X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=eaccda581af45e785e97cd22a9fee2ed83d97f8a;hb=10ce0a085680204df3dcc9e779f617efb487db58;hp=57c438320c0ed95916e2707ff0468bd66de6ffe7;hpb=cd3fa38347ce6af11215cca6eeeab40168c48860;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 57c438320c0..eaccda581af 100644 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -456,6 +456,12 @@ namespace Mono.CSharp { lr.local_info.Used = true; } + ParameterReference pr = Expr as ParameterReference; + if ((pr != null) && pr.Parameter.IsCaptured) { + AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc); + return null; + } + // According to the specs, a variable is considered definitely assigned if you take // its address. if ((variable != null) && (variable.VariableInfo != null)){ @@ -592,7 +598,7 @@ namespace Mono.CSharp { if (Expr == null) return null; - if (TypeManager.IsNullableType (Expr.Type)) + if (TypeManager.IsNullableValueType (Expr.Type)) return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec); eclass = ExprClass.Value; @@ -696,7 +702,7 @@ namespace Mono.CSharp { Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temporary = new LocalTemporary (ec, expr.Type); + temporary = new LocalTemporary (expr.Type); temporary.Store (ec); } } @@ -713,14 +719,16 @@ namespace Mono.CSharp { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temporary = new LocalTemporary (ec, expr.Type); + temporary = new LocalTemporary (expr.Type); temporary.Store (ec); } StoreFromPtr (ec.ig, type); - if (temporary != null) + if (temporary != null) { temporary.Emit (ec); + temporary.Release (ec); + } } public void AddressOf (EmitContext ec, AddressOp Mode) @@ -749,9 +757,7 @@ namespace Mono.CSharp { #region IVariable Members public VariableInfo VariableInfo { - get { - return null; - } + get { return null; } } public bool VerifyFixed () @@ -790,18 +796,18 @@ namespace Mono.CSharp { PostIncrement = IsPost, PostDecrement = IsPost | IsDecrement } - + Mode mode; bool is_expr = false; bool recurse = false; - + Expression expr; // // This is expensive for the simplest case. // StaticCallExpr method; - + public UnaryMutator (Mode m, Expression e, Location l) { mode = m; @@ -814,7 +820,7 @@ namespace Mono.CSharp { return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ? "++" : "--"; } - + /// /// Returns whether an object of type `t' can be incremented /// or decremented with add/sub (ie, basically whether we can @@ -899,7 +905,7 @@ namespace Mono.CSharp { eclass = ExprClass.Value; - if (TypeManager.IsNullableType (expr.Type)) + if (TypeManager.IsNullableValueType (expr.Type)) return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec); return ResolveOperator (ec); @@ -990,7 +996,7 @@ namespace Mono.CSharp { } } - + void EmitCode (EmitContext ec, bool is_expr) { recurse = true; @@ -1006,7 +1012,7 @@ namespace Mono.CSharp { // having to allocate another expression // if (recurse) { - ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement)); + ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement)); if (method == null) LoadOneAndEmitOp (ec, expr.Type); else @@ -1014,10 +1020,10 @@ namespace Mono.CSharp { recurse = false; return; } - + EmitCode (ec, true); } - + public override void EmitStatement (EmitContext ec) { EmitCode (ec, false); @@ -1055,8 +1061,6 @@ namespace Mono.CSharp { probe_type_expr = ProbeType.ResolveAsTypeTerminal (ec, false); if (probe_type_expr == null) return null; - if (probe_type_expr.ResolveType (ec) == null) - return null; expr = expr.Resolve (ec); if (expr == null) @@ -1184,6 +1188,9 @@ namespace Mono.CSharp { action = Action.AlwaysFalse; else action = Action.Probe; + } else if (etype.ContainsGenericParameters || probe_type.ContainsGenericParameters) { + expr = new BoxedCast (expr, etype); + action = Action.Probe; } else { action = Action.AlwaysFalse; warning_never_matches = true; @@ -1288,9 +1295,20 @@ namespace Mono.CSharp { return this; } + if (etype.ContainsGenericParameters || type.ContainsGenericParameters) { + expr = new BoxedCast (expr, etype); + do_isinst = true; + return this; + } + Error_CannotConvertType (etype, type, loc); return null; - } + } + + public override bool GetAttributableValue (Type valueType, out object value) + { + return expr.GetAttributableValue (valueType, out value); + } } /// @@ -1313,30 +1331,18 @@ namespace Mono.CSharp { this.target_type = cast_type; this.expr = expr; this.loc = loc; + + if (target_type == TypeManager.system_void_expr) + Error_VoidInvalidInTheContext (loc); } public Expression TargetType { - get { - return target_type; - } + get { return target_type; } } public Expression Expr { - get { - return expr; - } - set { - expr = value; - } - } - - public override Expression DoResolveLValue (EmitContext ec, Expression right_side) - { - expr = expr.DoResolveLValue (ec, right_side); - if (expr == null) - return null; - - return ResolveRest (ec); + get { return expr; } + set { expr = value; } } public override Expression DoResolve (EmitContext ec) @@ -1345,16 +1351,11 @@ namespace Mono.CSharp { if (expr == null) return null; - return ResolveRest (ec); - } - - Expression ResolveRest (EmitContext ec) - { TypeExpr target = target_type.ResolveAsTypeTerminal (ec, false); if (target == null) return null; - type = target.ResolveType (ec); + type = target.Type; if (type.IsAbstract && type.IsSealed) { Report.Error (716, loc, "Cannot convert to static type `{0}'", TypeManager.CSharpName (type)); @@ -1365,9 +1366,14 @@ namespace Mono.CSharp { Constant c = expr as Constant; if (c != null) { - c = c.TryReduce (ec, type, loc); - if (c != null) - return c; + try { + c = c.TryReduce (ec, type, loc); + if (c != null) + return c; + } + catch (OverflowException) { + return null; + } } if (type.IsPointer && !ec.InUnsafe) { @@ -1380,9 +1386,6 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - // - // This one will never happen - // throw new Exception ("Should not happen"); } } @@ -1542,193 +1545,60 @@ namespace Mono.CSharp { + "'"); } - bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions) + bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t) { - if ((l == t) || (r == t)) - return true; - - if (!check_user_conversions) - return false; + return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t); + } - if (Convert.ImplicitUserConversionExists (ec, l, t)) - return true; - else if (Convert.ImplicitUserConversionExists (ec, r, t)) - return true; - else + bool VerifyApplicable_Predefined (EmitContext ec, Type t) + { + if (!IsConvertible (ec, left, right, t)) return false; + left = ForceConversion (ec, left, t); + right = ForceConversion (ec, right, t); + type = t; + return true; } - // - // Note that handling the case l == Decimal || r == Decimal - // is taken care of by the Step 1 Operator Overload resolution. - // - // If `check_user_conv' is true, we also check whether a user-defined conversion - // exists. Note that we only need to do this if both arguments are of a user-defined - // 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, Expression lexpr, Expression rexpr, bool check_user_conv) - { - if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){ - // - // If either operand is of type double, the other operand is - // conveted to type double. - // - if (r != TypeManager.double_type) - right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc); - if (l != TypeManager.double_type) - left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc); - - type = TypeManager.double_type; - } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){ - // - // if either operand is of type float, the other operand is - // converted to type float. - // - if (r != TypeManager.double_type) - right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc); - if (l != TypeManager.double_type) - left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc); - type = TypeManager.float_type; - } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){ - Expression e; - Type other; - // - // If either operand is of type ulong, the other operand is - // converted to type ulong. or an error ocurrs if the other - // operand is of type sbyte, short, int or long - // - if (l == TypeManager.uint64_type){ - if (r != TypeManager.uint64_type){ - if (right is IntConstant){ - IntConstant ic = (IntConstant) right; - - e = Convert.TryImplicitIntConversion (l, ic); - if (e != null) - right = e; - } else if (right is LongConstant){ - long ll = ((LongConstant) right).Value; - - if (ll >= 0) - right = new ULongConstant ((ulong) ll, right.Location); - } else { - e = Convert.ImplicitNumericConversion (right, l); - if (e != null) - right = e; - } - } - other = right.Type; - } else { - if (left is IntConstant){ - e = Convert.TryImplicitIntConversion (r, (IntConstant) left); - if (e != null) - left = e; - } else if (left is LongConstant){ - long ll = ((LongConstant) left).Value; - - if (ll > 0) - left = new ULongConstant ((ulong) ll, right.Location); - } else { - e = Convert.ImplicitNumericConversion (left, r); - if (e != null) - left = e; - } - other = left.Type; - } - - if ((other == TypeManager.sbyte_type) || - (other == TypeManager.short_type) || - (other == TypeManager.int32_type) || - (other == TypeManager.int64_type)) - Error_OperatorAmbiguous (loc, oper, l, r); - else { - left = ForceConversion (ec, left, TypeManager.uint64_type); - right = ForceConversion (ec, right, TypeManager.uint64_type); - } - type = TypeManager.uint64_type; - } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){ - // - // If either operand is of type long, the other operand is converted - // to type long. - // - if (l != TypeManager.int64_type) - left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc); - if (r != TypeManager.int64_type) - right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc); - - type = TypeManager.int64_type; - } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){ - // - // If either operand is of type uint, and the other - // operand is of type sbyte, short or int, othe operands are - // converted to type long (unless we have an int constant). - // - Type other = null; - - if (l == TypeManager.uint32_type){ - if (right is IntConstant){ - IntConstant ic = (IntConstant) right; - int val = ic.Value; - - if (val >= 0){ - right = new UIntConstant ((uint) val, ic.Location); - type = l; - - return true; - } - } - other = r; - } else if (r == TypeManager.uint32_type){ - if (left is IntConstant){ - IntConstant ic = (IntConstant) left; - int val = ic.Value; - - if (val >= 0){ - left = new UIntConstant ((uint) val, ic.Location); - type = r; - return true; - } - } - - other = l; - } - - if ((other == TypeManager.sbyte_type) || - (other == TypeManager.short_type) || - (other == TypeManager.int32_type)){ - left = ForceConversion (ec, left, TypeManager.int64_type); - right = ForceConversion (ec, right, TypeManager.int64_type); - type = TypeManager.int64_type; - } else { - // - // if either operand is of type uint, the other - // operand is converd to type uint - // - left = ForceConversion (ec, left, TypeManager.uint32_type); - right = ForceConversion (ec, right, TypeManager.uint32_type); - type = TypeManager.uint32_type; - } - } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){ - if (l != TypeManager.decimal_type) - left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc); + bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper) + { + bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type); + bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type); - if (r != TypeManager.decimal_type) - right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc); - type = TypeManager.decimal_type; - } else { - left = ForceConversion (ec, left, TypeManager.int32_type); - right = ForceConversion (ec, right, TypeManager.int32_type); + if (oper == Operator.Equality || oper == Operator.Inequality) + return l && r; + if (oper == Operator.Addition) + return l || r; + return false; + } - 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); + bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper) + { + if (!IsApplicable_String (ec, left, right, oper)) + return false; + Type t = TypeManager.string_type; + if (Convert.ImplicitConversionExists (ec, left, t)) + left = ForceConversion (ec, left, t); + if (Convert.ImplicitConversionExists (ec, right, t)) + right = ForceConversion (ec, right, t); + type = t; + return true; + } - type = TypeManager.int32_type; - } + bool OverloadResolve_PredefinedIntegral (EmitContext ec) + { + return VerifyApplicable_Predefined (ec, TypeManager.int32_type) || + VerifyApplicable_Predefined (ec, TypeManager.uint32_type) || + VerifyApplicable_Predefined (ec, TypeManager.int64_type) || + VerifyApplicable_Predefined (ec, TypeManager.uint64_type) || + false; + } - return (left != null) && (right != null); + bool OverloadResolve_PredefinedFloating (EmitContext ec) + { + return VerifyApplicable_Predefined (ec, TypeManager.float_type) || + VerifyApplicable_Predefined (ec, TypeManager.double_type) || + false; } static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r) @@ -1744,7 +1614,8 @@ namespace Mono.CSharp { void Error_OperatorCannotBeApplied () { - Error_OperatorCannotBeApplied (Location, OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ()); + Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type), + TypeManager.CSharpName(right.Type)); } static bool is_unsigned (Type t) @@ -1753,15 +1624,6 @@ namespace Mono.CSharp { t == TypeManager.short_type || t == TypeManager.byte_type); } - static bool is_user_defined (Type t) - { - if (t.IsSubclassOf (TypeManager.value_type) && - (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type)) - return true; - else - return false; - } - Expression Make32or64 (EmitContext ec, Expression e) { Type t= e.Type; @@ -1786,34 +1648,17 @@ namespace Mono.CSharp { Expression CheckShiftArguments (EmitContext ec) { - Expression e; - - e = ForceConversion (ec, right, TypeManager.int32_type); - if (e == null){ + Expression new_left = Make32or64 (ec, left); + Expression new_right = ForceConversion (ec, right, TypeManager.int32_type); + if (new_left == null || new_right == null) { Error_OperatorCannotBeApplied (); return null; } - right = e; - - if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) || - ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) || - ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) || - ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){ - left = e; - type = e.Type; - - if (type == TypeManager.int32_type || type == TypeManager.uint32_type){ - right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (31, loc)); - right = right.DoResolve (ec); - } else { - right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (63, loc)); - right = right.DoResolve (ec); - } - - return this; - } - Error_OperatorCannotBeApplied (); - return null; + type = new_left.Type; + int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63; + left = new_left; + right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec); + return this; } // @@ -1867,7 +1712,6 @@ namespace Mono.CSharp { if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) || (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) { Type = TypeManager.bool_type; - return this; } @@ -1884,12 +1728,12 @@ namespace Mono.CSharp { // built-in types // Expression left_operators = null, right_operators = null; - if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){ + if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) { // // Step 1: Perform Operator Overload location // string op = oper_names [(int) oper]; - + MethodGroupExpr union; left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc); if (r != l){ @@ -1898,23 +1742,21 @@ namespace Mono.CSharp { union = Invocation.MakeUnionSet (left_operators, right_operators, loc); } else union = (MethodGroupExpr) left_operators; - + if (union != null) { ArrayList args = new ArrayList (2); args.Add (new Argument (left, Argument.AType.Expression)); args.Add (new Argument (right, Argument.AType.Expression)); - - MethodBase method = Invocation.OverloadResolve ( - ec, union, args, true, Location.Null); + + MethodBase method = Invocation.OverloadResolve (ec, union, args, true, Location.Null); if (method != null) { MethodInfo mi = (MethodInfo) method; - return new BinaryMethod (mi.ReturnType, method, args); } } } - + // // Step 0: String concatenation (because overloading will get this wrong) // @@ -1933,7 +1775,7 @@ namespace Mono.CSharp { Error_OperatorCannotBeApplied (); return null; } - + // try to fold it in on the left if (left is StringConcat) { @@ -1949,7 +1791,7 @@ namespace Mono.CSharp { return left; } } - + // Otherwise, start a new concat expression return new StringConcat (ec, loc, left, right).Resolve (ec); } @@ -1974,7 +1816,7 @@ namespace Mono.CSharp { Error_OperatorCannotBeApplied (); return null; } - + type = TypeManager.bool_type; return this; } @@ -2069,19 +1911,8 @@ namespace Mono.CSharp { if (r != TypeManager.object_type) right = new EmptyCast (right, TypeManager.object_type); - // - // FIXME: CSC here catches errors cs254 and cs252 - // return this; } - - // - // One of them is a valuetype, but the other one is not. - // - if (!l.IsValueType || !r.IsValueType) { - Error_OperatorCannotBeApplied (); - return null; - } } // Only perform numeric promotions on: @@ -2099,8 +1930,8 @@ namespace Mono.CSharp { r = right.Type; } } - - if (TypeManager.IsDelegateType (r)){ + + if (TypeManager.IsDelegateType (r) || right is NullLiteral){ MethodInfo method; ArrayList args = new ArrayList (2); @@ -2113,7 +1944,7 @@ namespace Mono.CSharp { else method = TypeManager.delegate_remove_delegate_delegate; - if (!TypeManager.IsEqual (l, r)) { + if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) { Error_OperatorCannotBeApplied (); return null; } @@ -2271,18 +2102,27 @@ namespace Mono.CSharp { return e.Resolve (ec); } + Expression orig_left = left; + Expression orig_right = right; + // // operator & (bool x, bool y) // operator | (bool x, bool y) // operator ^ (bool x, bool y) // - if (l == TypeManager.bool_type && r == TypeManager.bool_type){ - if (oper == Operator.BitwiseAnd || - oper == Operator.BitwiseOr || - oper == Operator.ExclusiveOr){ - type = l; - return this; + if (oper == Operator.BitwiseAnd || + oper == Operator.BitwiseOr || + oper == Operator.ExclusiveOr) { + if (OverloadResolve_PredefinedIntegral (ec)) { + if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) { + Error_OperatorAmbiguous (loc, oper, l, r); + return null; + } + } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) { + Error_OperatorCannotBeApplied (); + return null; } + return this; } // @@ -2295,42 +2135,26 @@ namespace Mono.CSharp { return this; } } - - // - // 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, left, right, check_user_conv); - if (left == null || right == null){ - Error_OperatorCannotBeApplied (loc, OperName (oper), l, r); - return null; - } - // - // reload our cached types if required - // - l = left.Type; - r = right.Type; - - if (oper == Operator.BitwiseAnd || - oper == Operator.BitwiseOr || - oper == Operator.ExclusiveOr){ - if (l == r){ - if (((l == TypeManager.int32_type) || - (l == TypeManager.uint32_type) || - (l == TypeManager.short_type) || - (l == TypeManager.ushort_type) || - (l == TypeManager.int64_type) || - (l == TypeManager.uint64_type))){ - type = l; - } else { - Error_OperatorCannotBeApplied (); - return null; - } - } else { - Error_OperatorCannotBeApplied (); + if (OverloadResolve_PredefinedIntegral (ec)) { + if (IsApplicable_String (ec, orig_left, orig_right, oper)) { + Error_OperatorAmbiguous (loc, oper, l, r); + return null; + } + } else if (OverloadResolve_PredefinedFloating (ec)) { + if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) || + IsApplicable_String (ec, orig_left, orig_right, oper)) { + Error_OperatorAmbiguous (loc, oper, l, r); return null; } + } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) { + if (IsApplicable_String (ec, orig_left, orig_right, oper)) { + Error_OperatorAmbiguous (loc, oper, l, r); + return null; + } + } else if (!OverloadResolve_PredefinedString (ec, oper)) { + Error_OperatorCannotBeApplied (); + return null; } if (oper == Operator.Equality || @@ -2338,14 +2162,30 @@ namespace Mono.CSharp { oper == Operator.LessThanOrEqual || oper == Operator.LessThan || oper == Operator.GreaterThanOrEqual || - oper == Operator.GreaterThan){ + oper == Operator.GreaterThan) type = TypeManager.bool_type; + + l = left.Type; + r = right.Type; + + if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) { + Type lookup = l; + if (r == TypeManager.string_type) + lookup = r; + MethodGroupExpr ops = (MethodGroupExpr) MemberLookup ( + ec.ContainerType, lookup, oper_names [(int) oper], + MemberTypes.Method, AllBindingFlags, loc); + ArrayList args = new ArrayList (2); + args.Add (new Argument (left, Argument.AType.Expression)); + args.Add (new Argument (right, Argument.AType.Expression)); + MethodBase method = Invocation.OverloadResolve (ec, ops, args, true, Location.Null); + return new BinaryMethod (type, method, args); } return this; } - Constant EnumLiftUp (EmitContext ec, Constant left, Constant right) + Constant EnumLiftUp (Constant left, Constant right) { switch (oper) { case Operator.BitwiseOr: @@ -2422,11 +2262,11 @@ namespace Mono.CSharp { // The conversion rules are ignored in enum context but why if (!ec.InEnumContext && lc != null && rc != null && (TypeManager.IsEnumType (left.Type) || TypeManager.IsEnumType (right.Type))) { - left = lc = EnumLiftUp (ec, lc, rc); + left = lc = EnumLiftUp (lc, rc); if (lc == null) return null; - right = rc = EnumLiftUp (ec, rc, lc); + right = rc = EnumLiftUp (rc, lc); if (rc == null) return null; } @@ -2466,7 +2306,11 @@ namespace Mono.CSharp { return e; } - if (TypeManager.IsNullableType (left.Type) || TypeManager.IsNullableType (right.Type)) + Type ltype = left.Type, rtype = right.Type; + if ((left is NullLiteral || ltype.IsValueType) && + (right is NullLiteral || rtype.IsValueType) && + !(left is NullLiteral && right is NullLiteral) && + (TypeManager.IsNullableType (ltype) || TypeManager.IsNullableType (rtype))) return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec); // Comparison warnings @@ -2483,6 +2327,11 @@ namespace Mono.CSharp { return ResolveOperator (ec); } + public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent) + { + return null; + } + private void CheckUselessComparison (Constant c, Type type) { if (c == null || !IsTypeIntegral (type) @@ -2982,11 +2831,21 @@ namespace Mono.CSharp { // // Constant folding // - 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, last_operand.Location); - return; + StringConstant sc = operand as StringConstant; + if (sc != null) { +// TODO: it will be better to do this silently as an optimalization +// int i = 0; +// string s = "" + i; +// because this code has poor performace +// if (sc.Value.Length == 0) +// Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?"); + + if (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, last_operand.Location); + return; + } } } @@ -3165,7 +3024,7 @@ namespace Mono.CSharp { return null; } - left_temp = new LocalTemporary (ec, type); + left_temp = new LocalTemporary (type); ArrayList arguments = new ArrayList (); arguments.Add (new Argument (left_temp, Argument.AType.Expression)); @@ -3211,6 +3070,9 @@ namespace Mono.CSharp { ig.MarkLabel (false_target); op.Emit (ec); ig.MarkLabel (end_target); + + // We release 'left_temp' here since 'op' may refer to it too + left_temp.Release (ec); } } @@ -3349,7 +3211,7 @@ namespace Mono.CSharp { if (expr == null) return null; - if (TypeManager.IsNullableType (expr.Type)) + if (TypeManager.IsNullableValueType (expr.Type)) return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec); if (expr.Type != TypeManager.bool_type){ @@ -3419,6 +3281,11 @@ namespace Mono.CSharp { return this; } + public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent) + { + return null; + } + public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; @@ -3435,128 +3302,227 @@ namespace Mono.CSharp { } - /// - /// Local variables - /// - public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable { - public readonly string Name; - public readonly Block Block; - public LocalInfo local_info; - bool is_readonly; + public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation { bool prepared; LocalTemporary temp; - - public LocalVariableReference (Block block, string name, Location l) - { - Block = block; - Name = name; - loc = l; - eclass = ExprClass.Variable; - } - // - // Setting `is_readonly' to false will allow you to create a writable - // reference to a read-only variable. This is used by foreach and using. - // - public LocalVariableReference (Block block, string name, Location l, - LocalInfo local_info, bool is_readonly) - : this (block, name, l) - { - this.local_info = local_info; - this.is_readonly = is_readonly; + public abstract Variable Variable { + get; } - public VariableInfo VariableInfo { - get { - return local_info.VariableInfo; - } + public abstract bool IsRef { + get; } - public bool IsReadOnly { - get { - return is_readonly; - } + public override void Emit (EmitContext ec) + { + Emit (ec, false); } - public bool VerifyAssigned (EmitContext ec) + // + // This method is used by parameters that are references, that are + // being passed as references: we only want to pass the pointer (that + // is already stored in the parameter, not the address of the pointer, + // and not the value of the variable). + // + public void EmitLoad (EmitContext ec) + { + Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc); + if (!prepared) + Variable.EmitInstance (ec); + Variable.Emit (ec); + } + + public void Emit (EmitContext ec, bool leave_copy) + { + Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc); + + EmitLoad (ec); + + if (IsRef) { + if (prepared) + ec.ig.Emit (OpCodes.Dup); + + // + // If we are a reference, we loaded on the stack a pointer + // Now lets load the real value + // + LoadFromPtr (ec.ig, type); + } + + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + + if (IsRef || Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + } + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, + bool prepare_for_load) + { + Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef, + source, loc); + + ILGenerator ig = ec.ig; + prepared = prepare_for_load; + + Variable.EmitInstance (ec); + if (prepare_for_load && Variable.HasInstance) + ig.Emit (OpCodes.Dup); + else if (IsRef && !prepared) + Variable.Emit (ec); + + source.Emit (ec); + + if (leave_copy) { + ig.Emit (OpCodes.Dup); + if (IsRef || Variable.NeedsTemporary) { + temp = new LocalTemporary (Type); + temp.Store (ec); + } + } + + if (IsRef) + StoreFromPtr (ig, type); + else + Variable.EmitAssign (ec); + + if (temp != null) { + temp.Emit (ec); + temp.Release (ec); + } + } + + public void AddressOf (EmitContext ec, AddressOp mode) + { + Variable.EmitInstance (ec); + Variable.EmitAddressOf (ec); + } + } + + /// + /// Local variables + /// + public class LocalVariableReference : VariableReference, IVariable { + public readonly string Name; + public readonly Block Block; + public LocalInfo local_info; + bool is_readonly; + Variable variable; + + public LocalVariableReference (Block block, string name, Location l) + { + Block = block; + Name = name; + loc = l; + eclass = ExprClass.Variable; + } + + // + // Setting `is_readonly' to false will allow you to create a writable + // reference to a read-only variable. This is used by foreach and using. + // + public LocalVariableReference (Block block, string name, Location l, + LocalInfo local_info, bool is_readonly) + : this (block, name, l) + { + this.local_info = local_info; + this.is_readonly = is_readonly; + } + + public VariableInfo VariableInfo { + get { return local_info.VariableInfo; } + } + + public override bool IsRef { + get { return false; } + } + + public bool IsReadOnly { + get { return is_readonly; } + } + + 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) + void ResolveLocalInfo () { if (local_info == null) { local_info = Block.GetLocalInfo (Name); - - // is out param - if (lvalue_right_side == EmptyExpression.OutAccess) - local_info.Used = true; - is_readonly = local_info.ReadOnly; } + } + protected Expression DoResolveBase (EmitContext ec) + { type = local_info.VariableType; - VariableInfo variable_info = local_info.VariableInfo; - if (lvalue_right_side != null){ - if (is_readonly){ - if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.OutAccess) - Report.Error (1657, loc, "Cannot pass `{0}' as a ref or out argument because it is a `{1}'", - Name, local_info.GetReadOnlyContext ()); - else if (lvalue_right_side == EmptyExpression.LValueMemberAccess) - Report.Error (1654, loc, "Cannot assign to members of `{0}' 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) { - local_info.Used = true; - eclass = ExprClass.Value; + if (e != null) return e.Resolve (ec); - } if (!VerifyAssigned (ec)) return null; - if (lvalue_right_side == null) - local_info.Used = true; - - if (ec.CurrentAnonymousMethod != null){ - // - // If we are referencing a variable from the external block - // flag it for capturing - // - if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) || - ec.CurrentAnonymousMethod.IsIterator) - { - if (local_info.AddressTaken){ - AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); - return null; - } - ec.CaptureVariable (local_info); + // + // If we are referencing a variable from the external block + // flag it for capturing + // + if (ec.MustCaptureVariable (local_info)) { + if (local_info.AddressTaken){ + AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); + return null; } + + ScopeInfo scope = local_info.Block.CreateScopeInfo (); + variable = scope.AddLocal (local_info); + type = variable.Type; } return this; } - + public override Expression DoResolve (EmitContext ec) { - return DoResolveBase (ec, null); + ResolveLocalInfo (); + local_info.Used = true; + return DoResolveBase (ec); } override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { - return DoResolveBase (ec, right_side); + ResolveLocalInfo (); + + if (is_readonly) { + int code; + string msg; + if (right_side == EmptyExpression.OutAccess) { + code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'"; + } else if (right_side == EmptyExpression.LValueMemberAccess) { + code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'"; + } else if (right_side == EmptyExpression.LValueMemberOutAccess) { + code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'"; + } else { + code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'"; + } + Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ()); + return null; + } + + // is out param + if (right_side == EmptyExpression.OutAccess) + local_info.Used = true; + + if (VariableInfo != null) + VariableInfo.SetAssigned (ec); + + return DoResolveBase (ec); } public bool VerifyFixed () @@ -3565,7 +3531,7 @@ namespace Mono.CSharp { return true; } - public override int GetHashCode() + public override int GetHashCode () { return Name.GetHashCode (); } @@ -3579,90 +3545,8 @@ namespace Mono.CSharp { return Name == lvr.Name && Block == lvr.Block; } - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods. - // - if (!prepared) - ec.EmitCapturedVariableInstance (local_info); - - ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder); - } - } - - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy){ - ec.ig.Emit (OpCodes.Dup); - if (local_info.FieldBuilder != null){ - temp = new LocalTemporary (ec, Type); - temp.Store (ec); - } - } - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - ILGenerator ig = ec.ig; - prepared = prepare_for_load; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - 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); - ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or itereators. - // - ec.EmitCapturedVariableInstance (local_info); - - if (prepare_for_load) - ig.Emit (OpCodes.Dup); - source.Emit (ec); - if (leave_copy){ - ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, Type); - temp.Store (ec); - } - ig.Emit (OpCodes.Stfld, local_info.FieldBuilder); - if (temp != null) - temp.Emit (ec); - } - } - - public void AddressOf (EmitContext ec, AddressOp mode) - { - ILGenerator ig = ec.ig; - - if (local_info.FieldBuilder == null){ - // - // A local variable on the local CLR stack - // - ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder); - } else { - // - // A local variable captured by anonymous methods or iterators - // - ec.EmitCapturedVariableInstance (local_info); - ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder); - } + public override Variable Variable { + get { return variable != null ? variable : local_info.Variable; } } public override string ToString () @@ -3675,13 +3559,13 @@ namespace Mono.CSharp { /// This represents a reference to a parameter in the intermediate /// representation. /// - public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable { + public class ParameterReference : VariableReference, IVariable { Parameter par; string name; int idx; Block block; VariableInfo vi; - public bool is_ref, is_out, prepared; + public bool is_ref, is_out; public bool IsOut { get { @@ -3689,13 +3573,25 @@ namespace Mono.CSharp { } } - public bool IsRef { + public override bool IsRef { get { return is_ref; } } - LocalTemporary temp; + public string Name { + get { + return name; + } + } + + public Parameter Parameter { + get { + return par; + } + } + + Variable variable; public ParameterReference (Parameter par, Block block, int idx, Location loc) { @@ -3711,6 +3607,10 @@ namespace Mono.CSharp { get { return vi; } } + public override Variable Variable { + get { return variable != null ? variable : par.Variable; } + } + public bool VerifyFixed () { // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param). @@ -3764,23 +3664,33 @@ namespace Mono.CSharp { if (is_out) vi = block.ParameterMap [idx]; - if (ec.CurrentAnonymousMethod != null){ - if (is_ref && !block.Toplevel.IsLocalParameter (name)){ - Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block", - par.Name); - return false; - } + AnonymousContainer am = ec.CurrentAnonymousMethod; + if (am == null) + return true; - // - // 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.Toplevel.IsLocalParameter (name)){ - ec.CaptureParameter (name, type, idx); + if (is_ref && !block.Toplevel.IsLocalParameter (name)){ + Report.Error (1628, Location, + "Cannot use ref or out parameter `{0}' inside an " + + "anonymous method block", par.Name); + return false; + } + + if (!am.IsIterator && block.Toplevel.IsLocalParameter (name)) + return true; + + AnonymousMethodHost host = null; + ToplevelBlock toplevel = block.Toplevel; + while (toplevel != null) { + if (toplevel.IsLocalParameter (name)) { + host = toplevel.AnonymousMethodHost; + break; } + + toplevel = toplevel.Container; } + variable = host.AddParameter (par, idx); + type = variable.Type; return true; } @@ -3815,7 +3725,8 @@ namespace Mono.CSharp { if (!DoResolveBase (ec)) return null; - if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) + if (is_out && ec.DoFlowAnalysis && + (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc)) return null; return this; @@ -3845,135 +3756,6 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldarg, x); } - // - // This method is used by parameters that are references, that are - // being passed as references: we only want to pass the pointer (that - // is already stored in the parameter, not the address of the pointer, - // and not the value of the variable). - // - public void EmitLoad (EmitContext ec) - { - ILGenerator ig = ec.ig; - int arg_idx = idx; - - if (!ec.MethodIsStatic) - arg_idx++; - - EmitLdArg (ig, arg_idx); - - // - // FIXME: Review for anonymous methods - // - } - - public override void Emit (EmitContext ec) - { - Emit (ec, false); - } - - public void Emit (EmitContext ec, bool leave_copy) - { - ILGenerator ig = ec.ig; - int arg_idx = idx; - - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitParameter (name, leave_copy, prepared, ref temp); - return; - } - - if (!ec.MethodIsStatic) - arg_idx++; - - EmitLdArg (ig, arg_idx); - - if (is_ref) { - if (prepared) - ec.ig.Emit (OpCodes.Dup); - - // - // If we are a reference, we loaded on the stack a pointer - // Now lets load the real value - // - LoadFromPtr (ig, type); - } - - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - temp = new LocalTemporary (ec, type); - temp.Store (ec); - } - } - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - prepared = prepare_for_load; - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load, ref temp); - return; - } - - ILGenerator ig = ec.ig; - int arg_idx = idx; - - - - if (!ec.MethodIsStatic) - arg_idx++; - - if (is_ref && !prepared) - EmitLdArg (ig, arg_idx); - - source.Emit (ec); - - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - if (leave_copy) { - temp = new LocalTemporary (ec, type); - temp.Store (ec); - } - - StoreFromPtr (ig, type); - - if (temp != null) - temp.Emit (ec); - } else { - if (arg_idx <= 255) - ig.Emit (OpCodes.Starg_S, (byte) arg_idx); - else - ig.Emit (OpCodes.Starg, arg_idx); - } - } - - public void AddressOf (EmitContext ec, AddressOp mode) - { - if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ - ec.EmitAddressOfParameter (name); - return; - } - - int arg_idx = idx; - - if (!ec.MethodIsStatic) - arg_idx++; - - if (is_ref){ - if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx); - else - ec.ig.Emit (OpCodes.Ldarg, arg_idx); - } else { - if (arg_idx <= 255) - ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); - else - ec.ig.Emit (OpCodes.Ldarga, arg_idx); - } - } - public override string ToString () { return "ParameterReference[" + name + "]"; @@ -4041,7 +3823,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (a.Expr.Type); } - public bool ResolveMethodGroup (EmitContext ec, Location loc) + public bool ResolveMethodGroup (EmitContext ec) { SimpleName sn = Expr as SimpleName; if (sn != null) @@ -4055,106 +3837,44 @@ namespace Mono.CSharp { return true; } - - void Error_LValueRequired (Location loc) - { - 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); - ec.InRefOutArgumentResolving = false; - if (Expr == null) { - ec.DoFlowAnalysis = old_do_flow_analysis; - return false; - } - - int errors = Report.Errors; - Expr = Expr.DoResolveLValue (ec, Expr); - if (Expr == null && errors == Report.Errors) - Error_LValueRequired (loc); - } else if (ArgType == AType.Out) { - int errors = Report.Errors; - ec.InRefOutArgumentResolving = true; - Expr = Expr.DoResolveLValue (ec, EmptyExpression.OutAccess); - ec.InRefOutArgumentResolving = false; - - if (Expr == null && errors == Report.Errors) - Error_LValueRequired (loc); - } - else - Expr = Expr.Resolve (ec); - - ec.DoFlowAnalysis = old_do_flow_analysis; + using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) { + // Verify that the argument is readable + if (ArgType != AType.Out) + Expr = Expr.Resolve (ec); - if (Expr == null) - return false; + // Verify that the argument is writeable + if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref)) + Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc); - if (ArgType == AType.Expression) - return true; - else { - // - // Catch errors where fields of a MarshalByRefObject are passed as ref or out - // This is only allowed for `this' - // - FieldExpr fe = Expr as FieldExpr; - if (fe != null && !fe.IsStatic){ - Expression instance = fe.InstanceExpression; - - if (instance.GetType () != typeof (This)){ - if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){ - Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type); - 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; - } - } - } + return Expr != null; } - - return true; } public void Emit (EmitContext ec) { - // - // Ref and Out parameters need to have their addresses taken. + if (ArgType != AType.Ref && ArgType != AType.Out) { + Expr.Emit (ec); + return; + } + + AddressOp mode = AddressOp.Store; + if (ArgType == AType.Ref) + mode |= AddressOp.Load; + + IMemoryLocation ml = (IMemoryLocation) Expr; + ParameterReference pr = ml as ParameterReference; + // // ParameterReferences might already be references, so we want // to pass just the value // - if (ArgType == AType.Ref || ArgType == AType.Out){ - AddressOp mode = AddressOp.Store; - - if (ArgType == AType.Ref) - mode |= AddressOp.Load; - - if (Expr is ParameterReference){ - ParameterReference pr = (ParameterReference) Expr; - - if (pr.IsRef) - pr.EmitLoad (ec); - else { - - pr.AddressOf (ec, mode); - } - } else { - if (Expr is IMemoryLocation) - ((IMemoryLocation) Expr).AddressOf (ec, mode); - else { - Error_LValueRequired (Expr.Location); - return; - } - } - } else - Expr.Emit (ec); + if (pr != null && pr.IsRef) + pr.EmitLoad (ec); + else + ml.AddressOf (ec, mode); } } @@ -4194,7 +3914,7 @@ namespace Mono.CSharp { /// q if a->q is better, /// null if neither is better /// - static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) + static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q) { Type argument_type = TypeManager.TypeToCoreType (a.Type); Expression argument_expr = a.Expr; @@ -4294,7 +4014,15 @@ namespace Mono.CSharp { if (!p.IsGenericParameter && q.IsGenericParameter) return p; - if (p.IsGenericType) { + if (TypeManager.HasElementType (p)) { + Type pe = TypeManager.GetElementType (p); + Type qe = TypeManager.GetElementType (q); + Type specific = MoreSpecific (pe, qe); + if (specific == pe) + return p; + if (specific == qe) + return q; + } else if (p.IsGenericType) { Type[] pargs = TypeManager.GetTypeArguments (p); Type[] qargs = TypeManager.GetTypeArguments (q); @@ -4313,14 +4041,6 @@ namespace Mono.CSharp { return p; if (!p_specific_at_least_once && q_specific_at_least_once) return q; - } else if (TypeManager.HasElementType (p)) { - Type pe = TypeManager.GetElementType (p); - Type qe = TypeManager.GetElementType (q); - Type specific = MoreSpecific (pe, qe); - if (specific == pe) - return p; - if (specific == qe) - return q; } return null; @@ -4337,7 +4057,7 @@ namespace Mono.CSharp { /// static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count, MethodBase candidate, bool candidate_params, - MethodBase best, bool best_params, Location loc) + MethodBase best, bool best_params) { ParameterData candidate_pd = TypeManager.GetParameterData (candidate); ParameterData best_pd = TypeManager.GetParameterData (best); @@ -4362,7 +4082,7 @@ namespace Mono.CSharp { continue; same = false; - Type better = BetterConversion (ec, a, ct, bt, loc); + Type better = BetterConversion (ec, a, ct, bt); // for each argument, the conversion to 'ct' should be no worse than // the conversion to 'bt'. @@ -4557,6 +4277,9 @@ namespace Mono.CSharp { !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate)) return false; + if (TypeManager.IsGenericMethodDefinition (candidate)) + throw new InternalErrorException ("a generic method definition took part in overload resolution"); + return IsParamsMethodApplicable ( ec, arguments, arg_count, candidate, do_varargs); } @@ -4656,6 +4379,9 @@ namespace Mono.CSharp { !TypeManager.InferTypeArguments (arguments, ref candidate)) return false; + if (TypeManager.IsGenericMethodDefinition (candidate)) + throw new InternalErrorException ("a generic method definition took part in overload resolution"); + return IsApplicable (ec, arguments, arg_count, candidate); } @@ -4771,11 +4497,17 @@ namespace Mono.CSharp { int j = 0; for (int i = 0; i < methods.Length; ++i) { MethodBase m = methods [i]; + Type [] gen_args = m.IsGenericMethod && !m.IsGenericMethodDefinition ? m.GetGenericArguments () : null; if (TypeManager.IsOverride (m)) { if (candidate_overrides == null) candidate_overrides = new ArrayList (); candidate_overrides.Add (m); m = TypeManager.TryGetBaseDefinition (m); + if (m != null && gen_args != null) { + if (!m.IsGenericMethodDefinition) + throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition"); + m = ((MethodInfo) m).MakeGenericMethod (gen_args); + } } if (m != null) methods [j++] = m; @@ -4849,6 +4581,9 @@ namespace Mono.CSharp { if (!TypeManager.InferTypeArguments (Arguments, ref c)) continue; + if (TypeManager.IsGenericMethodDefinition (c)) + continue; + VerifyArgumentsCompat (ec, Arguments, arg_count, c, false, null, may_fail, loc); @@ -4956,7 +4691,7 @@ namespace Mono.CSharp { if (BetterFunction (ec, Arguments, arg_count, candidate, cand_params, - method, method_params, loc)) { + method, method_params)) { method = candidate; method_params = cand_params; } @@ -4975,8 +4710,7 @@ namespace Mono.CSharp { bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate); if (!BetterFunction (ec, Arguments, arg_count, method, method_params, - candidate, cand_params, - loc)) { + candidate, cand_params)) { Report.SymbolRelatedToPreviousError (candidate); ambiguous = candidate; } @@ -5074,85 +4808,54 @@ namespace Mono.CSharp { Location loc) { ParameterData pd = TypeManager.GetParameterData (method); - int pd_count = pd.Count; - - for (int j = 0; j < arg_count; j++) { + int j; + for (j = 0; j < arg_count; j++) { Argument a = (Argument) Arguments [j]; Expression a_expr = a.Expr; Type parameter_type = pd.ParameterType (j); Parameter.Modifier pm = pd.ParameterModifier (j); - - if (pm == Parameter.Modifier.PARAMS){ - if ((pm & ~Parameter.Modifier.PARAMS) != a.Modifier) { - if (!may_fail) - Error_InvalidArguments (loc, j, method, delegate_type, a, pd); - return false; - } + Parameter.Modifier am = a.Modifier; - if (chose_params_expanded) - parameter_type = TypeManager.GetElementType (parameter_type); - } else if (pm == Parameter.Modifier.ARGLIST) { - if (!(a.Expr is Arglist)) { - if (!may_fail) - Error_InvalidArguments (loc, j, method, delegate_type, a, pd); - return false; - } + if (pm == Parameter.Modifier.ARGLIST) { + if (!(a.Expr is Arglist)) + break; continue; - } else { - // - // Check modifiers - // - if (pd.ParameterModifier (j) != a.Modifier){ - if (!may_fail) - Error_InvalidArguments (loc, j, method, delegate_type, a, pd); - return false; - } } - // - // Check Type - // - if (!TypeManager.IsEqual (a.Type, parameter_type)){ - Expression conv; + if (pm == Parameter.Modifier.PARAMS) { + pm = Parameter.Modifier.NONE; + if (chose_params_expanded) + parameter_type = TypeManager.GetElementType (parameter_type); + } + + if (pm != am) + break; - conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc); + if (!TypeManager.IsEqual (a.Type, parameter_type)) { + if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF) + break; + + Expression conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc); + if (conv == null) + break; - if (conv == null) { - if (!may_fail) - Error_InvalidArguments (loc, j, method, delegate_type, a, pd); - return false; - } - - // // Update the argument with the implicit conversion - // if (a_expr != conv) a.Expr = conv; } - if (parameter_type.IsPointer){ - if (!ec.InUnsafe){ - UnsafeError (loc); - return false; - } - } - - 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)); - - if (a_mod != p_mod && - pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) { - if (!may_fail) { - Invocation.Error_InvalidArguments (loc, j, method, null, a, pd); - } - + if (parameter_type.IsPointer && !ec.InUnsafe) { + UnsafeError (loc); return false; } } - return true; + if (j == arg_count) + return true; + + if (!may_fail) + Error_InvalidArguments (loc, j, method, delegate_type, (Argument) Arguments [j], pd); + return false; } private bool resolved = false; @@ -5255,7 +4958,7 @@ namespace Mono.CSharp { } if (mg.InstanceExpression != null) - mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType); + mg.InstanceExpression.CheckMarshalByRefAccess (); eclass = ExprClass.Value; this.method = method; @@ -5365,7 +5068,7 @@ namespace Mono.CSharp { a.Emit (ec); if (dup_args) { ec.ig.Emit (OpCodes.Dup); - (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec); + (temps [i] = new LocalTemporary (a.Type)).Store (ec); } } @@ -5373,8 +5076,10 @@ namespace Mono.CSharp { if (this_arg != null) this_arg.Emit (ec); - for (int i = 0; i < top; i ++) + for (int i = 0; i < top; i ++) { temps [i].Emit (ec); + temps [i].Release (ec); + } } if (pd != null && pd.Count > top && @@ -5386,8 +5091,7 @@ namespace Mono.CSharp { } } - static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb, - ArrayList arguments) + static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments) { ParameterData pd = TypeManager.GetParameterData (mb); @@ -5534,7 +5238,7 @@ namespace Mono.CSharp { ((IMemoryLocation)instance_expr). AddressOf (ec, AddressOp.LoadStore); } else { - LocalTemporary temp = new LocalTemporary (ec, iexpr_type); + LocalTemporary temp = new LocalTemporary (iexpr_type); instance_expr.Emit (ec); temp.Store (ec); temp.AddressOf (ec, AddressOp.Load); @@ -5556,7 +5260,7 @@ namespace Mono.CSharp { if (dup_args) { ig.Emit (OpCodes.Dup); if (Arguments != null && Arguments.Count != 0) { - this_arg = new LocalTemporary (ec, t); + this_arg = new LocalTemporary (t); this_arg.Store (ec); } } @@ -5576,7 +5280,7 @@ namespace Mono.CSharp { call_op = OpCodes.Callvirt; if ((method.CallingConvention & CallingConventions.VarArgs) != 0) { - Type[] varargs_types = GetVarargsTypes (ec, method, Arguments); + Type[] varargs_types = GetVarargsTypes (method, Arguments); ig.EmitCall (call_op, (MethodInfo) method, varargs_types); return; } @@ -5878,7 +5582,7 @@ namespace Mono.CSharp { if (texpr == null) return null; - type = texpr.ResolveType (ec); + type = texpr.Type; if (Arguments == null) { Expression c = Constantify (type); @@ -6024,7 +5728,7 @@ namespace Mono.CSharp { // We need to create a new LocalTemporary each time since // you can't share LocalBuilders among ILGeneators. if (!value_target_set) - value_target = new LocalTemporary (ec, type); + value_target = new LocalTemporary (type); ml = (IMemoryLocation) value_target; ml.AddressOf (ec, AddressOp.Store); @@ -6082,7 +5786,7 @@ namespace Mono.CSharp { } if (!value_target_set) - value_target = new LocalTemporary (ec, type); + value_target = new LocalTemporary (type); IMemoryLocation ml = (IMemoryLocation) value_target; ml.AddressOf (ec, AddressOp.Store); @@ -6134,15 +5838,10 @@ namespace Mono.CSharp { ArrayList array_data; - Hashtable bounds; - - // - // The number of array initializers that we can handle - // via the InitializeArray method - through EmitStaticInitializers - // - int num_automatic_initializers; + IDictionary bounds; - const int max_automatic_initializers = 6; + // The number of constants in array initializers + int const_initializers_count; public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l) { @@ -6192,7 +5891,7 @@ namespace Mono.CSharp { Error (178, "Invalid rank specifier: expected `,' or `]'"); } - public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims) + bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims) { if (specified_dims) { Argument a = (Argument) arguments [idx]; @@ -6234,7 +5933,7 @@ namespace Mono.CSharp { Error_IncorrectArrayInitializer (); return false; } - if (specified_dims && (idx + 1 >= arguments.Count)){ + if (idx + 1 >= dimensions){ Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead"); return false; } @@ -6250,38 +5949,37 @@ namespace Mono.CSharp { Expression tmp = (Expression) o; tmp = tmp.Resolve (ec); - probe [i] = tmp; if (tmp == null) return false; - // Console.WriteLine ("I got: " + tmp); - // Handle initialization from vars, fields etc. - Expression conv = Convert.ImplicitConversionRequired ( ec, tmp, underlying_type, loc); if (conv == null) return false; - if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) { - // These are subclasses of Constant that can appear as elements of an - // array that cannot be statically initialized (with num_automatic_initializers - // > max_automatic_initializers), so num_automatic_initializers should be left as zero. - array_data.Add (conv); - } else if (conv is Constant) { - // These are the types of Constant that can appear in arrays that can be - // statically allocated. - array_data.Add (conv); - num_automatic_initializers++; - } else - array_data.Add (conv); + // Initializers with the default values can be ignored + Constant c = tmp as Constant; + if (c != null) { + if (c.IsDefaultInitializer (array_element_type)) { + conv = null; + } + else { + ++const_initializers_count; + } + } else { + // Used to invalidate static initializer + const_initializers_count = int.MinValue; + } + + array_data.Add (conv); } } return true; } - public void UpdateIndices (EmitContext ec) + public void UpdateIndices () { int i = 0; for (ArrayList probe = initializers; probe != null;) { @@ -6298,19 +5996,16 @@ namespace Mono.CSharp { arguments.Add (new Argument (e, Argument.AType.Expression)); bounds [i++] = probe.Count; - probe = null; + return; } } } - public bool ValidateInitializers (EmitContext ec, Type array_type) + bool ResolveInitializers (EmitContext ec) { if (initializers == null) { - if (expect_initializers) - return false; - else - return true; + return !expect_initializers; } if (underlying_type == null) @@ -6321,30 +6016,24 @@ namespace Mono.CSharp { // will need to store them in the byte blob later // array_data = new ArrayList (); - bounds = new Hashtable (); + bounds = new System.Collections.Specialized.HybridDictionary (); - bool ret; + if (arguments != null) + return CheckIndices (ec, initializers, 0, true); - if (arguments != null) { - ret = CheckIndices (ec, initializers, 0, true); - return ret; - } else { - arguments = new ArrayList (); + arguments = new ArrayList (); - ret = CheckIndices (ec, initializers, 0, false); - - if (!ret) - return false; + if (!CheckIndices (ec, initializers, 0, false)) + return false; - UpdateIndices (ec); + UpdateIndices (); - if (arguments.Count != dimensions) { - Error_IncorrectArrayInitializer (); - return false; - } - - return ret; + if (arguments.Count != dimensions) { + Error_IncorrectArrayInitializer (); + return false; } + + return true; } // @@ -6374,7 +6063,7 @@ namespace Mono.CSharp { if (array_type_expr == null) return false; - type = array_type_expr.ResolveType (ec); + type = array_type_expr.Type; underlying_type = TypeManager.GetElementType (type); dimensions = type.GetArrayRank (); @@ -6383,18 +6072,26 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - int arg_count; + if (type != null) + return this; if (!LookupType (ec)) return null; + 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)); + return null; + } + // // First step is to validate the initializers and fill // in any missing bits // - if (!ValidateInitializers (ec, type)) + if (!ResolveInitializers (ec)) return null; + int arg_count; if (arguments == null) arg_count = 0; else { @@ -6411,13 +6108,6 @@ 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)); - return null; - } - if (arg_count == 1) { is_one_dimensional = true; eclass = ExprClass.Value; @@ -6484,7 +6174,7 @@ namespace Mono.CSharp { } } - public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc) + byte [] MakeByteBlob () { int factor; byte [] data; @@ -6500,7 +6190,7 @@ namespace Mono.CSharp { data = new byte [(count * factor + 4) & ~3]; int idx = 0; - + for (int i = 0; i < count; ++i) { object v = array_data [i]; @@ -6639,7 +6329,7 @@ namespace Mono.CSharp { FieldBuilder fb; ILGenerator ig = ec.ig; - byte [] data = MakeByteBlob (array_data, underlying_type, loc); + byte [] data = MakeByteBlob (); fb = RootContext.MakeStaticData (data); @@ -6660,90 +6350,69 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; int dims = bounds.Count; int [] current_pos = new int [dims]; - int top = array_data.Count; MethodInfo set = null; if (dims != 1){ - Type [] args; - ModuleBuilder mb = null; - mb = CodeGen.Module.Builder; - args = new Type [dims + 1]; + Type [] args = new Type [dims + 1]; - int j; - for (j = 0; j < dims; j++) + for (int j = 0; j < dims; j++) args [j] = TypeManager.int32_type; - - args [j] = array_element_type; + args [dims] = array_element_type; - set = mb.GetArrayMethod ( + set = CodeGen.Module.Builder.GetArrayMethod ( type, "Set", CallingConventions.HasThis | CallingConventions.Standard, TypeManager.void_type, args); } - - for (int i = 0; i < top; i++){ - Expression e = null; + for (int i = 0; i < array_data.Count; i++){ - if (array_data [i] is Expression) - e = (Expression) array_data [i]; + Expression e = (Expression)array_data [i]; if (e != null) { - // - // Basically we do this for string literals and - // other non-literal expressions - // - if (e is EnumConstant){ - e = ((EnumConstant) e).Child; - } - - if (e is StringConstant || e is DecimalConstant || !(e is Constant) || - num_automatic_initializers <= max_automatic_initializers) { - Type etype = e.Type; + Type etype = e.Type; - ig.Emit (OpCodes.Dup); + ig.Emit (OpCodes.Dup); - for (int idx = 0; idx < dims; idx++) - IntConstant.EmitInt (ig, current_pos [idx]); + for (int idx = 0; idx < dims; idx++) + IntConstant.EmitInt (ig, current_pos [idx]); - // - // If we are dealing with a struct, get the - // address of it, so we can store it. - // - if ((dims == 1) && - TypeManager.IsValueType (etype) && - (!TypeManager.IsBuiltinOrEnum (etype) || - etype == TypeManager.decimal_type)) { - if (e is New){ - New n = (New) e; - - // - // Let new know that we are providing - // the address where to store the results - // - n.DisableTemporaryValueType (); - } + // + // If we are dealing with a struct, get the + // address of it, so we can store it. + // + if ((dims == 1) && + TypeManager.IsValueType (etype) && + (!TypeManager.IsBuiltinOrEnum (etype) || + etype == TypeManager.decimal_type)) { + if (e is New){ + New n = (New) e; - ig.Emit (OpCodes.Ldelema, etype); + // + // Let new know that we are providing + // the address where to store the results + // + n.DisableTemporaryValueType (); } - e.Emit (ec); - - if (dims == 1) { - bool is_stobj, has_type_arg; - OpCode op = ArrayAccess.GetStoreOpcode ( - etype, out is_stobj, - out has_type_arg); - if (is_stobj) - ig.Emit (OpCodes.Stobj, etype); - else if (has_type_arg) - ig.Emit (op, etype); - else - ig.Emit (op); - } else - ig.Emit (OpCodes.Call, set); + ig.Emit (OpCodes.Ldelema, etype); } + + e.Emit (ec); + + if (dims == 1) { + bool is_stobj, has_type_arg; + OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg); + if (is_stobj) + ig.Emit (OpCodes.Stobj, etype); + else if (has_type_arg) + ig.Emit (op, etype); + else + ig.Emit (op); + } else + ig.Emit (OpCodes.Call, set); + } // @@ -6787,60 +6456,87 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Newobj, (MethodInfo) new_method); } - if (initializers != null){ - // - // FIXME: Set this variable correctly. - // - bool dynamic_initializers = true; + if (initializers == null) + return; - // This will never be true for array types that cannot be statically - // initialized. num_automatic_initializers will always be zero. See - // CheckIndices. - if (num_automatic_initializers > max_automatic_initializers) - EmitStaticInitializers (ec); - - if (dynamic_initializers) - EmitDynamicInitializers (ec); + // This is a treshold for static initializers + // I tried to make more accurate but it seems to me that Array.Initialize is + // always slower (managed -> unmanaged switch?) + const int max_automatic_initializers = 200; + + if (const_initializers_count > max_automatic_initializers && TypeManager.IsPrimitiveType (array_element_type)) { + EmitStaticInitializers (ec); + return; } + + EmitDynamicInitializers (ec); } - public object EncodeAsAttribute () + public override bool GetAttributableValue (Type valueType, out object value) { if (!is_one_dimensional){ - Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays"); - return null; +// Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays"); + return base.GetAttributableValue (null, out value); } - if (array_data == null){ - Report.Error (-212, Location, "array should be initialized when passing it to an attribute"); - return null; + if (array_data == null) { + Constant c = (Constant)((Argument)arguments [0]).Expr; + if (c.IsDefaultValue) { + value = Array.CreateInstance (array_element_type, 0); + return true; + } +// Report.Error (-212, Location, "array should be initialized when passing it to an attribute"); + return base.GetAttributableValue (null, out value); } - object [] ret = new object [array_data.Count]; - int i = 0; - foreach (Expression e in array_data){ - object v; - - if (e is NullLiteral) - v = null; - else { - if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v)) - return null; + Array ret = Array.CreateInstance (array_element_type, array_data.Count); + object element_value; + for (int i = 0; i < ret.Length; ++i) + { + Expression e = (Expression)array_data [i]; + if (e == null) // Is null when initializer is optimized away + e = (Expression)initializers [i]; + + if (!e.GetAttributableValue (array_element_type, out element_value)) { + value = null; + return false; } - ret [i++] = v; + ret.SetValue (element_value, i); } - return ret; + value = ret; + return true; + } + } + + public sealed class CompilerGeneratedThis : This + { + public static This Instance = new CompilerGeneratedThis (); + + private CompilerGeneratedThis () + : base (Location.Null) + { + } + + public override Expression DoResolve (EmitContext ec) + { + eclass = ExprClass.Variable; + type = ec.ContainerType; + variable = new SimpleThis (type); + return this; } } /// /// Represents the `this' construct /// - public class This : Expression, IAssignMethod, IMemoryLocation, IVariable { + public class This : VariableReference, IVariable + { Block block; VariableInfo variable_info; - + protected Variable variable; + bool is_struct; + public This (Block block, Location loc) { this.loc = loc; @@ -6861,6 +6557,14 @@ namespace Mono.CSharp { return !TypeManager.IsValueType (Type); } + public override bool IsRef { + get { return is_struct; } + } + + public override Variable Variable { + get { return variable; } + } + public bool ResolveBase (EmitContext ec) { eclass = ExprClass.Variable; @@ -6870,16 +6574,38 @@ namespace Mono.CSharp { else type = ec.ContainerType; + is_struct = ec.TypeContainer is Struct; + if (ec.IsStatic) { - Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer"); + Error (26, "Keyword `this' is not valid in a static property, " + + "static method, or static field initializer"); return false; } - if (block != null && block.Toplevel.ThisVariable != null) - variable_info = block.Toplevel.ThisVariable.VariableInfo; + if (block != null) { + if (block.Toplevel.ThisVariable != null) + variable_info = block.Toplevel.ThisVariable.VariableInfo; + + AnonymousContainer am = ec.CurrentAnonymousMethod; + if (is_struct && (am != null) && !am.IsIterator) { + Report.Error (1673, loc, "Anonymous methods inside structs " + + "cannot access instance members of `this'. " + + "Consider copying `this' to a local variable " + + "outside the anonymous method and using the " + + "local instead."); + return false; + } + + AnonymousMethodHost host = block.Toplevel.AnonymousMethodHost; + if ((host != null) && (!is_struct || host.IsIterator)) { + variable = host.CaptureThis (); + type = variable.Type; + is_struct = false; + } + } - if (ec.CurrentAnonymousMethod != null) - ec.CaptureThis (); + if (variable == null) + variable = new SimpleThis (type); return true; } @@ -6889,8 +6615,10 @@ namespace Mono.CSharp { if (!ResolveBase (ec)) return null; - 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"); + 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; } @@ -6918,47 +6646,6 @@ namespace Mono.CSharp { return this; } - - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) - { - ILGenerator ig = ec.ig; - - if (ec.TypeContainer is Struct){ - ec.EmitThis (false); - source.Emit (ec); - - LocalTemporary t = null; - if (leave_copy) { - t = new LocalTemporary (ec, type); - ec.ig.Emit (OpCodes.Dup); - t.Store (ec); - } - - ig.Emit (OpCodes.Stobj, type); - - if (leave_copy) - t.Emit (ec); - } else { - throw new Exception ("how did you get here"); - } - } - - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - ec.EmitThis (false); - if (ec.TypeContainer is Struct) - ig.Emit (OpCodes.Ldobj, type); - } - public override int GetHashCode() { return block.GetHashCode (); @@ -6973,18 +6660,46 @@ namespace Mono.CSharp { return block == t.block; } - public void AddressOf (EmitContext ec, AddressOp mode) + protected class SimpleThis : Variable { - ec.EmitThis (true); + Type type; - // FIMXE - // FIGURE OUT WHY LDARG_S does not work - // - // consider: struct X { int val; int P { set { val = value; }}} - // - // Yes, this looks very bad. Look at `NOTAS' for - // an explanation. - // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0); + public SimpleThis (Type type) + { + this.type = type; + } + + public override Type Type { + get { return type; } + } + + public override bool HasInstance { + get { return false; } + } + + public override bool NeedsTemporary { + get { return false; } + } + + public override void EmitInstance (EmitContext ec) + { + // Do nothing. + } + + public override void Emit (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } + + public override void EmitAssign (EmitContext ec) + { + throw new InvalidOperationException (); + } + + public override void EmitAddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarg_0); + } } } @@ -6998,21 +6713,15 @@ namespace Mono.CSharp { this.loc = loc; } - public bool ResolveBase (EmitContext ec) + public override Expression DoResolve (EmitContext ec) { eclass = ExprClass.Variable; type = TypeManager.runtime_argument_handle_type; - return true; - } - - public override Expression DoResolve (EmitContext ec) - { - if (!ResolveBase (ec)) - return null; - if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) { + if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) + { Error (190, "The __arglist construct is valid only within " + - "a variable argument method."); + "a variable argument method"); return null; } @@ -7094,7 +6803,7 @@ namespace Mono.CSharp { /// Implements the typeof operator /// public class TypeOf : Expression { - public Expression QueriedType; + readonly Expression QueriedType; protected Type typearg; public TypeOf (Expression queried_type, Location l) @@ -7109,7 +6818,7 @@ namespace Mono.CSharp { if (texpr == null) return null; - typearg = texpr.ResolveType (ec); + typearg = texpr.Type; if (typearg == TypeManager.void_type) { Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object"); @@ -7134,8 +6843,30 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle); } - public Type TypeArg { - get { return typearg; } + public override bool GetAttributableValue (Type valueType, out object value) + { + if (typearg.ContainsGenericParameters) { + Report.SymbolRelatedToPreviousError(typearg); + Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters", + TypeManager.CSharpName(typearg)); + value = null; + return false; + } + + if (valueType == TypeManager.object_type) { + value = (object)typearg; + return true; + } + value = typearg; + return true; + } + + public Type TypeArgument + { + get + { + return typearg; + } } } @@ -7182,7 +6913,14 @@ namespace Mono.CSharp { return null; } - type_queried = texpr.ResolveType (ec); + type_queried = texpr.Type; + if (type_queried.IsEnum) + type_queried = TypeManager.EnumToUnderlying (type_queried); + + if (type_queried == TypeManager.void_type) { + Expression.Error_VoidInvalidInTheContext (loc); + return null; + } int size_of = GetTypeSize (type_queried); if (size_of > 0) { @@ -7229,7 +6967,7 @@ namespace Mono.CSharp { loc = l; } - public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) + public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent) { if (alias == "global") return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent); @@ -7246,7 +6984,7 @@ namespace Mono.CSharp { 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); + return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent); } public override Expression DoResolve (EmitContext ec) @@ -7264,7 +7002,7 @@ namespace Mono.CSharp { } } - Expression retval = new MemberAccess (fne, identifier, loc).DoResolve (ec); + Expression retval = new MemberAccess (fne, identifier).DoResolve (ec); if (retval == null) return null; @@ -7306,17 +7044,20 @@ namespace Mono.CSharp { Expression expr; TypeArguments args; - // TODO: Location can be removed - public MemberAccess (Expression expr, string id, Location l) + public MemberAccess (Expression expr, string id) + : this (expr, id, expr.Location) + { + } + + public MemberAccess (Expression expr, string identifier, Location loc) { this.expr = expr; - Identifier = id; - loc = expr.Location; + Identifier = identifier; + this.loc = loc; } - public MemberAccess (Expression expr, string id, TypeArguments args, - Location l) - : this (expr, id, l) + public MemberAccess (Expression expr, string id, TypeArguments args) + : this (expr, id) { this.args = args; } @@ -7354,8 +7095,7 @@ namespace Mono.CSharp { if ((retval != null) && (args != null)) retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false); if (retval == null) - 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); + ns.Error_NamespaceDoesNotExist (loc, Identifier); return retval; } @@ -7453,14 +7193,14 @@ namespace Mono.CSharp { return DoResolve (ec, right_side); } - public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) + public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent) { return ResolveNamespaceOrType (ec, silent); } - public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent) + public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent) { - FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec, silent); + FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent); if (new_expr == null) return null; @@ -7469,20 +7209,19 @@ namespace Mono.CSharp { if (new_expr is Namespace) { Namespace ns = (Namespace) new_expr; - FullNamedExpression retval = ns.Lookup (ec.DeclContainer, lookup_id, loc); + FullNamedExpression retval = ns.Lookup (rc.DeclContainer, lookup_id, loc); if ((retval != null) && (args != null)) - retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false); + retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false); if (!silent && retval == null) - 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); + ns.Error_NamespaceDoesNotExist (loc, Identifier); return retval; } - TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (ec, false); + TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false); if (tnew_expr == null) return null; - Type expr_type = tnew_expr.ResolveType (ec); + Type expr_type = tnew_expr.Type; if (expr_type.IsPointer){ Error (23, "The `.' operator can not be applied to pointer operands (" + @@ -7491,11 +7230,11 @@ namespace Mono.CSharp { } Expression member_lookup = MemberLookup ( - ec.ContainerType, expr_type, expr_type, lookup_id, + rc.DeclContainer.TypeBuilder, expr_type, expr_type, lookup_id, MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc); if (member_lookup == null) { int errors = Report.Errors; - MemberLookupFailed (ec.ContainerType, expr_type, expr_type, lookup_id, null, false, loc); + MemberLookupFailed (rc.DeclContainer.TypeBuilder, expr_type, expr_type, lookup_id, null, false, loc); if (!silent && errors == Report.Errors) { Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'", @@ -7505,11 +7244,11 @@ namespace Mono.CSharp { } if (!(member_lookup is TypeExpr)) { - new_expr.Error_UnexpectedKind (ec.DeclContainer, "type", loc); + new_expr.Error_UnexpectedKind (rc.DeclContainer, "type", loc); return null; } - TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (ec, false); + TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false); if (texpr == null) return null; @@ -7529,7 +7268,7 @@ namespace Mono.CSharp { if (the_args != null) { ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc); - return ctype.ResolveAsTypeStep (ec, false); + return ctype.ResolveAsTypeStep (rc, false); } return texpr; @@ -7566,14 +7305,8 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - bool last_check = ec.CheckState; - bool last_const_check = ec.ConstantCheckState; - - ec.CheckState = true; - ec.ConstantCheckState = true; - Expr = Expr.Resolve (ec); - ec.CheckState = last_check; - ec.ConstantCheckState = last_const_check; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + Expr = Expr.Resolve (ec); if (Expr == null) return null; @@ -7588,16 +7321,15 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - bool last_check = ec.CheckState; - bool last_const_check = ec.ConstantCheckState; - - ec.CheckState = true; - ec.ConstantCheckState = true; - Expr.Emit (ec); - ec.CheckState = last_check; - ec.ConstantCheckState = last_const_check; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + Expr.Emit (ec); + } + + public override void EmitBranchable (EmitContext ec, Label target, bool onTrue) + { + using (ec.With (EmitContext.Flags.AllCheckStateFlags, true)) + Expr.EmitBranchable (ec, target, onTrue); } - } /// @@ -7615,14 +7347,8 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - bool last_check = ec.CheckState; - bool last_const_check = ec.ConstantCheckState; - - ec.CheckState = false; - ec.ConstantCheckState = false; - Expr = Expr.Resolve (ec); - ec.CheckState = last_check; - ec.ConstantCheckState = last_const_check; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + Expr = Expr.Resolve (ec); if (Expr == null) return null; @@ -7637,16 +7363,15 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - bool last_check = ec.CheckState; - bool last_const_check = ec.ConstantCheckState; - - ec.CheckState = false; - ec.ConstantCheckState = false; - Expr.Emit (ec); - ec.CheckState = last_check; - ec.ConstantCheckState = last_const_check; + using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + Expr.Emit (ec); } + public override void EmitBranchable (EmitContext ec, Label target, bool onTrue) + { + using (ec.With (EmitContext.Flags.AllCheckStateFlags, false)) + Expr.EmitBranchable (ec, target, onTrue); + } } /// @@ -8042,7 +7767,7 @@ namespace Mono.CSharp { if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); + temp = new LocalTemporary (this.type); temp.Store (ec); } } @@ -8065,13 +7790,15 @@ namespace Mono.CSharp { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); + temp = new LocalTemporary (this.type); temp.Store (ec); } StoreFromPtr (ec.ig, t); - if (temp != null) + if (temp != null) { temp.Emit (ec); + temp.Release (ec); + } return; } @@ -8093,7 +7820,7 @@ namespace Mono.CSharp { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); + temp = new LocalTemporary (this.type); temp.Store (ec); } @@ -8112,7 +7839,7 @@ namespace Mono.CSharp { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); + temp = new LocalTemporary (this.type); temp.Store (ec); } @@ -8132,8 +7859,10 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, set); } - if (temp != null) + if (temp != null) { temp.Emit (ec); + temp.Release (ec); + } } public void AddressOf (EmitContext ec, AddressOp mode) @@ -8226,7 +7955,7 @@ namespace Mono.CSharp { BindingFlags.DeclaredOnly, p_name, null); } - static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) + static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) { Indexers ix = empty; @@ -8304,7 +8033,6 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - ArrayList AllGetters = new ArrayList(); if (!CommonResolve (ec)) return null; @@ -8314,37 +8042,35 @@ namespace Mono.CSharp { // // This is a group of properties, piles of them. - bool found_any = false, found_any_getters = false; - Type lookup_type = indexer_type; + ArrayList AllGetters = null; - Indexers ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc); + Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type); if (ilist.Properties != null) { - found_any = true; + AllGetters = new ArrayList(ilist.Properties.Count); foreach (Indexers.Indexer ix in ilist.Properties) { if (ix.Getter != null) AllGetters.Add (ix.Getter); } } - if (AllGetters.Count > 0) { - found_any_getters = true; - get = (MethodInfo) Invocation.OverloadResolve ( - ec, new MethodGroupExpr (AllGetters, loc), - arguments, false, loc); - } - - if (!found_any) { + if (AllGetters == null) { Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'", - TypeManager.CSharpName (indexer_type)); + TypeManager.CSharpName (indexer_type)); return null; } - if (!found_any_getters) { + if (AllGetters.Count == 0) { + // FIXME: we cannot simply select first one as the error message is missleading when + // multiple indexers exist + Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1]; Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor", - "XXXXXXXX"); + TypeManager.GetFullNameSignature (first_indexer.PropertyInfo)); return null; } + get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc), + arguments, false, loc); + if (get == null) { Invocation.Error_WrongNumArguments (loc, "this", arguments.Count); return null; @@ -8364,7 +8090,7 @@ namespace Mono.CSharp { return null; } - instance_expr.CheckMarshallByRefAccess (ec.ContainerType); + instance_expr.CheckMarshalByRefAccess (); eclass = ExprClass.IndexerAccess; return this; @@ -8379,7 +8105,7 @@ namespace Mono.CSharp { } // if the indexer returns a value type, and we try to set a field in it - if (right_side == EmptyExpression.LValueMemberAccess) { + if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) { Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable", GetSignatureForError ()); return null; @@ -8391,7 +8117,7 @@ namespace Mono.CSharp { bool found_any = false, found_any_setters = false; - Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc); + Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type); if (ilist.Properties != null) { found_any = true; foreach (Indexers.Indexer ix in ilist.Properties) { @@ -8444,7 +8170,7 @@ namespace Mono.CSharp { } } - instance_expr.CheckMarshallByRefAccess (ec.ContainerType); + instance_expr.CheckMarshalByRefAccess (); eclass = ExprClass.IndexerAccess; return this; @@ -8458,7 +8184,7 @@ namespace Mono.CSharp { Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, Type); + temp = new LocalTemporary (Type); temp.Store (ec); } } @@ -8477,11 +8203,11 @@ namespace Mono.CSharp { source.Emit (ec); if (leave_copy) { ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, Type); + temp = new LocalTemporary (Type); temp.Store (ec); } } else if (leave_copy) { - temp = new LocalTemporary (ec, Type); + temp = new LocalTemporary (Type); source.Emit (ec); temp.Store (ec); a.Expr = temp; @@ -8489,8 +8215,10 @@ namespace Mono.CSharp { Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared); - if (temp != null) + if (temp != null) { temp.Emit (ec); + temp.Release (ec); + } } @@ -8656,6 +8384,7 @@ namespace Mono.CSharp { public static readonly EmptyExpression OutAccess = new EmptyExpression (); public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression (); + public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression (); static EmptyExpression temp = new EmptyExpression (); public static EmptyExpression Grab () @@ -8784,16 +8513,15 @@ namespace Mono.CSharp { return this; } - protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) + protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) { TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false); if (lexpr == null) return null; - Type ltype = lexpr.ResolveType (ec); + Type ltype = lexpr.Type; if ((ltype == TypeManager.void_type) && (dim != "*")) { - Report.Error (1547, Location, - "Keyword 'void' cannot be used in this context"); + Error_VoidInvalidInTheContext (loc); return null; } @@ -8972,7 +8700,7 @@ namespace Mono.CSharp { if (texpr == null) return null; - otype = texpr.ResolveType (ec); + otype = texpr.Type; if (!TypeManager.VerifyUnManaged (otype, loc)) return null;