X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=87e0a954f08a2b73122a53145bb9dedf5f4380c2;hb=6532ba9161a25f45c841c4b28adb2877fde069da;hp=889d3eba69703e357e38bd15c0fb18a984ce0a12;hpb=dac1a705ea8721eeff8b2a91da1747d04706f0bb;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs old mode 100755 new mode 100644 index 889d3eba697..87e0a954f08 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -46,13 +46,13 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { if (args != null) - Invocation.EmitArguments (ec, mi, args); + Invocation.EmitArguments (ec, mi, args, false, null); ec.ig.Emit (OpCodes.Call, mi); return; } - static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, + static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, Expression e, Location loc) { ArrayList args; @@ -81,6 +81,10 @@ namespace Mono.CSharp { if (TypeManager.TypeToCoreType (type) != TypeManager.void_type) ec.ig.Emit (OpCodes.Pop); } + + public MethodInfo Method { + get { return mi; } + } } public class ParenthesizedExpression : Expression @@ -319,11 +323,22 @@ namespace Mono.CSharp { Expression ResolveOperator (EmitContext ec) { - Type expr_type = Expr.Type; + // + // Step 1: Default operations on CLI native types. + // + + // Attempt to use a constant folding operation. + if (Expr is Constant){ + Expression result; + + if (Reduce (ec, (Constant) Expr, out result)) + return result; + } // - // Step 1: Perform Operator Overload location + // Step 2: Perform Operator Overload location // + Type expr_type = Expr.Type; Expression mg; string op_name; @@ -349,18 +364,6 @@ namespace Mono.CSharp { if (expr_type == null) return null; - // - // Step 2: Default operations on CLI native types. - // - - // Attempt to use a constant folding operation. - if (Expr is Constant){ - Expression result; - - if (Reduce (ec, (Constant) Expr, out result)) - return result; - } - switch (Oper){ case Operator.LogicalNot: if (expr_type != TypeManager.bool_type) { @@ -435,6 +438,16 @@ namespace Mono.CSharp { return null; } + LocalVariableReference lr = Expr as LocalVariableReference; + if (lr != null){ + if (lr.local_info.IsCaptured){ + AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc); + return null; + } + lr.local_info.AddressTaken = true; + lr.local_info.Used = true; + } + // According to the specs, a variable is considered definitely assigned if you take // its address. if ((variable != null) && (variable.VariableInfo != null)) @@ -644,7 +657,7 @@ namespace Mono.CSharp { public class Indirection : Expression, IMemoryLocation, IAssignMethod { Expression expr; LocalTemporary temporary; - bool have_temporary; + bool prepared; public Indirection (Expression expr, Location l) { @@ -660,54 +673,47 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; - - if (temporary != null){ - if (have_temporary) { - temporary.Emit (ec); - } else { + if (!prepared) expr.Emit (ec); + + LoadFromPtr (ec.ig, Type); + } + + public void Emit (EmitContext ec, bool leave_copy) + { + Emit (ec); + if (leave_copy) { ec.ig.Emit (OpCodes.Dup); + temporary = new LocalTemporary (ec, expr.Type); temporary.Store (ec); - have_temporary = true; - } - } else - expr.Emit (ec); - - LoadFromPtr (ig, Type); + } } - public void EmitAssign (EmitContext ec, Expression source) + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { - if (temporary != null){ - if (have_temporary) - temporary.Emit (ec); - else { - expr.Emit (ec); - ec.ig.Emit (OpCodes.Dup); - temporary.Store (ec); - have_temporary = true; - } - } else - expr.Emit (ec); + prepared = prepare_for_load; + + expr.Emit (ec); + + if (prepare_for_load) + ec.ig.Emit (OpCodes.Dup); source.Emit (ec); + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temporary = new LocalTemporary (ec, expr.Type); + temporary.Store (ec); + } + StoreFromPtr (ec.ig, type); + + if (temporary != null) + temporary.Emit (ec); } - + public void AddressOf (EmitContext ec, AddressOp Mode) { - if (temporary != null){ - if (have_temporary){ - temporary.Emit (ec); - return; - } - expr.Emit (ec); - ec.ig.Emit (OpCodes.Dup); - temporary.Store (ec); - have_temporary = true; - } else - expr.Emit (ec); + expr.Emit (ec); } public override Expression DoResolve (EmitContext ec) @@ -717,12 +723,7 @@ namespace Mono.CSharp { // return this; } - - public new void CacheTemporaries (EmitContext ec) - { - temporary = new LocalTemporary (ec, expr.Type); - } - + public override string ToString () { return "*(" + expr + ")"; @@ -758,13 +759,15 @@ namespace Mono.CSharp { } Mode mode; + bool is_expr = false; + bool recurse = false; + Expression expr; - LocalTemporary temp_storage; // // This is expensive for the simplest case. // - Expression method; + StaticCallExpr method; public UnaryMutator (Mode m, Expression e, Location l) { @@ -856,9 +859,7 @@ namespace Mono.CSharp { } else if (expr.eclass == ExprClass.IndexerAccess){ IndexerAccess ia = (IndexerAccess) expr; - temp_storage = new LocalTemporary (ec, expr.Type); - - expr = ia.ResolveLValue (ec, temp_storage); + expr = ia.ResolveLValue (ec, this); if (expr == null) return null; @@ -871,7 +872,7 @@ namespace Mono.CSharp { return null; } else { - expr.Error_UnexpectedKind ("variable, indexer or property access"); + expr.Error_UnexpectedKind ("variable, indexer or property access", loc); return null; } @@ -976,114 +977,39 @@ namespace Mono.CSharp { } } - - static EmptyExpression empty_expr; void EmitCode (EmitContext ec, bool is_expr) { - ILGenerator ig = ec.ig; - IAssignMethod ia = (IAssignMethod) expr; - Type expr_type = expr.Type; - - ia.CacheTemporaries (ec); + recurse = true; + this.is_expr = is_expr; + ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true); + } + + public override void Emit (EmitContext ec) + { // - // NOTE: We should probably handle three cases: - // - // * method invocation required. - // * direct stack manipulation possible - // * the object requires an "instance" field + // We use recurse to allow ourselfs to be the source + // of an assignment. This little hack prevents us from + // having to allocate another expression // - if (temp_storage == null){ - // - // Temporary improvement: if we are dealing with something that does - // not require complicated instance setup, avoid using a temporary - // - // For now: only localvariables when not remapped - // - - if (method == null && - ((expr is LocalVariableReference) ||(expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic))){ - if (empty_expr == null) - empty_expr = new EmptyExpression (); - - switch (mode){ - case Mode.PreIncrement: - case Mode.PreDecrement: - expr.Emit (ec); - - LoadOneAndEmitOp (ec, expr_type); - if (is_expr) - ig.Emit (OpCodes.Dup); - ia.EmitAssign (ec, empty_expr); - break; - - case Mode.PostIncrement: - case Mode.PostDecrement: - expr.Emit (ec); - if (is_expr) - ig.Emit (OpCodes.Dup); - - LoadOneAndEmitOp (ec, expr_type); - ia.EmitAssign (ec, empty_expr); - break; - } - return; - } - temp_storage = new LocalTemporary (ec, expr_type); + if (recurse) { + ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement)); + if (method == null) + LoadOneAndEmitOp (ec, expr.Type); + else + ec.ig.Emit (OpCodes.Call, method.Method); + recurse = false; + return; } - switch (mode){ - case Mode.PreIncrement: - case Mode.PreDecrement: - if (method == null){ - expr.Emit (ec); - - LoadOneAndEmitOp (ec, expr_type); - } else - method.Emit (ec); - - temp_storage.Store (ec); - ia.EmitAssign (ec, temp_storage); - if (is_expr) - temp_storage.Emit (ec); - break; - - case Mode.PostIncrement: - case Mode.PostDecrement: - if (is_expr) - expr.Emit (ec); - - if (method == null){ - if (!is_expr) - expr.Emit (ec); - else - ig.Emit (OpCodes.Dup); - - LoadOneAndEmitOp (ec, expr_type); - } else { - method.Emit (ec); - } - - temp_storage.Store (ec); - ia.EmitAssign (ec, temp_storage); - break; - } - - temp_storage.Release (ec); - } - - public override void Emit (EmitContext ec) - { EmitCode (ec, true); - } public override void EmitStatement (EmitContext ec) { EmitCode (ec, false); } - } /// @@ -1095,7 +1021,7 @@ namespace Mono.CSharp { /// size. /// public abstract class Probe : Expression { - public readonly Expression ProbeType; + public Expression ProbeType; protected Expression expr; protected Type probe_type; @@ -1114,10 +1040,10 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc); - - if (probe_type == null) + TypeExpr texpr = ProbeType.ResolveAsTypeTerminal (ec); + if (texpr == null) return null; + probe_type = texpr.Type; CheckObsoleteAttribute (probe_type); @@ -1125,6 +1051,10 @@ namespace Mono.CSharp { if (expr == null) return null; + if (expr.Type.IsPointer) { + Report.Error (244, loc, "\"is\" or \"as\" are not valid on pointer types"); + return null; + } return this; } } @@ -1232,6 +1162,9 @@ namespace Mono.CSharp { warning_always_matches = true; } else if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){ + if (etype.IsGenericParameter) + expr = new BoxedCast (expr, etype); + // // Second case: explicit reference convresion // @@ -1244,20 +1177,15 @@ namespace Mono.CSharp { warning_never_matches = true; } - if (RootContext.WarningLevel >= 1){ - if (warning_always_matches) - Warning (183, "The expression is always of type `" + - TypeManager.CSharpName (probe_type) + "'"); - else if (warning_never_matches){ - if (!(probe_type.IsInterface || expr.Type.IsInterface)) - Warning (184, - "The expression is never of type `" + - TypeManager.CSharpName (probe_type) + "'"); - } + if (warning_always_matches) + Warning (183, "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)); } return this; - } + } } /// @@ -1315,6 +1243,9 @@ namespace Mono.CSharp { } if (Convert.ExplicitReferenceConversionExists (etype, probe_type)){ + if (etype.IsGenericParameter) + expr = new BoxedCast (expr, etype); + do_isinst = true; return this; } @@ -1852,13 +1783,19 @@ namespace Mono.CSharp { if (expr == null) return null; - type = ec.DeclSpace.ResolveType (target_type, false, Location); - - if (type == null) + TypeExpr target = target_type.ResolveAsTypeTerminal (ec); + if (target == null) return null; + + type = target.Type; CheckObsoleteAttribute (type); + if (type.IsAbstract && type.IsSealed) { + Report.Error (716, loc, "Cannot convert to static type '{0}'", TypeManager.CSharpName (type)); + return null; + } + eclass = ExprClass.Value; if (expr is Constant){ @@ -2139,6 +2076,10 @@ namespace Mono.CSharp { (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)){ // @@ -2306,14 +2247,12 @@ namespace Mono.CSharp { Type l = left.Type; Type r = right.Type; - bool overload_failed = false; - // // Special cases: string or type parameter comapred to null // if (oper == Operator.Equality || oper == Operator.Inequality){ - if ((l == TypeManager.string_type && (right is NullLiteral)) || - (r == TypeManager.string_type && (left is NullLiteral))){ + if ((!TypeManager.IsValueType (l) && r == TypeManager.null_type) || + (!TypeManager.IsValueType (r) && l == TypeManager.null_type)) { Type = TypeManager.bool_type; return this; @@ -2382,8 +2321,6 @@ namespace Mono.CSharp { MethodInfo mi = (MethodInfo) method; return new BinaryMethod (mi.ReturnType, method, args); - } else { - overload_failed = true; } } } @@ -2474,8 +2411,8 @@ namespace Mono.CSharp { // // Also, a standard conversion must exist from either one // - if (!(Convert.ImplicitStandardConversionExists (left, r) || - Convert.ImplicitStandardConversionExists (right, l))){ + if (!(Convert.ImplicitStandardConversionExists (ec, left, r) || + Convert.ImplicitStandardConversionExists (ec, right, l))){ Error_OperatorCannotBeApplied (); return null; } @@ -2507,13 +2444,16 @@ namespace Mono.CSharp { // if (oper == Operator.Addition || oper == Operator.Subtraction) { if (TypeManager.IsDelegateType (l)){ - if (right.eclass == ExprClass.MethodGroup && RootContext.V2){ + if (((right.eclass == ExprClass.MethodGroup) || + (r == TypeManager.anonymous_method_type))){ + if ((RootContext.Version != LanguageVersion.ISO_1)){ Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc); if (tmp == null) return null; right = tmp; r = right.Type; } + } if (TypeManager.IsDelegateType (r)){ MethodInfo method; @@ -2562,16 +2502,16 @@ namespace Mono.CSharp { if (r == l) return new PointerArithmetic ( false, left, right, TypeManager.int64_type, - loc); + loc).Resolve (ec); } else { Expression t = Make32or64 (ec, right); if (t != null) - return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc); + return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec); } } else if (r.IsPointer && oper == Operator.Addition){ Expression t = Make32or64 (ec, left); if (t != null) - return new PointerArithmetic (true, right, t, r, loc); + return new PointerArithmetic (true, right, t, r, loc).Resolve (ec); } } @@ -2708,14 +2648,6 @@ namespace Mono.CSharp { } } - // - // We are dealing with numbers - // - if (overload_failed){ - Error_OperatorCannotBeApplied (); - return null; - } - // // This will leave left or right set to null if there is an error // @@ -2779,16 +2711,27 @@ namespace Mono.CSharp { } } else left = left.Resolve (ec); - right = right.Resolve (ec); - if (left == null || right == null) + if (left == null) + return null; + + Constant lc = left as Constant; + if (lc != null && lc.Type == TypeManager.bool_type && + ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) || + (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) { + + // TODO: make a sence to resolve unreachable expression as we do for statement + Report.Warning (429, 4, loc, "Unreachable expression code detected"); + return left; + } + + right = right.Resolve (ec); + if (right == null) return null; eclass = ExprClass.Value; Constant rc = right as Constant; - Constant lc = left as Constant; - if (rc != null & lc != null){ Expression e = ConstantFold.BinaryFold ( ec, oper, lc, rc, loc); @@ -3163,7 +3106,7 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; if (Arguments != null) - Invocation.EmitArguments (ec, method, Arguments); + Invocation.EmitArguments (ec, method, Arguments, false, null); if (method is MethodInfo) ig.Emit (OpCodes.Call, (MethodInfo) method); @@ -3179,7 +3122,11 @@ namespace Mono.CSharp { public class StringConcat : Expression { ArrayList operands; bool invalid = false; - + bool emit_conv_done = false; + // + // Are we also concating objects? + // + bool is_strings_only = true; public StringConcat (EmitContext ec, Location loc, Expression left, Expression right) { @@ -3233,14 +3180,13 @@ namespace Mono.CSharp { { MethodInfo concat_method = null; - // - // Are we also concating objects? - // - bool is_strings_only = true; - // // Do conversion to arguments; check for strings only // + + // This can get called multiple times, so we have to deal with that. + if (!emit_conv_done) { + emit_conv_done = true; for (int i = 0; i < operands.Count; i ++) { Expression e = (Expression) operands [i]; is_strings_only &= e.Type == TypeManager.string_type; @@ -3254,10 +3200,11 @@ namespace Mono.CSharp { // method might look at the type of this expression, see it is a // string and emit a string [] when we want an object []; - e = Convert.ImplicitConversion (ec, e, TypeManager.object_type, loc); + e = new EmptyCast (e, TypeManager.object_type); } operands [i] = new Argument (e, Argument.AType.Expression); } + } // // Find the right method @@ -3298,7 +3245,7 @@ namespace Mono.CSharp { break; } - Invocation.EmitArguments (ec, concat_method, operands); + Invocation.EmitArguments (ec, concat_method, operands, false, null); ec.ig.Emit (OpCodes.Call, concat_method); } } @@ -3327,7 +3274,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - Invocation.EmitArguments (ec, method, args); + Invocation.EmitArguments (ec, method, args, false, null); ig.Emit (OpCodes.Call, (MethodInfo) method); ig.Emit (OpCodes.Castclass, type); @@ -3419,8 +3366,6 @@ namespace Mono.CSharp { Label false_target = ig.DefineLabel (); Label end_target = ig.DefineLabel (); - ig.Emit (OpCodes.Nop); - left.Emit (ec); left_temp.Store (ec); @@ -3430,8 +3375,6 @@ namespace Mono.CSharp { ig.MarkLabel (false_target); op.Emit (ec); ig.MarkLabel (end_target); - - ig.Emit (OpCodes.Nop); } } @@ -3445,7 +3388,6 @@ namespace Mono.CSharp { public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc) { type = t; - eclass = ExprClass.Variable; this.loc = loc; left = l; right = r; @@ -3454,9 +3396,13 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - // - // We are born fully resolved - // + eclass = ExprClass.Variable; + + if (left.Type == TypeManager.void_ptr_type) { + Error (242, "The operation in question is undefined on void pointers"); + return null; + } + return this; } @@ -3464,7 +3410,8 @@ namespace Mono.CSharp { { Type op_type = left.Type; ILGenerator ig = ec.ig; - int size = GetTypeSize (TypeManager.GetElementType (op_type)); + Type element = TypeManager.GetElementType (op_type); + int size = GetTypeSize (element); Type rtype = right.Type; if (rtype.IsPointer){ @@ -3477,7 +3424,7 @@ namespace Mono.CSharp { if (size != 1){ if (size == 0) - ig.Emit (OpCodes.Sizeof, op_type); + ig.Emit (OpCodes.Sizeof, element); else IntLiteral.EmitInt (ig, size); ig.Emit (OpCodes.Div); @@ -3492,7 +3439,7 @@ namespace Mono.CSharp { right.Emit (ec); if (size != 1){ if (size == 0) - ig.Emit (OpCodes.Sizeof, op_type); + ig.Emit (OpCodes.Sizeof, element); else IntLiteral.EmitInt (ig, size); if (rtype == TypeManager.int64_type) @@ -3500,8 +3447,11 @@ namespace Mono.CSharp { else if (rtype == TypeManager.uint64_type) ig.Emit (OpCodes.Conv_U8); ig.Emit (OpCodes.Mul); - ig.Emit (OpCodes.Conv_I); } + + if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type) + ig.Emit (OpCodes.Conv_I); + if (is_add) ig.Emit (OpCodes.Add); else @@ -3571,14 +3521,6 @@ namespace Mono.CSharp { Type true_type = trueExpr.Type; Type false_type = falseExpr.Type; - if (trueExpr is NullLiteral){ - type = false_type; - return this; - } else if (falseExpr is NullLiteral){ - type = true_type; - return this; - } - // // First, if an implicit conversion exists from trueExpr // to falseExpr, then the result type is of type falseExpr.Type @@ -3644,8 +3586,10 @@ namespace Mono.CSharp { public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable { public readonly string Name; public readonly Block Block; - LocalInfo local_info; + public LocalInfo local_info; bool is_readonly; + bool prepared; + LocalTemporary temp; public LocalVariableReference (Block block, string name, Location l) { @@ -3655,8 +3599,10 @@ namespace Mono.CSharp { 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) @@ -3666,7 +3612,9 @@ namespace Mono.CSharp { } public VariableInfo VariableInfo { - get { return local_info.VariableInfo; } + get { + return local_info.VariableInfo; + } } public bool IsReadOnly { @@ -3675,73 +3623,73 @@ namespace Mono.CSharp { } } - protected void DoResolveBase (EmitContext ec) + protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side) { if (local_info == null) { local_info = Block.GetLocalInfo (Name); + + // is out param + if (lvalue_right_side == EmptyExpression.Null) + local_info.Used = true; + is_readonly = local_info.ReadOnly; } type = local_info.VariableType; -#if false - if (ec.InAnonymousMethod) - Block.LiftVariable (local_info); -#endif + + VariableInfo variable_info = local_info.VariableInfo; + if (lvalue_right_side != null){ + if (is_readonly){ + Error (1604, "cannot assign to `" + Name + "' because it is readonly"); + return null; + } + + if (variable_info != null) + variable_info.SetAssigned (ec); } - protected Expression DoResolve (EmitContext ec, bool is_lvalue) - { Expression e = Block.GetConstantExpression (Name); if (e != null) { local_info.Used = true; eclass = ExprClass.Value; - return e; + return e.Resolve (ec); } - VariableInfo variable_info = local_info.VariableInfo; if ((variable_info != null) && !variable_info.IsAssigned (ec, loc)) return null; - if (!is_lvalue) + if (lvalue_right_side == null) local_info.Used = true; - if (local_info.LocalBuilder == null) - return ec.RemapLocal (local_info); + 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){ + if (local_info.AddressTaken){ + AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc); + return null; + } + ec.CaptureVariable (local_info); + } + } return this; } public override Expression DoResolve (EmitContext ec) { - DoResolveBase (ec); - - return DoResolve (ec, false); + return DoResolveBase (ec, null); } override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { - DoResolveBase (ec); - - VariableInfo variable_info = local_info.VariableInfo; - if (variable_info != null) - variable_info.SetAssigned (ec); - - Expression e = DoResolve (ec, true); - - if (e == null) - return null; - - if (is_readonly){ - Error (1604, "cannot assign to `" + Name + "' because it is readonly"); - return null; - } + Expression ret = DoResolveBase (ec, right_side); + if (ret != null) + CheckObsoleteAttribute (ret.Type); - CheckObsoleteAttribute (e.Type); - - if (local_info.LocalBuilder == null) - return ec.RemapLocalLValue (local_info, right_side); - - return this; + return ret; } public bool VerifyFixed (bool is_expression) @@ -3753,25 +3701,89 @@ namespace Mono.CSharp { { 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) + 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); - ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); + 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); - } - - public override string ToString () + } else { + // + // A local variable captured by anonymous methods or iterators + // + ec.EmitCapturedVariableInstance (local_info); + ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder); + } + } + + public override string ToString () { return String.Format ("{0} ({1}:{2})", GetType (), Name, loc); } @@ -3788,7 +3800,21 @@ namespace Mono.CSharp { Block block; VariableInfo vi; public Parameter.Modifier mod; - public bool is_ref, is_out; + public bool is_ref, is_out, prepared; + + public bool IsOut { + get { + return is_out; + } + } + + public bool IsRef { + get { + return is_ref; + } + } + + LocalTemporary temp; public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc) { @@ -3811,8 +3837,7 @@ namespace Mono.CSharp { public bool IsAssigned (EmitContext ec, Location loc) { - if (!ec.DoFlowAnalysis || !is_out || - ec.CurrentBranching.IsAssigned (vi)) + if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi)) return true; Report.Error (165, loc, @@ -3822,8 +3847,7 @@ namespace Mono.CSharp { public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc) { - if (!ec.DoFlowAnalysis || !is_out || - ec.CurrentBranching.IsFieldAssigned (vi, field_name)) + if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name)) return true; Report.Error (170, loc, @@ -3845,13 +3869,30 @@ namespace Mono.CSharp { protected void DoResolveBase (EmitContext ec) { - type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod); + type = pars.GetParameterInfo (ec, idx, out mod); is_ref = (mod & Parameter.Modifier.ISBYREF) != 0; is_out = (mod & Parameter.Modifier.OUT) != 0; eclass = ExprClass.Variable; if (is_out) vi = block.ParameterMap [idx]; + + if (ec.CurrentAnonymousMethod != null){ + if (is_ref){ + Report.Error (1628, Location, + "Can not reference a ref or out parameter in an anonymous method"); + 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)){ + ec.CaptureParameter (name, type, idx); + } + } } // @@ -3920,12 +3961,25 @@ namespace Mono.CSharp { arg_idx++; EmitLdArg (ig, arg_idx); + + // + // FIXME: Review for anonymous methods + // } public override void Emit (EmitContext ec) { - ILGenerator ig = ec.ig; + if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ + ec.EmitParameter (name); + return; + } + Emit (ec, false); + } + + public void Emit (EmitContext ec, bool leave_copy) + { + ILGenerator ig = ec.ig; int arg_idx = idx; if (!ec.IsStatic) @@ -3933,33 +3987,61 @@ namespace Mono.CSharp { EmitLdArg (ig, arg_idx); - if (!is_ref) - return; - - // - // If we are a reference, we loaded on the stack a pointer - // Now lets load the real value - // - LoadFromPtr (ig, type); + 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) + + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { + if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ + ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load); + return; + } + ILGenerator ig = ec.ig; - int arg_idx = idx; - + + prepared = prepare_for_load; + if (!ec.IsStatic) arg_idx++; - if (is_ref) + if (is_ref && !prepared) EmitLdArg (ig, arg_idx); source.Emit (ec); - if (is_ref) + 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); - else { + + if (temp != null) + temp.Emit (ec); + } else { if (arg_idx <= 255) ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else @@ -3969,6 +4051,11 @@ namespace Mono.CSharp { public void AddressOf (EmitContext ec, AddressOp mode) { + if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){ + ec.EmitAddressOfParameter (name); + return; + } + int arg_idx = idx; if (!ec.IsStatic) @@ -4009,6 +4096,12 @@ namespace Mono.CSharp { this.ArgType = type; } + public Argument (Expression expr) + { + this.Expr = expr; + this.ArgType = AType.Expression; + } + public Type Type { get { if (ArgType == AType.Ref || ArgType == AType.Out) @@ -4064,9 +4157,19 @@ namespace Mono.CSharp { if (Expr == null) 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.ResolveLValue (ec, Expr); } else if (ArgType == AType.Out) - Expr = Expr.ResolveLValue (ec, new EmptyExpression ()); + Expr = Expr.ResolveLValue (ec, EmptyExpression.Null); else Expr = Expr.Resolve (ec); @@ -4086,8 +4189,9 @@ namespace Mono.CSharp { if (instance.GetType () != typeof (This)){ if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){ - Report.Error (197, loc, - "Can not pass a type that derives from MarshalByRefObject with out or ref"); + 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); return false; } } @@ -4132,7 +4236,7 @@ namespace Mono.CSharp { if (Expr is ParameterReference){ ParameterReference pr = (ParameterReference) Expr; - if (pr.is_ref) + if (pr.IsRef) pr.EmitLoad (ec); else { @@ -4154,7 +4258,6 @@ namespace Mono.CSharp { Expression expr; MethodBase method = null; - bool is_base; static Hashtable method_parameter_cache; @@ -4211,172 +4314,103 @@ namespace Mono.CSharp { /// /// Determines "better conversion" as specified in 7.4.2.3 /// - /// Returns : 1 if a->p is better - /// 0 if a->q or neither is better + /// Returns : p if a->p is better, + /// q if a->q is better, + /// null if neither is better /// - static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) + static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) { - Type argument_type = a.Type; + Type argument_type = TypeManager.TypeToCoreType (a.Type); Expression argument_expr = a.Expr; + // p = TypeManager.TypeToCoreType (p); + // q = TypeManager.TypeToCoreType (q); + if (argument_type == null) throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); + if (p == null || q == null) + throw new InternalErrorException ("BetterConversion Got a null conversion"); + + if (p == q) + return null; + + if (argument_expr is NullLiteral) { // - // This is a special case since csc behaves this way. + // If the argument is null and one of the types to compare is 'object' and + // the other is a reference type, we prefer the other. // - if (argument_expr is NullLiteral && - p == TypeManager.string_type && - q == TypeManager.object_type) - return 1; - else if (argument_expr is NullLiteral && - p == TypeManager.object_type && - q == TypeManager.string_type) - return 0; - - // - // csc behaves this way so we emulate it. Basically, if the argument - // is null and one of the types to compare is 'object' and the other - // is a reference type, we prefer the other. - // - // I can't find this anywhere in the spec but we can interpret this - // to mean that null can be of any type you wish in such a context - // - if (p != null && q != null) { - if (argument_expr is NullLiteral && - !p.IsValueType && - q == TypeManager.object_type) - return 1; - else if (argument_expr is NullLiteral && - !q.IsValueType && - p == TypeManager.object_type) - return 0; - } - - if (p == q) - return 0; + // This follows from the usual rules: + // * There is an implicit conversion from 'null' to type 'object' + // * There is an implicit conversion from 'null' to any reference type + // * There is an implicit conversion from any reference type to type 'object' + // * There is no implicit conversion from type 'object' to other reference types + // => Conversion of 'null' to a reference type is better than conversion to 'object' + // + // FIXME: This probably isn't necessary, since the type of a NullLiteral is the + // null type. I think it used to be 'object' and thus needed a special + // case to avoid the immediately following two checks. + // + if (!p.IsValueType && q == TypeManager.object_type) + return p; + if (!q.IsValueType && p == TypeManager.object_type) + return q; + } if (argument_type == p) - return 1; + return p; if (argument_type == q) - return 0; - - // - // Now probe whether an implicit constant expression conversion - // can be used. - // - // An implicit constant expression conversion permits the following - // conversions: - // - // * A constant-expression of type `int' can be converted to type - // sbyte, byute, short, ushort, uint, ulong provided the value of - // of the expression is withing the range of the destination type. - // - // * A constant-expression of type long can be converted to type - // ulong, provided the value of the constant expression is not negative - // - // FIXME: Note that this assumes that constant folding has - // taken place. We dont do constant folding yet. - // - - if (argument_expr is IntConstant){ - IntConstant ei = (IntConstant) argument_expr; - int value = ei.Value; - - if (p == TypeManager.sbyte_type){ - if (value >= SByte.MinValue && value <= SByte.MaxValue) - return 1; - } else if (p == TypeManager.byte_type){ - if (q == TypeManager.sbyte_type && - value >= SByte.MinValue && value <= SByte.MaxValue) - return 0; - else if (Byte.MinValue >= 0 && value <= Byte.MaxValue) - return 1; - } else if (p == TypeManager.short_type){ - if (value >= Int16.MinValue && value <= Int16.MaxValue) - return 1; - } else if (p == TypeManager.ushort_type){ - if (q == TypeManager.short_type && - value >= Int16.MinValue && value <= Int16.MaxValue) - return 0; - else if (value >= UInt16.MinValue && value <= UInt16.MaxValue) - return 1; - } else if (p == TypeManager.int32_type){ - if (value >= Int32.MinValue && value <= Int32.MaxValue) - return 1; - } else if (p == TypeManager.uint32_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint32 - // - if (value >= 0) - return 1; - } else if (p == TypeManager.uint64_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint64 - // - - // - // This special case is needed because csc behaves like this. - // int -> uint is better than int -> ulong! - // - if (q == TypeManager.uint32_type) - return 0; - - if (q == TypeManager.int64_type) - return 0; - else if (value >= 0) - return 1; - } else if (p == TypeManager.int64_type){ - return 1; - } - } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){ - LongConstant lc = (LongConstant) argument_expr; - - if (p == TypeManager.uint64_type){ - if (lc.Value > 0) - return 1; - } - } - - if (q == null) { - Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc); - - if (tmp != null) - return 1; - else - return 0; - } + return q; Expression p_tmp = new EmptyExpression (p); Expression q_tmp = new EmptyExpression (q); - if (Convert.ImplicitConversionExists (ec, p_tmp, q) == true && - Convert.ImplicitConversionExists (ec, q_tmp, p) == false) - return 1; + bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q); + bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p); + + if (p_to_q && !q_to_p) + return p; + + if (q_to_p && !p_to_q) + return q; if (p == TypeManager.sbyte_type) if (q == TypeManager.byte_type || q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) - return 1; + return p; + if (q == TypeManager.sbyte_type) + if (p == TypeManager.byte_type || p == TypeManager.ushort_type || + p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return q; if (p == TypeManager.short_type) if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || q == TypeManager.uint64_type) - return 1; + return p; + + if (q == TypeManager.short_type) + if (p == TypeManager.ushort_type || p == TypeManager.uint32_type || + p == TypeManager.uint64_type) + return q; if (p == TypeManager.int32_type) if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) - return 1; + return p; + + if (q == TypeManager.int32_type) + if (p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return q; if (p == TypeManager.int64_type) if (q == TypeManager.uint64_type) - return 1; + return p; + if (q == TypeManager.int64_type) + if (p == TypeManager.uint64_type) + return q; - return 0; + return null; } /// @@ -4384,24 +4418,17 @@ namespace Mono.CSharp { /// and the current best match /// /// - /// Returns an integer indicating : - /// 0 if candidate ain't better - /// 1 if candidate is better than the current best match + /// Returns a boolean indicating : + /// false if candidate ain't better + /// true if candidate is better than the current best match /// - static int BetterFunction (EmitContext ec, ArrayList args, + 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, Location loc) { ParameterData candidate_pd = GetParameterData (candidate); - ParameterData best_pd; - int argument_count; + ParameterData best_pd = GetParameterData (best); - if (args == null) - argument_count = 0; - else - argument_count = args.Count; - int cand_count = candidate_pd.Count; // @@ -4426,52 +4453,21 @@ namespace Mono.CSharp { // Trim (); is better than Trim (params char[] chars); // if (cand_count == 0 && argument_count == 0) - return best == null || best_params ? 1 : 0; + return !candidate_params && best_params; if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) && (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST)) if (cand_count != argument_count) - return 0; - - if (best == null) { - int x = 0; - - if (argument_count == 0 && cand_count == 1 && - candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS) - return 1; - - for (int j = 0; j < argument_count; ++j) { - - Argument a = (Argument) args [j]; - Type t = candidate_pd.ParameterType (j); - - if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) - if (candidate_params) - t = TypeManager.GetElementType (t); - - x = BetterConversion (ec, a, t, null, loc); - - if (x <= 0) - break; - } - - if (x > 0) - return 1; - else - return 0; - } + return false; - best_pd = GetParameterData (best); + bool better_at_least_one = false; + bool is_equal = true; - int rating1 = 0, rating2 = 0; - for (int j = 0; j < argument_count; ++j) { - int x, y; - Argument a = (Argument) args [j]; - Type ct = candidate_pd.ParameterType (j); - Type bt = best_pd.ParameterType (j); + Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j)); + Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j)); if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) if (candidate_params) @@ -4481,14 +4477,19 @@ namespace Mono.CSharp { if (best_params) bt = TypeManager.GetElementType (bt); - x = BetterConversion (ec, a, ct, bt, loc); - y = BetterConversion (ec, a, bt, ct, loc); + if (!ct.Equals (bt)) + is_equal = false; - if (x < y) - return 0; + Type better = BetterConversion (ec, a, ct, bt, loc); + // for each argument, the conversion to 'ct' should be no worse than + // the conversion to 'bt'. + if (better == bt) + return false; - rating1 += x; - rating2 += y; + // for at least one argument, the conversion to 'ct' should be better than + // the conversion to 'bt'. + if (better == ct) + better_at_least_one = true; } // @@ -4499,12 +4500,20 @@ namespace Mono.CSharp { // force it to select the candidate // if (!candidate_params && best_params && cand_count == argument_count) - return 1; + return true; - if (rating1 > rating2) - return 1; - else - return 0; + // + // If two methods have equal parameter types, but + // only one of them is generic, the non-generic one wins. + // + if (is_equal) { + if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate)) + return true; + else if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate)) + return false; + } + + return better_at_least_one; } public static string FullMethodDesc (MethodBase mb) @@ -4586,14 +4595,27 @@ namespace Mono.CSharp { } static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me, - ArrayList arguments, bool do_varargs, + ArrayList arguments, int arg_count, ref MethodBase candidate) + { + return IsParamsMethodApplicable ( + ec, me, arguments, arg_count, false, ref candidate) || + IsParamsMethodApplicable ( + ec, me, arguments, arg_count, true, ref candidate); + + + } + + static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me, + ArrayList arguments, int arg_count, + bool do_varargs, ref MethodBase candidate) { if (!me.HasTypeArguments && !InferParamsTypeArguments (ec, arguments, ref candidate)) return false; - return IsParamsMethodApplicable (ec, arguments, candidate, do_varargs); + return IsParamsMethodApplicable ( + ec, arguments, arg_count, candidate, do_varargs); } /// @@ -4601,15 +4623,9 @@ namespace Mono.CSharp { /// in its expanded form to the given set of arguments /// static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, - MethodBase candidate, bool do_varargs) + int arg_count, MethodBase candidate, + bool do_varargs) { - int arg_count; - - if (arguments == null) - arg_count = 0; - else - arg_count = arguments.Count; - ParameterData pd = GetParameterData (candidate); int pd_count = pd.Count; @@ -4644,9 +4660,9 @@ namespace Mono.CSharp { Argument a = (Argument) arguments [i]; Parameter.Modifier a_mod = a.GetParameterModifier () & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF))); Parameter.Modifier p_mod = pd.ParameterModifier (i) & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF))); if (a_mod == p_mod) { @@ -4691,29 +4707,23 @@ namespace Mono.CSharp { } static bool IsApplicable (EmitContext ec, MethodGroupExpr me, - ArrayList arguments, ref MethodBase candidate) + ArrayList arguments, int arg_count, + ref MethodBase candidate) { if (!me.HasTypeArguments && !InferTypeArguments (ec, arguments, ref candidate)) return false; - return IsApplicable (ec, arguments, candidate); + return IsApplicable (ec, arguments, arg_count, candidate); } /// /// Determines if the candidate method is applicable (section 14.4.2.1) /// to the given set of arguments /// - static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate) + static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count, + MethodBase candidate) { - int arg_count; - - if (arguments == null) - arg_count = 0; - else - arg_count = arguments.Count; - - ParameterData pd = GetParameterData (candidate); if (arg_count != pd.Count) @@ -4725,9 +4735,9 @@ namespace Mono.CSharp { Argument a = (Argument) arguments [i]; Parameter.Modifier a_mod = a.GetParameterModifier () & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); Parameter.Modifier p_mod = pd.ParameterModifier (i) & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); if (a_mod == p_mod || @@ -4755,6 +4765,13 @@ namespace Mono.CSharp { return true; } + static private bool IsAncestralType (Type first_type, Type second_type) + { + return first_type != second_type && + (second_type.IsSubclassOf (first_type) || + TypeManager.ImplementsInterface (second_type, first_type)); + } + /// /// Find the Applicable Function Members (7.4.2.1) /// @@ -4776,8 +4793,9 @@ namespace Mono.CSharp { Location loc) { MethodBase method = null; + bool method_params = false; Type applicable_type = null; - int argument_count; + int arg_count = 0; ArrayList candidates = new ArrayList (); // @@ -4787,189 +4805,212 @@ namespace Mono.CSharp { // // false is normal form, true is expanded form // - Hashtable candidate_to_form = new PtrHashtable (); + Hashtable candidate_to_form = null; - - // - // First we construct the set of applicable methods - // - // We start at the top of the type hierarchy and - // go down to find applicable methods - // - applicable_type = me.DeclaringType; - - if (me.Name == "Invoke" && TypeManager.IsDelegateType (applicable_type)) { + if (Arguments != null) + arg_count = Arguments.Count; + + if ((me.Name == "Invoke") && + TypeManager.IsDelegateType (me.DeclaringType)) { Error_InvokeOnDelegate (loc); return null; } - bool found_applicable = false; - MethodBase[] methods = me.Methods; - for (int i = 0; i < methods.Length; i++) { + // + // 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 (decl_type != applicable_type && - (applicable_type.IsSubclassOf (decl_type) || - TypeManager.ImplementsInterface (applicable_type, decl_type)) && - found_applicable) + if ((applicable_type != null) && + IsAncestralType (decl_type, applicable_type)) continue; + // // Check if candidate is applicable (section 14.4.2.1) - if (IsApplicable (ec, me, Arguments, ref methods [i])) { - // Candidate is applicable in normal form + // Is candidate applicable in normal form? + // + bool is_applicable = IsApplicable ( + ec, me, Arguments, arg_count, ref methods [i]); + + if (!is_applicable && + (IsParamsMethodApplicable ( + ec, me, Arguments, arg_count, ref methods [i]))) { MethodBase candidate = methods [i]; - candidates.Add (candidate); - applicable_type = candidate.DeclaringType; - found_applicable = true; - candidate_to_form [candidate] = false; - } else if (IsParamsMethodApplicable ( - ec, me, Arguments,false, ref methods [i])) { - // Candidate is applicable in expanded form - MethodBase candidate = methods [i]; - candidates.Add (candidate); - applicable_type = candidate.DeclaringType; - found_applicable = true; - candidate_to_form [candidate] = true; - } else if (IsParamsMethodApplicable ( - ec, me, Arguments,true, ref methods [i])) { + if (candidate_to_form == null) + candidate_to_form = new PtrHashtable (); + candidate_to_form [candidate] = candidate; // Candidate is applicable in expanded form - MethodBase candidate = methods [i]; - candidates.Add (candidate); - applicable_type = candidate.DeclaringType; - found_applicable = true; - candidate_to_form [candidate] = true; + is_applicable = true; } - } - if (Arguments == null) - argument_count = 0; - else - argument_count = Arguments.Count; - - // - // Now we actually find the best method - // - int candidate_top = candidates.Count; - for (int ix = 0; ix < candidate_top; ix++){ - MethodBase candidate = (MethodBase) candidates [ix]; - - bool cand_params = (bool) candidate_to_form [candidate]; - bool method_params = false; - - if (method != null) - method_params = (bool) candidate_to_form [method]; - - int x = BetterFunction (ec, Arguments, - candidate, cand_params, - method, method_params, - loc); - if (x == 0) + if (!is_applicable) continue; - - method = candidate; - } - if (method == null) { - int errors = Report.Errors; + candidates.Add (methods [i]); + + if (applicable_type == null) + applicable_type = decl_type; + else if (applicable_type != decl_type) { + is_sorted = false; + if (IsAncestralType (applicable_type, decl_type)) + applicable_type = decl_type; + } + } + + int candidate_top = candidates.Count; + if (candidate_top == 0) { // // Okay so we have failed to find anything so we // return by providing info about the closest match // for (int i = 0; i < methods.Length; ++i) { - - MethodBase c = methods [i]; - if (c == null) - continue; - + MethodBase c = (MethodBase) methods [i]; ParameterData pd = GetParameterData (c); - if (pd.Count != argument_count) + + if (pd.Count != arg_count) continue; if (!InferTypeArguments (ec, Arguments, ref c)) continue; - VerifyArgumentsCompat (ec, Arguments, argument_count, - c, false, null, loc); + VerifyArgumentsCompat (ec, Arguments, arg_count, + c, false, null, may_fail, loc); break; } - if (Report.Errors > errors) - return null; - - string report_name = me.Name; - if (report_name == ".ctor") - report_name = me.DeclaringType.ToString (); + if (!may_fail) { + string report_name = me.Name; + if (report_name == ".ctor") + report_name = me.DeclaringType.ToString (); - for (int i = 0; i < methods.Length; ++i) { + for (int i = 0; i < methods.Length; ++i) { + MethodBase c = methods [i]; + ParameterData pd = GetParameterData (c); - MethodBase c = methods [i]; - if (c == null) - continue; + if (pd.Count != arg_count) + continue; - ParameterData pd = GetParameterData (c); - if (pd.Count != argument_count) - continue; + if (InferTypeArguments (ec, Arguments, ref c)) + continue; - if (InferTypeArguments (ec, Arguments, ref c)) - continue; + Report.Error ( + 411, loc, "The type arguments for " + + "method `{0}' cannot be infered from " + + "the usage. Try specifying the type " + + "arguments explicitly.", report_name); + return null; + } - Report.Error (411, loc, "The type arguments for " + - "method `{0}' cannot be infered from " + - "the usage. Try specifying the type " + - "arguments explicitly.", report_name); - break; + Error_WrongNumArguments ( + loc, report_name, arg_count); + return null; } - if (!may_fail && (errors == Report.Errors)) - Error_WrongNumArguments (loc, report_name, - argument_count); - return null; } + if (!is_sorted) { + // + // At this point, applicable_type is _one_ of the most derived types + // in the set of types containing the methods in this MethodGroup. + // Filter the candidates so that they only contain methods from the + // most derived types. + // + + int finalized = 0; // Number of finalized candidates + + do { + // Invariant: applicable_type is a most derived type + + // We'll try to complete Section 14.5.5.1 for 'applicable_type' by + // eliminating all it's base types. At the same time, we'll also move + // every unrelated type to the end of the array, and pick the next + // 'applicable_type'. + + Type next_applicable_type = null; + int j = finalized; // where to put the next finalized candidate + int k = finalized; // where to put the next undiscarded candidate + for (int i = finalized; i < candidate_top; ++i) { + Type decl_type = ((MethodBase) candidates[i]).DeclaringType; + + if (decl_type == applicable_type) { + candidates[k++] = candidates[j]; + candidates[j++] = candidates[i]; + continue; + } + + if (IsAncestralType (decl_type, applicable_type)) + continue; + + if (next_applicable_type != null && + IsAncestralType (decl_type, next_applicable_type)) + continue; + + candidates[k++] = candidates[i]; + + if (next_applicable_type == null || + IsAncestralType (next_applicable_type, decl_type)) + next_applicable_type = decl_type; + } + + applicable_type = next_applicable_type; + finalized = j; + candidate_top = k; + } while (applicable_type != null); + } + + // + // Now we actually find the best method + // + + method = (MethodBase) candidates[0]; + method_params = candidate_to_form != null && candidate_to_form.Contains (method); + for (int ix = 1; ix < candidate_top; ix++){ + MethodBase candidate = (MethodBase) candidates [ix]; + bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate); + + if (BetterFunction (ec, Arguments, arg_count, + candidate, cand_params, + method, method_params, loc)) { + method = candidate; + method_params = cand_params; + } + } + // // Now check that there are no ambiguities i.e the selected method // should be better than all the others // - bool best_params = (bool) candidate_to_form [method]; - + bool ambiguous = false; for (int ix = 0; ix < candidate_top; ix++){ MethodBase candidate = (MethodBase) candidates [ix]; if (candidate == method) continue; - - // - // If a normal method is applicable in - // the sense that it has the same - // number of arguments, then the - // expanded params method is never - // applicable so we debar the params - // method. - // - // if ((IsParamsMethodApplicable (ec, Arguments, candidate) && -// IsApplicable (ec, Arguments, method))) -// continue; - - bool cand_params = (bool) candidate_to_form [candidate]; - int x = BetterFunction (ec, Arguments, - method, best_params, - candidate, cand_params, - loc); - - if (x != 1) { - Report.Error ( - 121, loc, - "Ambiguous call when selecting function due to implicit casts"); - return null; - } + + 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)) { + Report.SymbolRelatedToPreviousError (candidate); + ambiguous = true; + } + } + + if (ambiguous) { + Report.SymbolRelatedToPreviousError (method); + Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts"); + return null; } // @@ -4978,8 +5019,8 @@ namespace Mono.CSharp { // necessary etc. and return if everything is // all right // - if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method, - best_params, null, loc)) + if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method, + method_params, null, may_fail, loc)) return null; return method; @@ -5016,16 +5057,15 @@ namespace Mono.CSharp { } public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments, - int argument_count, - MethodBase method, + int arg_count, MethodBase method, bool chose_params_expanded, - Type delegate_type, + Type delegate_type, bool may_fail, Location loc) { ParameterData pd = GetParameterData (method); int pd_count = pd.Count; - for (int j = 0; j < argument_count; j++) { + for (int j = 0; j < arg_count; j++) { Argument a = (Argument) Arguments [j]; Expression a_expr = a.Expr; Type parameter_type = pd.ParameterType (j); @@ -5033,7 +5073,7 @@ namespace Mono.CSharp { if (pm == Parameter.Modifier.PARAMS){ if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) { - if (!Location.IsNull (loc)) + if (!may_fail) Error_InvalidArguments ( loc, j, method, delegate_type, Argument.FullDesc (a), pd.ParameterDesc (j)); @@ -5049,7 +5089,7 @@ namespace Mono.CSharp { // Check modifiers // if (pd.ParameterModifier (j) != a.GetParameterModifier ()){ - if (!Location.IsNull (loc)) + if (!may_fail) Error_InvalidArguments ( loc, j, method, delegate_type, Argument.FullDesc (a), pd.ParameterDesc (j)); @@ -5060,13 +5100,13 @@ namespace Mono.CSharp { // // Check Type // - if (a.Type != parameter_type){ + if (!TypeManager.IsEqual (a.Type, parameter_type)){ Expression conv; - + conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc); if (conv == null) { - if (!Location.IsNull (loc)) + if (!may_fail) Error_InvalidArguments ( loc, j, method, delegate_type, Argument.FullDesc (a), pd.ParameterDesc (j)); @@ -5080,14 +5120,21 @@ namespace Mono.CSharp { a.Expr = conv; } + if (parameter_type.IsPointer){ + if (!ec.InUnsafe){ + UnsafeError (loc); + return false; + } + } + Parameter.Modifier a_mod = a.GetParameterModifier () & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); Parameter.Modifier p_mod = pd.ParameterModifier (j) & - ~(Parameter.Modifier.OUT | Parameter.Modifier.REF); + unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)); if (a_mod != p_mod && pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) { - if (!Location.IsNull (loc)) { + if (!may_fail) { Report.Error (1502, loc, "The best overloaded match for method '" + FullMethodDesc (method)+ "' has some invalid arguments"); @@ -5104,9 +5151,9 @@ namespace Mono.CSharp { return true; } - static bool InferType (Type pt, Type at, ref Type[] infered) + static bool InferType (Type pt, Type at, Type[] infered) { - if (pt.IsGenericParameter) { + if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) { int pos = pt.GenericParameterPosition; if (infered [pos] == null) { @@ -5114,7 +5161,7 @@ namespace Mono.CSharp { while (check.IsArray) check = check.GetElementType (); - if (pt.Equals (check)) + if (pt == check) return false; infered [pos] = at; @@ -5127,16 +5174,19 @@ namespace Mono.CSharp { return true; } - if (!pt.ContainsGenericParameters) - return true; + if (!pt.ContainsGenericParameters) { + if (at.ContainsGenericParameters) + return InferType (at, pt, infered); + else + return true; + } if (at.IsArray) { if (!pt.IsArray || (at.GetArrayRank () != pt.GetArrayRank ())) return false; - return InferType (pt.GetElementType (), at.GetElementType (), - ref infered); + return InferType (pt.GetElementType (), at.GetElementType (), infered); } if (pt.IsArray) { @@ -5144,36 +5194,63 @@ namespace Mono.CSharp { (pt.GetArrayRank () != at.GetArrayRank ())) return false; - return InferType (pt.GetElementType (), at.GetElementType (), - ref infered); + return InferType (pt.GetElementType (), at.GetElementType (), infered); } - if (!at.IsGenericInstance) - return false; + if (pt.IsByRef && at.IsByRef) + return InferType (pt.GetElementType (), at.GetElementType (), infered); + ArrayList list = new ArrayList (); + if (at.IsGenericInstance) + list.Add (at); + else { + for (Type bt = at.BaseType; bt != null; bt = bt.BaseType) + list.Add (bt); + + list.AddRange (TypeManager.GetInterfaces (at)); + } + + bool found_one = false; + + foreach (Type type in list) { + if (!type.IsGenericInstance) + continue; + + Type[] infered_types = new Type [infered.Length]; + + if (!InferGenericInstance (pt, type, infered_types)) + continue; + for (int i = 0; i < infered_types.Length; i++) { + if (infered [i] == null) { + infered [i] = infered_types [i]; + continue; + } + + if (infered [i] != infered_types [i]) + return false; + } + + found_one = true; + } + + return found_one; + } + + static bool InferGenericInstance (Type pt, Type at, Type[] infered_types) + { Type[] at_args = at.GetGenericArguments (); Type[] pt_args = pt.GetGenericArguments (); if (at_args.Length != pt_args.Length) return false; - Type[] infered_types = new Type [at_args.Length]; - - for (int i = 0; i < at_args.Length; i++) - if (!InferType (pt_args [i], at_args [i], ref infered_types)) - return false; - - for (int i = 0; i < infered_types.Length; i++) - if (infered_types [i] == null) + for (int i = 0; i < at_args.Length; i++) { + if (!InferType (pt_args [i], at_args [i], infered_types)) return false; + } for (int i = 0; i < infered_types.Length; i++) { - if (infered [i] == null) { - infered [i] = infered_types [i]; - continue; - } - - if (infered [i] != infered_types [i]) + if (infered_types [i] == null) return false; } @@ -5226,7 +5303,7 @@ namespace Mono.CSharp { Type pt = pd.ParameterType (i); Type at = a.Type; - if (!InferType (pt, at, ref infered_types)) + if (!InferType (pt, at, infered_types)) return false; } @@ -5238,7 +5315,7 @@ namespace Mono.CSharp { if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr)) continue; - if (!InferType (element_type, a.Type, ref infered_types)) + if (!InferType (element_type, a.Type, infered_types)) return false; } @@ -5250,15 +5327,16 @@ namespace Mono.CSharp { return true; } - public static bool InferTypeArguments (Type[] param_types, Type[] arg_types, - ref Type[] infered_types) + public static bool InferTypeArguments (Type[] param_types, Type[] arg_types, Type[] infered_types) { + if (infered_types == null) + return false; + for (int i = 0; i < arg_types.Length; i++) { if (arg_types [i] == null) continue; - if (!InferType (param_types [i], arg_types [i], - ref infered_types)) + if (!InferType (param_types [i], arg_types [i], infered_types)) return false; } @@ -5285,7 +5363,18 @@ namespace Mono.CSharp { if (arg_count != pd.Count) return false; - Type[] method_args = method.GetGenericArguments (); + Type[] method_args = method.GetGenericArguments (); + + bool is_open = false; + for (int i = 0; i < method_args.Length; i++) { + if (method_args [i].IsGenericParameter) { + is_open = true; + break; + } + } + if (!is_open) + return true; + Type[] infered_types = new Type [method_args.Length]; Type[] param_types = new Type [pd.Count]; @@ -5301,7 +5390,7 @@ namespace Mono.CSharp { arg_types [i] = a.Type; } - if (!InferTypeArguments (param_types, arg_types, ref infered_types)) + if (!InferTypeArguments (param_types, arg_types, infered_types)) return false; method = method.BindGenericParameters (infered_types); @@ -5329,7 +5418,7 @@ namespace Mono.CSharp { arg_types [i] = apd.ParameterType (i); } - if (!InferTypeArguments (param_types, arg_types, ref infered_types)) + if (!InferTypeArguments (param_types, arg_types, infered_types)) return false; method = method.BindGenericParameters (infered_types); @@ -5342,9 +5431,6 @@ namespace Mono.CSharp { // First, resolve the expression that is used to // trigger the invocation // - if (expr is BaseAccess) - is_base = true; - if (expr is ConstructedType) expr = ((ConstructedType) expr).GetSimpleName (ec); @@ -5364,7 +5450,7 @@ namespace Mono.CSharp { } if (!(expr is MethodGroupExpr)){ - expr.Error_UnexpectedKind (ResolveFlags.MethodGroup); + expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc); return null; } @@ -5413,17 +5499,30 @@ namespace Mono.CSharp { // // Only base will allow this invocation to happen. // - if (is_base && method.IsAbstract){ + if (mg.IsBase && method.IsAbstract){ Report.Error (205, loc, "Cannot call an abstract base member: " + FullMethodDesc (method)); return null; } + if (method.Name == "Finalize" && Arguments == null) { + 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.IsSpecialMethod (method)) - Report.Error (571, loc, method.Name + ": can not call operator or accessor"); + 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 (mg.InstanceExpression != null) + mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType); + eclass = ExprClass.Value; return this; } @@ -5470,14 +5569,24 @@ namespace Mono.CSharp { /// emission of the arguments is known not to contain /// a `params' field (for example in constructors or other routines /// that keep their arguments in this structure) + /// + /// if `dup_args' is true, a copy of the arguments will be left + /// on the stack. If `dup_args' is true, you can specify `this_arg' + /// which will be duplicated before any other args. Only EmitCall + /// should be using this interface. /// - public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments) + public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg) { ParameterData pd; if (mb != null) pd = GetParameterData (mb); else pd = null; + + LocalTemporary [] temps = null; + + if (dup_args) + temps = new LocalTemporary [arguments.Count]; // // If we are calling a params method with no arguments, special case it @@ -5514,6 +5623,18 @@ namespace Mono.CSharp { } a.Emit (ec); + if (dup_args) { + ec.ig.Emit (OpCodes.Dup); + (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec); + } + } + + if (dup_args) { + if (this_arg != null) + this_arg.Emit (ec); + + for (int i = 0; i < top; i ++) + temps [i].Emit (ec); } if (pd != null && pd.Count > top && @@ -5577,10 +5698,25 @@ namespace Mono.CSharp { public static void EmitCall (EmitContext ec, bool is_base, bool is_static, Expression instance_expr, MethodBase method, ArrayList Arguments, Location loc) + { + EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false); + } + + // `dup_args' leaves an extra copy of the arguments on the stack + // `omit_args' does not leave any arguments at all. + // So, basically, you could make one call with `dup_args' set to true, + // and then another with `omit_args' set to true, and the two calls + // would have the same set of arguments. However, each argument would + // only have been evaluated once. + public static void EmitCall (EmitContext ec, bool is_base, + bool is_static, Expression instance_expr, + MethodBase method, ArrayList Arguments, Location loc, + bool dup_args, bool omit_args) { ILGenerator ig = ec.ig; bool struct_call = false; bool this_call = false; + LocalTemporary this_arg = null; Type decl_type = method.DeclaringType; @@ -5603,79 +5739,93 @@ namespace Mono.CSharp { method = TypeManager.void_array_copyto_array_int; } - // - // This checks ObsoleteAttribute on the method and on the declaring type - // - ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method); - if (oa != null) - AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc); - - oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType); - if (oa != null) { - AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc); - } - + if (ec.TestObsoleteMethodUsage) { + // + // This checks ObsoleteAttribute on the method and on the declaring type + // + ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method); + if (oa != null) + AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc); - oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType); - if (oa != null) { - AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc); + oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType); + if (oa != null) { + AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc); + } } if (IsMethodExcluded (method, ec)) return; if (!is_static){ - if (TypeManager.IsValueType (decl_type)) + this_call = instance_expr == null; + if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType)) struct_call = true; + // // If this is ourselves, push "this" // - if (instance_expr == null){ - this_call = true; - ig.Emit (OpCodes.Ldarg_0); - } else { - Type itype = instance_expr.Type; + if (!omit_args) { + Type t = null; + if (this_call) { + ig.Emit (OpCodes.Ldarg_0); + t = decl_type; + } else { + Type iexpr_type = instance_expr.Type; - // - // Push the instance expression - // - if (TypeManager.IsValueType (itype)){ // - // 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 || itype.IsGenericParameter){ - // - // If the expression implements IMemoryLocation, then - // we can optimize and use AddressOf on the - // return. + // Push the instance expression + // + if (TypeManager.IsValueType (iexpr_type)) { // - // If not we have to use some temporary storage for - // it. - if (instance_expr is IMemoryLocation){ - ((IMemoryLocation)instance_expr). - AddressOf (ec, AddressOp.LoadStore); - } - else { + // 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); + } else { instance_expr.Emit (ec); - LocalBuilder temp = ig.DeclareLocal (itype); - ig.Emit (OpCodes.Stloc, temp); - ig.Emit (OpCodes.Ldloca, temp); + ig.Emit (OpCodes.Box, instance_expr.Type); + t = TypeManager.object_type; } - if (itype.IsGenericParameter) - ig.Emit (OpCodes.Constrained, itype); - else - struct_call = true; } else { instance_expr.Emit (ec); - ig.Emit (OpCodes.Box, itype); - } - } 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); + } } } - EmitArguments (ec, method, Arguments); + if (!omit_args) + EmitArguments (ec, method, Arguments, dup_args, this_arg); + + if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter)) + ig.Emit (OpCodes.Constrained, instance_expr.Type); OpCode call_op; if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) @@ -5695,9 +5845,9 @@ namespace Mono.CSharp { // and DoFoo is not virtual, you can omit the callvirt, // because you don't need the null checking behavior. // - if (method is MethodInfo) + if (method is MethodInfo) ig.Emit (call_op, (MethodInfo) method); - else + else ig.Emit (call_op, (ConstructorInfo) method); } @@ -5705,7 +5855,7 @@ namespace Mono.CSharp { { MethodGroupExpr mg = (MethodGroupExpr) this.expr; - EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc); + EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc); } public override void EmitStatement (EmitContext ec) @@ -5740,9 +5890,9 @@ namespace Mono.CSharp { // // First try to resolve it as a cast. // - type = ec.DeclSpace.ResolveType (expr, true, loc); - if (type != null) { - Cast cast = new Cast (new TypeExpression (type, loc), argument, loc); + TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr; + if ((te != null) && (te.eclass == ExprClass.Type)) { + Cast cast = new Cast (te, argument, loc); return cast.Resolve (ec); } @@ -5787,8 +5937,8 @@ namespace Mono.CSharp { // // First try to resolve it as a cast. // - type = ec.DeclSpace.ResolveType (expr, true, loc); - if (type != null) { + TypeExpr te = expr.ResolveAsTypeStep (ec) as TypeExpr; + if ((te != null) && (te.eclass == ExprClass.Type)) { error201 (); return null; } @@ -5874,7 +6024,7 @@ namespace Mono.CSharp { value_target = value; value_target_set = true; if (!(value_target is IMemoryLocation)){ - Error_UnexpectedKind ("variable"); + Error_UnexpectedKind ("variable", loc); return false; } return true; @@ -5923,8 +6073,11 @@ namespace Mono.CSharp { return this; } - type = ec.DeclSpace.ResolveType (RequestedType, false, loc); + TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec); + if (texpr == null) + return null; + type = texpr.Type; if (type == null) return null; @@ -5935,7 +6088,7 @@ namespace Mono.CSharp { if (IsDelegate){ RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec); if (RequestedType != null) - if (!(RequestedType is NewDelegate)) + if (!(RequestedType is DelegateCreation)) throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ()); return RequestedType; } @@ -5961,11 +6114,18 @@ namespace Mono.CSharp { is_type_parameter = true; eclass = ExprClass.Value; return this; - } else if (type.IsInterface || type.IsAbstract){ + } + + if (type.IsInterface || type.IsAbstract){ Error (144, "It is not possible to create instances of interfaces or abstract classes"); return null; } - + + if (type.IsAbstract && type.IsSealed) { + Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type)); + return null; + } + bool is_struct = type.IsValueType; eclass = ExprClass.Value; @@ -5975,7 +6135,7 @@ 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'. @@ -5987,7 +6147,7 @@ namespace Mono.CSharp { if (! (ml is MethodGroupExpr)){ if (!is_struct){ - ml.Error_UnexpectedKind ("method group"); + ml.Error_UnexpectedKind ("method group", loc); return null; } } @@ -6055,7 +6215,7 @@ namespace Mono.CSharp { // bool DoEmit (EmitContext ec, bool need_value_on_stack) { - bool is_value_type = type.IsValueType; + bool is_value_type = TypeManager.IsValueType (type); ILGenerator ig = ec.ig; if (is_value_type){ @@ -6072,7 +6232,7 @@ namespace Mono.CSharp { } if (method != null) - Invocation.EmitArguments (ec, method, Arguments); + Invocation.EmitArguments (ec, method, Arguments, false, null); if (is_value_type){ if (method == null) @@ -6128,7 +6288,7 @@ namespace Mono.CSharp { IMemoryLocation ml = (IMemoryLocation) value_target; ml.AddressOf (ec, AddressOp.Store); if (method != null) - Invocation.EmitArguments (ec, method, Arguments); + Invocation.EmitArguments (ec, method, Arguments, false, null); if (method == null) ec.ig.Emit (OpCodes.Initobj, type); @@ -6285,7 +6445,7 @@ namespace Mono.CSharp { Expression tmp = (Expression) o; tmp = tmp.Resolve (ec); if (tmp == null) - continue; + return false; // Console.WriteLine ("I got: " + tmp); // Handle initialization from vars, fields etc. @@ -6380,11 +6540,6 @@ namespace Mono.CSharp { } } - void Error_NegativeArrayIndex () - { - Error (284, "Can not create array with a negative size"); - } - // // Converts `source' to an int, uint, long or ulong. // @@ -6415,14 +6570,14 @@ namespace Mono.CSharp { if (target is Constant){ if (target is IntConstant){ if (((IntConstant) target).Value < 0){ - Error_NegativeArrayIndex (); + Expression.Error_NegativeArrayIndex (loc); return null; } } if (target is LongConstant){ if (((LongConstant) target).Value < 0){ - Error_NegativeArrayIndex (); + Expression.Error_NegativeArrayIndex (loc); return null; } } @@ -6453,16 +6608,19 @@ namespace Mono.CSharp { // // Lookup the type // - Expression array_type_expr; + TypeExpr array_type_expr; array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc); - type = ec.DeclSpace.ResolveType (array_type_expr, false, loc); - - if (type == null) + array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec); + if (array_type_expr == null) return false; - underlying_type = type; - if (underlying_type.IsArray) - underlying_type = TypeManager.GetElementType (underlying_type); + type = array_type_expr.Type; + + if (!type.IsArray) { + Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead."); + return false; + } + underlying_type = TypeManager.GetElementType (type); dimensions = type.GetArrayRank (); return true; @@ -6500,6 +6658,11 @@ 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; @@ -6515,7 +6678,7 @@ namespace Mono.CSharp { AllBindingFlags, loc); if (!(ml is MethodGroupExpr)) { - ml.Error_UnexpectedKind ("method group"); + ml.Error_UnexpectedKind ("method group", loc); return null; } @@ -6812,12 +6975,20 @@ namespace Mono.CSharp { e.Emit (ec); - if (dims == 1) - ArrayAccess.EmitStoreOpcode (ig, array_element_type); - else + 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); - - } + } } // @@ -6898,23 +7069,13 @@ namespace Mono.CSharp { if (e is NullLiteral) v = null; else { - if (!Attribute.GetAttributeArgumentExpression (e, Location, out v)) + if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v)) return null; } ret [i++] = v; } return ret; } - - public Expression TurnIntoConstant () - { - // - // Should use something like the above attribute thing. - // It should return a subclass of Constant that just returns - // the computed value of the array - // - throw new Exception ("Does not support yet Turning array into a Constant"); - } } /// @@ -6953,7 +7114,7 @@ namespace Mono.CSharp { eclass = ExprClass.Variable; if (ec.TypeContainer.CurrentType != null) - type = ec.TypeContainer.CurrentType.ResolveType (ec); + type = ec.TypeContainer.CurrentType; else type = ec.ContainerType; @@ -7005,28 +7166,36 @@ namespace Mono.CSharp { return this; } - public override void Emit (EmitContext ec) + public void Emit (EmitContext ec, bool leave_copy) { - ILGenerator ig = ec.ig; - - ec.EmitThis (); - if (ec.TypeContainer is Struct) - ig.Emit (OpCodes.Ldobj, type); + Emit (ec); + if (leave_copy) + ec.ig.Emit (OpCodes.Dup); } - - public void EmitAssign (EmitContext ec, Expression source) + + 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 (); source.Emit (ec); + if (leave_copy) + ec.ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Stobj, type); } else { - source.Emit (ec); - ig.Emit (OpCodes.Starg, 0); + throw new Exception ("how did you get here"); } } + + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + ec.EmitThis (); + if (ec.TypeContainer is Struct) + ig.Emit (OpCodes.Ldobj, type); + } public void AddressOf (EmitContext ec, AddressOp mode) { @@ -7149,7 +7318,7 @@ namespace Mono.CSharp { /// Implements the typeof operator /// public class TypeOf : Expression { - public readonly Expression QueriedType; + public Expression QueriedType; protected Type typearg; public TypeOf (Expression queried_type, Location l) @@ -7160,17 +7329,22 @@ namespace Mono.CSharp { public override Expression DoResolve (EmitContext ec) { - typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc); - - if (typearg == null) + TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec); + if (texpr == null) return null; + 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"); return null; } + if (typearg.IsPointer && !ec.InUnsafe){ + UnsafeError (loc); + return null; + } CheckObsoleteAttribute (typearg); type = TypeManager.type_type; @@ -7225,22 +7399,20 @@ namespace Mono.CSharp { if (!ec.InUnsafe) { Report.Error ( 233, loc, "Sizeof may only be used in an unsafe context " + - "(consider using System.Runtime.InteropServices.Marshal.Sizeof"); + "(consider using System.Runtime.InteropServices.Marshal.SizeOf"); return null; } - QueriedType = ec.DeclSpace.ResolveTypeExpr (QueriedType, false, loc); - if (QueriedType == null || QueriedType.Type == null) + TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec); + if (texpr == null) return null; - if (QueriedType is TypeParameterExpr){ - ((TypeParameterExpr)QueriedType).Error_CannotUseAsUnmanagedType (loc); + if (texpr is TypeParameterExpr){ + ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc); return null; } - type_queried = QueriedType.Type; - if (type_queried == null) - return null; + type_queried = texpr.Type; CheckObsoleteAttribute (type_queried); @@ -7310,6 +7482,8 @@ namespace Mono.CSharp { return RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc) != null; } + // 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) @@ -7335,7 +7509,10 @@ namespace Mono.CSharp { FieldInfo fi = fe.FieldInfo.Mono_GetGenericFieldDefinition (); Type decl_type = fi.DeclaringType; - if (fi is FieldBuilder) { + bool is_emitted = fi is FieldBuilder; + Type t = fi.FieldType; + + if (is_emitted) { Const c = TypeManager.LookupConstant ((FieldBuilder) fi); if (c != null) { @@ -7345,16 +7522,21 @@ namespace Mono.CSharp { object real_value = ((Constant) c.Expr).GetValue (); - return Constantify (real_value, fi.FieldType); + return Constantify (real_value, t); } } + // 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) { - Type t = fi.FieldType; - object o; - if (fi is FieldBuilder) + if (is_emitted) o = TypeManager.GetValue ((FieldBuilder) fi); else o = fi.GetValue (fi); @@ -7391,7 +7573,7 @@ namespace Mono.CSharp { return exp; } - if (fi.FieldType.IsPointer && !ec.InUnsafe){ + if (t.IsPointer && !ec.InUnsafe){ UnsafeError (loc); return null; } @@ -7519,8 +7701,13 @@ namespace Mono.CSharp { if (expr is SimpleName){ SimpleName child_expr = (SimpleName) expr; + string fqname = DeclSpace.MakeFQN (child_expr.Name, Identifier); - Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc); + Expression new_expr; + if (args != null) + new_expr = new ConstructedType (fqname, args, loc); + else + new_expr = new SimpleName (fqname, loc); return new_expr.Resolve (ec, flags); } @@ -7536,10 +7723,10 @@ namespace Mono.CSharp { Type expr_type; if (expr is TypeExpr){ - expr_type = ((TypeExpr) expr).ResolveType (ec); + expr_type = expr.Type; if (!ec.DeclSpace.CheckAccessLevel (expr_type)){ - Report.Error_T (122, loc, expr_type); + Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type); return null; } @@ -7550,7 +7737,12 @@ namespace Mono.CSharp { object value = en.LookupEnumValue (ec, Identifier, loc); if (value != null){ - ObsoleteAttribute oa = en.GetObsoleteAttribute (ec, Identifier); + 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); } @@ -7584,7 +7776,7 @@ namespace Mono.CSharp { member_lookup = MemberLookup ( ec, expr_type, expr_type, Identifier, loc); if ((member_lookup == null) && (args != null)) { - string lookup_id = Identifier + "!" + args.Count; + string lookup_id = MemberName.MakeName (Identifier, args); member_lookup = MemberLookup ( ec, expr_type, expr_type, lookup_id, loc); } @@ -7667,11 +7859,18 @@ namespace Mono.CSharp { else fname = full_expr.Identifier; + fname = MemberName.MakeName (fname, args); + if (full_expr.Expr is SimpleName) { string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname); Type fully_qualified = ec.DeclSpace.FindType (loc, full_name); - if (fully_qualified != null) - return new TypeExpression (fully_qualified, loc); + if (fully_qualified != null) { + if (args == null) + return new TypeExpression (fully_qualified, loc); + + ConstructedType ctype = new ConstructedType (fully_qualified, args, loc); + return ctype.ResolveAsTypeStep (ec); + } } full_expr = full_expr.Expr as MemberAccess; @@ -7684,13 +7883,21 @@ namespace Mono.CSharp { if (new_expr is SimpleName){ SimpleName child_expr = (SimpleName) new_expr; + string fqname = DeclSpace.MakeFQN (child_expr.Name, Identifier); - new_expr = new SimpleName (child_expr.Name, Identifier, loc); + if (args != null) + new_expr = new ConstructedType (fqname, args, loc); + else + new_expr = new SimpleName (fqname, loc); return new_expr.ResolveAsTypeStep (ec); } - Type expr_type = ((TypeExpr) new_expr).ResolveType (ec); + TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (ec); + if (tnew_expr == null) + return null; + + Type expr_type = tnew_expr.Type; if (expr_type.IsPointer){ Error (23, "The `.' operator can not be applied to pointer operands (" + @@ -7700,10 +7907,7 @@ namespace Mono.CSharp { Expression member_lookup; string lookup_id; - if (args != null) - lookup_id = Identifier + "!" + args.Count; - else - lookup_id = Identifier; + lookup_id = MemberName.MakeName (Identifier, args); member_lookup = MemberLookupFinal ( ec, expr_type, expr_type, lookup_id, loc); if (member_lookup == null) @@ -7713,10 +7917,11 @@ namespace Mono.CSharp { if (texpr == null) return null; - Type t = texpr.ResolveType (ec); - if (t == null) + texpr = texpr.ResolveAsTypeTerminal (ec); + if (texpr == null) return null; + TypeArguments the_args = args; if (TypeManager.HasGenericArguments (expr_type)) { Type[] decl_args = TypeManager.GetTypeArguments (expr_type); @@ -7727,11 +7932,11 @@ namespace Mono.CSharp { if (args != null) new_args.Add (args); - args = new_args; + the_args = new_args; } - if (args != null) { - ConstructedType ctype = new ConstructedType (t, args, loc); + if (the_args != null) { + ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc); return ctype.ResolveAsTypeStep (ec); } @@ -7745,10 +7950,7 @@ namespace Mono.CSharp { public override string ToString () { - if (args != null) - return expr + "." + Identifier + "!" + args.Count; - else - return expr + "." + Identifier; + return expr + "." + MemberName.MakeName (Identifier, args); } } @@ -7893,7 +8095,7 @@ namespace Mono.CSharp { return true; } - Expression MakePointerAccess () + Expression MakePointerAccess (EmitContext ec) { Type t = Expr.Type; @@ -7907,8 +8109,10 @@ namespace Mono.CSharp { } Expression p; - p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc); - return new Indirection (p, loc); + p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec); + if (p == null) + return null; + return new Indirection (p, loc).Resolve (ec); } public override Expression DoResolve (EmitContext ec) @@ -7932,7 +8136,7 @@ namespace Mono.CSharp { if (t.IsArray) return (new ArrayAccess (this, loc)).Resolve (ec); else if (t.IsPointer) - return MakePointerAccess (); + return MakePointerAccess (ec); else return (new IndexerAccess (this, loc)).Resolve (ec); } @@ -7946,7 +8150,7 @@ namespace Mono.CSharp { if (t.IsArray) return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side); else if (t.IsPointer) - return MakePointerAccess (); + return MakePointerAccess (ec); else return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side); } @@ -7966,7 +8170,8 @@ namespace Mono.CSharp { // ElementAccess ea; - LocalTemporary [] cached_locations; + LocalTemporary temp; + bool prepared; public ArrayAccess (ElementAccess ea_data, Location l) { @@ -8009,8 +8214,13 @@ namespace Mono.CSharp { if (argtype == TypeManager.int32_type || argtype == TypeManager.uint32_type || argtype == TypeManager.int64_type || - argtype == TypeManager.uint64_type) + 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)"); + } continue; + } // // Mhm. This is strage, because the Argument.Type is not the same as @@ -8067,20 +8277,6 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldelem_Ref); } - /// - /// Emits the right opcode to store an object of Type `t' - /// from an array of T. - /// - static public void EmitStoreOpcode (ILGenerator ig, Type t) - { - bool is_stobj, has_type_arg; - OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); - if (has_type_arg) - ig.Emit (op, t); - else - ig.Emit (op); - } - /// /// Returns the right opcode to store an object of Type `t' /// from an array of T. @@ -8090,7 +8286,7 @@ namespace Mono.CSharp { //Console.WriteLine (new System.Diagnostics.StackTrace ()); has_type_arg = false; is_stobj = false; t = TypeManager.TypeToCoreType (t); - if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type) + if (TypeManager.IsEnumType (t)) t = TypeManager.EnumToUnderlying (t); if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.bool_type) @@ -8177,101 +8373,114 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - if (cached_locations == null){ - ea.Expr.Emit (ec); - foreach (Argument a in ea.Arguments){ - Type argtype = a.Expr.Type; - - a.Expr.Emit (ec); - - if (argtype == TypeManager.int64_type) - ig.Emit (OpCodes.Conv_Ovf_I); - else if (argtype == TypeManager.uint64_type) - ig.Emit (OpCodes.Conv_Ovf_I_Un); - } - return; - } - - if (cached_locations [0] == null){ - cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type); - ea.Expr.Emit (ec); - ig.Emit (OpCodes.Dup); - cached_locations [0].Store (ec); + ea.Expr.Emit (ec); + foreach (Argument a in ea.Arguments){ + Type argtype = a.Expr.Type; - int j = 1; + a.Expr.Emit (ec); - foreach (Argument a in ea.Arguments){ - Type argtype = a.Expr.Type; - - cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */); - a.Expr.Emit (ec); - if (argtype == TypeManager.int64_type) - ig.Emit (OpCodes.Conv_Ovf_I); - else if (argtype == TypeManager.uint64_type) - ig.Emit (OpCodes.Conv_Ovf_I_Un); - - ig.Emit (OpCodes.Dup); - cached_locations [j].Store (ec); - j++; - } - return; + if (argtype == TypeManager.int64_type) + ig.Emit (OpCodes.Conv_Ovf_I); + else if (argtype == TypeManager.uint64_type) + ig.Emit (OpCodes.Conv_Ovf_I_Un); } - - foreach (LocalTemporary lt in cached_locations) - lt.Emit (ec); } - public new void CacheTemporaries (EmitContext ec) - { - cached_locations = new LocalTemporary [ea.Arguments.Count + 1]; - } - - public override void Emit (EmitContext ec) + public void Emit (EmitContext ec, bool leave_copy) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; - LoadArrayAndArguments (ec); - - if (rank == 1) - EmitLoadOpcode (ig, type); - else { - MethodInfo method; + if (!prepared) { + LoadArrayAndArguments (ec); - method = FetchGetMethod (); - ig.Emit (OpCodes.Call, method); + if (rank == 1) + EmitLoadOpcode (ig, type); + else { + MethodInfo method; + + method = FetchGetMethod (); + ig.Emit (OpCodes.Call, method); + } + } else + LoadFromPtr (ec.ig, this.type); + + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temp = new LocalTemporary (ec, this.type); + temp.Store (ec); } } + + public override void Emit (EmitContext ec) + { + Emit (ec, false); + } - public void EmitAssign (EmitContext ec, Expression source) + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; Type t = source.Type; + prepared = prepare_for_load; - LoadArrayAndArguments (ec); - - // - // The stobj opcode used by value types will need - // an address on the stack, not really an array/array - // pair - // - if (rank == 1){ - if (t == TypeManager.enum_type || t == TypeManager.decimal_type || - (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t))) - ig.Emit (OpCodes.Ldelema, t); + if (prepare_for_load) { + AddressOf (ec, AddressOp.LoadStore); + ec.ig.Emit (OpCodes.Dup); + source.Emit (ec); + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temp = new LocalTemporary (ec, this.type); + temp.Store (ec); + } + StoreFromPtr (ec.ig, t); + + if (temp != null) + temp.Emit (ec); + + return; } - source.Emit (ec); + LoadArrayAndArguments (ec); - if (rank == 1) - EmitStoreOpcode (ig, t); - else { + if (rank == 1) { + bool is_stobj, has_type_arg; + OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); + + // + // The stobj opcode used by value types will need + // an address on the stack, not really an array/array + // pair + // + if (is_stobj) + ig.Emit (OpCodes.Ldelema, t); + + source.Emit (ec); + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temp = new LocalTemporary (ec, this.type); + temp.Store (ec); + } + + if (is_stobj) + ig.Emit (OpCodes.Stobj, t); + else if (has_type_arg) + ig.Emit (op, t); + else + ig.Emit (op); + } else { ModuleBuilder mb = CodeGen.Module.Builder; int arg_count = ea.Arguments.Count; Type [] args = new Type [arg_count + 1]; MethodInfo set; + source.Emit (ec); + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temp = new LocalTemporary (ec, this.type); + temp.Store (ec); + } + for (int i = 0; i < arg_count; i++){ //args [i++] = a.Type; args [i] = TypeManager.int32_type; @@ -8287,6 +8496,9 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, set); } + + if (temp != null) + temp.Emit (ec); } public void AddressOf (EmitContext ec, AddressOp mode) @@ -8382,10 +8594,9 @@ namespace Mono.CSharp { if (!lookup_type.IsInterface) return ix; - TypeExpr [] ifaces = TypeManager.GetInterfaces (lookup_type); + Type [] ifaces = TypeManager.GetInterfaces (lookup_type); if (ifaces != null) { - foreach (TypeExpr iface in ifaces) { - Type itype = iface.Type; + foreach (Type itype in ifaces) { MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype); if (mi != null){ if (ix == null) @@ -8505,6 +8716,8 @@ namespace Mono.CSharp { UnsafeError (loc); return null; } + + instance_expr.CheckMarshallByRefAccess (ec.ContainerType); eclass = ExprClass.IndexerAccess; return this; @@ -8575,23 +8788,59 @@ namespace Mono.CSharp { } } + instance_expr.CheckMarshallByRefAccess (ec.ContainerType); + eclass = ExprClass.IndexerAccess; return this; } - public override void Emit (EmitContext ec) + bool prepared = false; + LocalTemporary temp; + + public void Emit (EmitContext ec, bool leave_copy) { - Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc); + 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.Store (ec); + } } - + // // source is ignored, because we already have a copy of it from the // LValue resolution and we have already constructed a pre-cached // version of the arguments (ea.set_arguments); // - public void EmitAssign (EmitContext ec, Expression source) + public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) { - Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc); + prepared = prepare_for_load; + Argument a = (Argument) set_arguments [set_arguments.Count - 1]; + + if (prepared) { + source.Emit (ec); + if (leave_copy) { + ec.ig.Emit (OpCodes.Dup); + temp = new LocalTemporary (ec, Type); + temp.Store (ec); + } + } else if (leave_copy) { + temp = new LocalTemporary (ec, Type); + source.Emit (ec); + temp.Store (ec); + a.Expr = temp; + } + + Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared); + + if (temp != null) + temp.Emit (ec); + } + + + public override void Emit (EmitContext ec) + { + Emit (ec, false); } } @@ -8679,6 +8928,9 @@ namespace Mono.CSharp { pe.IsBase = true; } + if (e is MethodGroupExpr) + ((MethodGroupExpr) e).IsBase = true; + return e; } @@ -8727,6 +8979,9 @@ namespace Mono.CSharp { /// is needed (the `New' class). /// public class EmptyExpression : Expression { + public static readonly EmptyExpression Null = new EmptyExpression (); + + // TODO: should be protected public EmptyExpression () { type = TypeManager.object_type; @@ -8775,6 +9030,12 @@ namespace Mono.CSharp { loc = l; } + public Expression Source { + get { + return source; + } + } + public override Expression DoResolve (EmitContext ec) { // @@ -8814,12 +9075,14 @@ namespace Mono.CSharp { loc = l; } - public override TypeExpr DoResolveAsTypeStep (EmitContext ec) + protected override TypeExpr DoResolveAsTypeStep (EmitContext ec) { - Type ltype = ec.DeclSpace.ResolveType (left, false, loc); - if (ltype == null) + TypeExpr lexpr = left.ResolveAsTypeTerminal (ec); + if (lexpr == null) return null; + Type ltype = lexpr.Type; + if ((ltype == TypeManager.void_type) && (dim != "*")) { Report.Error (1547, Location, "Keyword 'void' cannot be used in this context"); @@ -8869,27 +9132,15 @@ namespace Mono.CSharp { // // For now, fall back to the full lookup in that case. // - TypeExpr texpr = RootContext.LookupType ( - ec.DeclSpace, cname, false, loc); - - if (texpr == null) - return null; - - type = texpr.ResolveType (ec); + type = RootContext.LookupType (ec.DeclSpace, cname, false, loc); if (type == null) return null; } - if (!ec.ResolvingTypeTree){ - // - // If the above flag is set, this is being invoked from the ResolveType function. - // Upper layers take care of the type validity in this context. - // if (!ec.InUnsafe && type.IsPointer){ UnsafeError (loc); return null; } - } eclass = ExprClass.Type; return this; @@ -8998,6 +9249,12 @@ namespace Mono.CSharp { return null; } + Constant c = count as Constant; + if (c != null && c.IsNegative) { + Report.Error (247, loc, "Cannot use a negative size with stackalloc"); + return null; + } + if (ec.CurrentBranching.InCatch () || ec.CurrentBranching.InFinally (true)) { Error (255, @@ -9005,11 +9262,12 @@ namespace Mono.CSharp { return null; } - otype = ec.DeclSpace.ResolveType (t, false, loc); - - if (otype == null) + TypeExpr texpr = t.ResolveAsTypeTerminal (ec); + if (texpr == null) return null; + otype = texpr.Type; + if (!TypeManager.VerifyUnManaged (otype, loc)) return null;