X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=e8e0e6f3b86a32a5505d15ec3cdf75e2060dc7dd;hb=06a1ce9f42b0feb1ee6f56c0010a0ffe89ca3249;hp=d77d41ad8573e6cdd76821cf07bef96dd3c3de05;hpb=ec47bae406de368cb3c5bb57b673e3f6aad1299d;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index d77d41ad857..e8e0e6f3b86 100644 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -5,7 +5,8 @@ // Miguel de Icaza (miguel@ximian.com) // Marek Safar (marek.safar@seznam.cz) // -// (C) 2001, 2002, 2003 Ximian, Inc. +// Copyright 2001, 2002, 2003 Ximian, Inc. +// Copyright 2003-2008 Novell, Inc. // // @@ -96,15 +97,10 @@ namespace Mono.CSharp { void AddressOf (EmitContext ec, AddressOp mode); } - /// - /// This interface is implemented by variables - /// + // TODO: Rename to something meaningful, this is flow-analysis interface only public interface IVariable { - VariableInfo VariableInfo { - get; - } - - bool VerifyFixed (); + VariableInfo VariableInfo { get; } + bool IsFixed { get; } } /// @@ -165,8 +161,7 @@ namespace Mono.CSharp { return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) || TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType); - if (mi.DeclaringType.Assembly == invocation_type.Assembly || - TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) { + if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem) return true; } else { @@ -229,8 +224,16 @@ namespace Mono.CSharp { // This is used if the expression should be resolved as a type or namespace name. // the default implementation fails. // - public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent) + public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent) { + if (!silent) { + Expression e = this; + EmitContext ec = rc as EmitContext; + if (ec != null) + e = e.Resolve (ec); + if (e != null) + e.Error_UnexpectedKind (ResolveFlags.Type, loc); + } return null; } @@ -347,9 +350,9 @@ namespace Mono.CSharp { if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) { #if GMCS_SOURCE - string sig1 = Type.DeclaringMethod == null ? - TypeManager.CSharpName (Type.DeclaringType) : - TypeManager.CSharpSignature (Type.DeclaringMethod); + string sig1 = type.DeclaringMethod == null ? + TypeManager.CSharpName (type.DeclaringType) : + TypeManager.CSharpSignature (type.DeclaringMethod); string sig2 = target.DeclaringMethod == null ? TypeManager.CSharpName (target.DeclaringType) : TypeManager.CSharpSignature (target.DeclaringMethod); @@ -377,7 +380,7 @@ namespace Mono.CSharp { if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null || - (ec != null && Convert.UserDefinedConversion (ec, this, target, Location.Null, true) != null)) + (ec != null && Convert.ExplicitUserConversion (ec, this, target, Location.Null) != null)) { Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " + "An explicit conversion exists (are you missing a cast?)", @@ -385,12 +388,6 @@ namespace Mono.CSharp { return; } - if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) { - Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", - ((Constant)(this)).GetValue ().ToString (), TypeManager.CSharpName (target)); - return; - } - Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'", TypeManager.CSharpName (type), TypeManager.CSharpName (target)); @@ -577,12 +574,25 @@ namespace Mono.CSharp { /// public abstract void Emit (EmitContext ec); + // Emit code to branch to @target if this expression is equivalent to @on_true. + // The default implementation is to emit the value, and then emit a brtrue or brfalse. + // Subclasses can provide more efficient implementations, but those MUST be equivalent, + // including the use of conditional branches. Note also that a branch MUST be emitted public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true) { Emit (ec); ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target); } + // Emit this expression for its side effects, not for its value. + // The default implementation is to emit the value, and then throw it away. + // Subclasses can provide more efficient implementations, but those MUST be equivalent + public virtual void EmitSideEffect (EmitContext ec) + { + Emit (ec); + ec.ig.Emit (OpCodes.Pop); + } + /// /// Protected constructor. Only derivate types should /// be able to be created @@ -893,6 +903,11 @@ namespace Mono.CSharp { throw new NotImplementedException (); } + protected void Error_PointerInsideExpressionTree () + { + Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation"); + } + /// /// Returns an expression that can be used to invoke operator true /// on the expression if it exists. @@ -914,25 +929,20 @@ namespace Mono.CSharp { static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc) { MethodGroupExpr operator_group; - -#if GMCS_SOURCE - if (TypeManager.IsNullableType (e.Type)) - return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec); -#endif - - operator_group = MethodLookup (ec.ContainerType, e.Type, is_true ? "op_True" : "op_False", loc) as MethodGroupExpr; + string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False); + operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr; if (operator_group == null) return null; ArrayList arguments = new ArrayList (1); arguments.Add (new Argument (e, Argument.AType.Expression)); operator_group = operator_group.OverloadResolve ( - ec, arguments, false, loc); + ec, ref arguments, false, loc); if (operator_group == null) return null; - return new StaticCallExpr ((MethodInfo) operator_group, arguments, loc); + return new UserOperatorCall (operator_group, arguments, null, loc); } /// @@ -1084,7 +1094,7 @@ namespace Mono.CSharp { if (t == TypeManager.enum_type) ig.Emit (OpCodes.Ldind_Ref); else - LoadFromPtr (ig, TypeManager.EnumToUnderlying (t)); + LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t)); } else if (t.IsValueType || TypeManager.IsGenericParameter (t)) ig.Emit (OpCodes.Ldobj, t); else if (t.IsPointer) @@ -1099,7 +1109,7 @@ namespace Mono.CSharp { public static void StoreFromPtr (ILGenerator ig, Type type) { if (TypeManager.IsEnumType (type)) - type = TypeManager.EnumToUnderlying (type); + type = TypeManager.GetEnumUnderlyingType (type); if (type == TypeManager.int32_type || type == TypeManager.uint32_type) ig.Emit (OpCodes.Stind_I4); else if (type == TypeManager.int64_type || type == TypeManager.uint64_type) @@ -1236,11 +1246,10 @@ namespace Mono.CSharp { return cloned; } - public virtual Expression CreateExpressionTree (EmitContext ec) - { - throw new NotImplementedException ( - "Expression tree conversion not implemented for " + GetType ()); - } + // + // Implementation of expression to expression tree conversion + // + public abstract Expression CreateExpressionTree (EmitContext ec); protected Expression CreateExpressionFactoryCall (string name, ArrayList args) { @@ -1254,9 +1263,26 @@ namespace Mono.CSharp { public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc) { - return new Invocation ( - new MemberAccess (ExpressionTreeManager.Type, name, typeArguments, loc), - args); + return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args); + } + + protected static TypeExpr CreateExpressionTypeExpression (Location loc) + { + TypeExpr texpr = TypeManager.expression_type_expr; + if (texpr == null) { + Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true); + if (t == null) + return null; + + TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null); + } + + return texpr; + } + + public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + // TODO: It should probably be type = storey.MutateType (type); } } @@ -1289,6 +1315,11 @@ namespace Mono.CSharp { /// Emit that will always leave a value on the stack). /// public abstract void EmitStatement (EmitContext ec); + + public override void EmitSideEffect (EmitContext ec) + { + EmitStatement (ec); + } } /// @@ -1303,30 +1334,28 @@ namespace Mono.CSharp { /// would be "unsigned int". /// /// - public class EmptyCast : Expression + public abstract class TypeCast : Expression { - protected Expression child; + protected readonly Expression child; - protected EmptyCast (Expression child, Type return_type) + protected TypeCast (Expression child, Type return_type) { eclass = child.eclass; loc = child.Location; type = return_type; this.child = child; } - - public static Expression Create (Expression child, Type type) - { - Constant c = child as Constant; - if (c != null) - return new EmptyConstantCast (c, type); - - return new EmptyCast (child, type); - } public override Expression CreateExpressionTree (EmitContext ec) { - return child.CreateExpressionTree (ec); + ArrayList args = new ArrayList (2); + args.Add (new Argument (child.CreateExpressionTree (ec))); + args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); + + if (type.IsPointer || child.Type.IsPointer) + Error_PointerInsideExpressionTree (); + + return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args); } public override Expression DoResolve (EmitContext ec) @@ -1347,18 +1376,55 @@ namespace Mono.CSharp { return child.GetAttributableValue (value_type, out value); } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + child.MutateHoistedGenericType (storey); + } + protected override void CloneTo (CloneContext clonectx, Expression t) { - EmptyCast target = (EmptyCast) t; + // Nothing to clone + } + + public override bool IsNull { + get { return child.IsNull; } + } + } + + public class EmptyCast : TypeCast { + EmptyCast (Expression child, Type target_type) + : base (child, target_type) + { + } + + public static Expression Create (Expression child, Type type) + { + Constant c = child as Constant; + if (c != null) + return new EmptyConstantCast (c, type); + + EmptyCast e = child as EmptyCast; + if (e != null) + return new EmptyCast (e.child, type); + + return new EmptyCast (child, type); + } + + public override void EmitBranchable (EmitContext ec, Label label, bool on_true) + { + child.EmitBranchable (ec, label, on_true); + } - target.child = child.Clone (clonectx); + public override void EmitSideEffect (EmitContext ec) + { + child.EmitSideEffect (ec); } } /// /// Performs a cast using an operator (op_Explicit or op_Implicit) /// - public class OperatorCast : EmptyCast { + public class OperatorCast : TypeCast { MethodInfo conversion_operator; bool find_explicit; @@ -1389,7 +1455,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in mi) { ParameterData pd = TypeManager.GetParameterData (oper); - if (pd.ParameterType (0) == child.Type && oper.ReturnType == type) + if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type) return oper; } @@ -1415,7 +1481,7 @@ namespace Mono.CSharp { /// /// This is a numeric cast to a Decimal /// - public class CastToDecimal : EmptyCast { + public class CastToDecimal : TypeCast { MethodInfo conversion_operator; public CastToDecimal (Expression child) @@ -1444,7 +1510,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in mi) { ParameterData pd = TypeManager.GetParameterData (oper); - if (pd.ParameterType (0) == child.Type && oper.ReturnType == type) + if (pd.ParameterType (0) == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type) return oper; } @@ -1462,7 +1528,7 @@ namespace Mono.CSharp { /// /// This is an explicit numeric cast from a Decimal /// - public class CastFromDecimal : EmptyCast + public class CastFromDecimal : TypeCast { static IDictionary operators; @@ -1487,7 +1553,7 @@ namespace Mono.CSharp { foreach (MethodInfo oper in all_oper) { ParameterData pd = TypeManager.GetParameterData (oper); if (pd.ParameterType (0) == TypeManager.decimal_type) - operators.Add (oper.ReturnType, oper); + operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper); } } @@ -1537,6 +1603,17 @@ namespace Mono.CSharp { return child.ConvertExplicitly (in_checked_context, target_type); } + public override Expression CreateExpressionTree (EmitContext ec) + { + ArrayList args = new ArrayList (2); + args.Add (new Argument (child.CreateExpressionTree (ec))); + args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc))); + if (type.IsPointer) + Error_PointerInsideExpressionTree (); + + return CreateExpressionFactoryCall ("Convert", args); + } + public override Constant Increment () { return child.Increment (); @@ -1556,13 +1633,23 @@ namespace Mono.CSharp { public override bool IsZeroInteger { get { return child.IsZeroInteger; } - } + } public override void Emit (EmitContext ec) { child.Emit (ec); } + public override void EmitBranchable (EmitContext ec, Label label, bool on_true) + { + child.EmitBranchable (ec, label, on_true); + } + + public override void EmitSideEffect (EmitContext ec) + { + child.EmitSideEffect (ec); + } + public override Constant ConvertImplicitly (Type target_type) { // FIXME: Do we need to check user conversions? @@ -1600,6 +1687,16 @@ namespace Mono.CSharp { Child.Emit (ec); } + public override void EmitBranchable (EmitContext ec, Label label, bool on_true) + { + Child.EmitBranchable (ec, label, on_true); + } + + public override void EmitSideEffect (EmitContext ec) + { + Child.EmitSideEffect (ec); + } + public override bool GetAttributableValue (Type value_type, out object value) { value = GetTypedValue (); @@ -1691,7 +1788,7 @@ namespace Mono.CSharp { /// The effect of it is to box the value type emitted by the previous /// operation. /// - public class BoxedCast : EmptyCast { + public class BoxedCast : TypeCast { public BoxedCast (Expression expr, Type target_type) : base (expr, target_type) @@ -1713,9 +1810,20 @@ namespace Mono.CSharp { ec.ig.Emit (OpCodes.Box, child.Type); } + + public override void EmitSideEffect (EmitContext ec) + { + // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType + // so, we need to emit the box+pop instructions in most cases + if (child.Type.IsValueType && + (type == TypeManager.object_type || type == TypeManager.value_type)) + child.EmitSideEffect (ec); + else + base.EmitSideEffect (ec); + } } - public class UnboxCast : EmptyCast { + public class UnboxCast : TypeCast { public UnboxCast (Expression expr, Type return_type) : base (expr, return_type) { @@ -1753,6 +1861,11 @@ namespace Mono.CSharp { LoadFromPtr (ig, t); } } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); + } } /// @@ -1762,7 +1875,7 @@ namespace Mono.CSharp { /// context, so they should generate the conv.ovf opcodes instead of /// conv opcodes. /// - public class ConvCast : EmptyCast { + public class ConvCast : TypeCast { public enum Mode : byte { I1_U1, I1_U2, I1_U4, I1_U8, I1_CH, U1_I1, U1_CH, @@ -1970,25 +2083,13 @@ namespace Mono.CSharp { } } - public class OpcodeCast : EmptyCast { - OpCode op, op2; - bool second_valid; + public class OpcodeCast : TypeCast { + readonly OpCode op; public OpcodeCast (Expression child, Type return_type, OpCode op) : base (child, return_type) - - { - this.op = op; - second_valid = false; - } - - public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2) - : base (child, return_type) - { this.op = op; - this.op2 = op2; - second_valid = true; } public override Expression DoResolve (EmitContext ec) @@ -2003,21 +2104,26 @@ namespace Mono.CSharp { { base.Emit (ec); ec.ig.Emit (op); + } - if (second_valid) - ec.ig.Emit (op2); - } + public Type UnderlyingType { + get { return child.Type; } + } } /// /// This kind of cast is used to encapsulate a child and cast it /// to the class requested /// - public class ClassCast : EmptyCast { + public sealed class ClassCast : TypeCast { + Type child_generic_parameter; + public ClassCast (Expression child, Type return_type) : base (child, return_type) { + if (TypeManager.IsGenericParameter (child.Type)) + child_generic_parameter = child.Type; } public override Expression DoResolve (EmitContext ec) @@ -2032,8 +2138,8 @@ namespace Mono.CSharp { { base.Emit (ec); - if (TypeManager.IsGenericParameter (child.Type)) - ec.ig.Emit (OpCodes.Box, child.Type); + if (child_generic_parameter != null) + ec.ig.Emit (OpCodes.Box, child_generic_parameter); #if GMCS_SOURCE if (type.IsGenericParameter) @@ -2042,38 +2148,192 @@ namespace Mono.CSharp { #endif ec.ig.Emit (OpCodes.Castclass, type); } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + type = storey.MutateType (type); + if (child_generic_parameter != null) + child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter); + + base.MutateHoistedGenericType (storey); + } + } + + // + // Used when resolved expression has different representations for + // expression trees and emit phase + // + public class ReducedExpression : Expression + { + class ReducedConstantExpression : Constant + { + readonly Constant expr; + readonly Expression orig_expr; + + public ReducedConstantExpression (Constant expr, Expression orig_expr) + : base (expr.Location) + { + this.expr = expr; + this.orig_expr = orig_expr; + eclass = expr.eclass; + type = expr.Type; + } + + public override string AsString () + { + return expr.AsString (); + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + return orig_expr.CreateExpressionTree (ec); + } + + public override object GetValue () + { + return expr.GetValue (); + } + + public override Constant ConvertExplicitly (bool in_checked_context, Type target_type) + { + throw new NotImplementedException (); + } + + public override Expression DoResolve (EmitContext ec) + { + return this; + } + + public override Constant Increment () + { + throw new NotImplementedException (); + } + + public override bool IsDefaultValue { + get { + return expr.IsDefaultValue; + } + } + + public override bool IsNegative { + get { + return expr.IsNegative; + } + } + + public override void Emit (EmitContext ec) + { + expr.Emit (ec); + } + } + + readonly Expression expr, orig_expr; + + private ReducedExpression (Expression expr, Expression orig_expr) + { + this.expr = expr; + this.orig_expr = orig_expr; + this.loc = orig_expr.Location; + } + + public static Expression Create (Constant expr, Expression original_expr) + { + return new ReducedConstantExpression (expr, original_expr); + } + + public static Expression Create (Expression expr, Expression original_expr) + { + Constant c = expr as Constant; + if (c != null) + return Create (c, original_expr); + + return new ReducedExpression (expr, original_expr); + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + return orig_expr.CreateExpressionTree (ec); + } + + public override Expression DoResolve (EmitContext ec) + { + eclass = expr.eclass; + type = expr.Type; + return this; + } + + public override void Emit (EmitContext ec) + { + expr.Emit (ec); + } + + public override void EmitBranchable (EmitContext ec, Label target, bool on_true) + { + expr.EmitBranchable (ec, target, on_true); + } + } + + // + // Unresolved type name expressions + // + public abstract class ATypeNameExpression : FullNamedExpression + { + public readonly string Name; + protected TypeArguments targs; + + protected ATypeNameExpression (string name, Location l) + { + Name = name; + loc = l; + } + + protected ATypeNameExpression (string name, TypeArguments targs, Location l) + { + Name = name; + this.targs = targs; + loc = l; + } + + public bool HasTypeArguments { + get { + return targs != null; + } + } + + public override string GetSignatureForError () + { + if (targs != null) { + return TypeManager.RemoveGenericArity (Name) + "<" + + targs.GetSignatureForError () + ">"; + } + + return Name; + } } /// /// SimpleName expressions are formed of a single word and only happen at the beginning /// of a dotted-name. /// - public class SimpleName : Expression { - public readonly string Name; - public readonly TypeArguments Arguments; + public class SimpleName : ATypeNameExpression { bool in_transit; public SimpleName (string name, Location l) + : base (name, l) { - Name = name; - loc = l; } public SimpleName (string name, TypeArguments args, Location l) + : base (name, args, l) { - Name = name; - Arguments = args; - loc = l; } public SimpleName (string name, TypeParameter[] type_params, Location l) + : base (name, l) { - Name = name; - loc = l; - - Arguments = new TypeArguments (l); + targs = new TypeArguments (l); foreach (TypeParameter type_param in type_params) - Arguments.Add (new TypeParameterExpr (type_param, l)); + targs.Add (new TypeParameterExpr (type_param, l)); } public static string RemoveGenericArity (string name) @@ -2106,7 +2366,7 @@ namespace Mono.CSharp { public SimpleName GetMethodGroup () { - return new SimpleName (RemoveGenericArity (Name), Arguments, loc); + return new SimpleName (RemoveGenericArity (Name), targs, loc); } public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name) @@ -2170,7 +2430,7 @@ namespace Mono.CSharp { Type[] gen_params = TypeManager.GetTypeArguments (t); - int arg_count = Arguments != null ? Arguments.Count : 0; + int arg_count = targs != null ? targs.Count : 0; for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) { if (arg_count + ds.CountTypeParameters == gen_params.Length) { @@ -2178,8 +2438,8 @@ namespace Mono.CSharp { foreach (TypeParameter param in ds.TypeParameters) new_args.Add (new TypeParameterExpr (param, loc)); - if (Arguments != null) - new_args.Add (Arguments); + if (targs != null) + new_args.Add (targs); return new ConstructedType (t, new_args, loc); } @@ -2205,8 +2465,8 @@ namespace Mono.CSharp { if (nested != null) return nested.ResolveAsTypeStep (ec, false); - if (Arguments != null) { - ConstructedType ct = new ConstructedType (fne, Arguments, loc); + if (targs != null) { + ConstructedType ct = new ConstructedType (fne, targs, loc); return ct.ResolveAsTypeStep (ec, false); } @@ -2245,7 +2505,7 @@ namespace Mono.CSharp { return; } - if (Arguments != null) { + if (targs != null) { FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true); if (retval != null) { Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc); @@ -2322,7 +2582,7 @@ namespace Mono.CSharp { if (current_block != null){ LocalInfo vi = current_block.GetLocalInfo (Name); if (vi != null){ - if (Arguments != null) { + if (targs != null) { Report.Error (307, loc, "The variable `{0}' cannot be used with type arguments", Name); @@ -2342,7 +2602,7 @@ namespace Mono.CSharp { ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc); if (pref != null) { - if (Arguments != null) { + if (targs != null) { Report.Error (307, loc, "The variable `{0}' cannot be used with type arguments", Name); @@ -2428,11 +2688,11 @@ namespace Mono.CSharp { } if (e is TypeExpr) { - if (Arguments == null) + if (targs == null) return e; ConstructedType ct = new ConstructedType ( - (FullNamedExpression) e, Arguments, loc); + e.Type, targs, loc); return ct.ResolveAsTypeStep (ec, false); } @@ -2452,7 +2712,7 @@ namespace Mono.CSharp { if (!me.IsStatic && (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) { Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ()); - return EmptyExpression.Null; + return null; } // @@ -2470,9 +2730,9 @@ namespace Mono.CSharp { if (me == null) return null; - if (Arguments != null) { - Arguments.Resolve (ec); - me.SetTypeArguments (Arguments); + if (targs != null) { + targs.Resolve (ec); + me.SetTypeArguments (targs); } if (!me.IsStatic && (me.InstanceExpression != null) && @@ -2493,26 +2753,6 @@ namespace Mono.CSharp { return e; } - public override void Emit (EmitContext ec) - { - throw new InternalErrorException ("The resolve phase was not executed"); - } - - public override string ToString () - { - return Name; - } - - public override string GetSignatureForError () - { - if (Arguments != null) { - return TypeManager.RemoveGenericArity (Name) + "<" + - Arguments.GetSignatureForError () + ">"; - } - - return Name; - } - protected override void CloneTo (CloneContext clonectx, Expression target) { // CloneTo: Nothing, we do not keep any state on this expression @@ -2524,13 +2764,21 @@ namespace Mono.CSharp { /// section 10.8.1 (Fully Qualified Names). /// public abstract class FullNamedExpression : Expression { + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent) { return this; } - public abstract string FullName { - get; + public override void Emit (EmitContext ec) + { + throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree", + GetSignatureForError ()); } } @@ -2553,19 +2801,14 @@ namespace Mono.CSharp { return ResolveAsTypeTerminal (ec, false); } - override public void Emit (EmitContext ec) - { - throw new Exception ("Should never be called"); - } - public virtual bool CheckAccessLevel (DeclSpace ds) { return ds.CheckAccessLevel (Type); } - public virtual bool AsAccessible (DeclSpace ds, int flags) + public virtual bool AsAccessible (DeclSpace ds) { - return ds.AsAccessible (Type, flags); + return ds.IsAccessibleAs (Type); } public virtual bool IsClass { @@ -2598,10 +2841,6 @@ namespace Mono.CSharp { protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec); - public abstract string Name { - get; - } - public override bool Equals (object obj) { TypeExpr tobj = obj as TypeExpr; @@ -2615,10 +2854,10 @@ namespace Mono.CSharp { { return Type.GetHashCode (); } - - public override string ToString () + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) { - return Name; + type = storey.MutateType (type); } } @@ -2642,14 +2881,6 @@ namespace Mono.CSharp { { return this; } - - public override string Name { - get { return Type.ToString (); } - } - - public override string FullName { - get { return Type.FullName; } - } } /// @@ -2783,14 +3014,6 @@ namespace Mono.CSharp { return this; } - public override string Name { - get { return name; } - } - - public override string FullName { - get { return name; } - } - protected override void CloneTo (CloneContext clonectx, Expression target) { // CloneTo: Nothing, we do not keep any state on this expression @@ -2819,6 +3042,11 @@ namespace Mono.CSharp { loc = l; } + protected override void CloneTo (CloneContext clonectx, Expression target) + { + // Nothing to clone + } + protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) { Expression expr; @@ -2836,99 +3064,6 @@ namespace Mono.CSharp { type = fne.Type; return new TypeExpression (type, loc); } - - public override string Name { - get { return name.FullName; } - } - - public override string FullName { - get { return name.FullName; } - } - } - - public class TypeAliasExpression : TypeExpr { - FullNamedExpression alias; - TypeExpr texpr; - TypeArguments args; - string name; - - public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l) - { - this.alias = alias; - this.args = args; - loc = l; - - eclass = ExprClass.Type; - if (args != null) - name = alias.FullName + "<" + args.ToString () + ">"; - else - name = alias.FullName; - } - - public override string Name { - get { return alias.FullName; } - } - - public override string FullName { - get { return name; } - } - - protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec) - { - texpr = alias.ResolveAsTypeTerminal (ec, false); - if (texpr == null) - return null; - - Type type = texpr.Type; - int num_args = TypeManager.GetNumberOfTypeArguments (type); - - if (args != null) { - if (num_args == 0) { - Report.Error (308, loc, - "The non-generic type `{0}' cannot " + - "be used with type arguments.", - TypeManager.CSharpName (type)); - return null; - } - - ConstructedType ctype = new ConstructedType (type, args, loc); - return ctype.ResolveAsTypeTerminal (ec, false); - } else if (num_args > 0) { - Report.Error (305, loc, - "Using the generic type `{0}' " + - "requires {1} type arguments", - TypeManager.CSharpName (type), num_args.ToString ()); - return null; - } - - return texpr; - } - - public override bool CheckAccessLevel (DeclSpace ds) - { - return texpr.CheckAccessLevel (ds); - } - - public override bool AsAccessible (DeclSpace ds, int flags) - { - return texpr.AsAccessible (ds, flags); - } - - public override bool IsClass { - get { return texpr.IsClass; } - } - - public override bool IsValueType { - get { return texpr.IsValueType; } - } - - public override bool IsInterface { - get { return texpr.IsInterface; } - } - - public override bool IsSealed { - get { return texpr.IsSealed; } - } } /// @@ -2987,6 +3122,17 @@ namespace Mono.CSharp { "with an instance reference, qualify it with a type name instead", name); } + public static void Error_BaseAccessInExpressionTree (Location loc) + { + Report.Error (831, loc, "An expression tree may not contain a base access"); + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + if (InstanceExpression != null) + InstanceExpression.MutateHoistedGenericType (storey); + } + // TODO: possible optimalization // Cache resolved constant result in FieldBuilder <-> expression map public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, @@ -3100,11 +3246,8 @@ namespace Mono.CSharp { base.EmitCall (ec, arguments); } - public override MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList arguments, bool may_fail, Location loc) + public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc) { - if ((ExtensionExpression.eclass & (ExprClass.Value | ExprClass.Variable)) == 0) - return base.OverloadResolve (ec, arguments, may_fail, loc); - if (arguments == null) arguments = new ArrayList (1); @@ -3122,7 +3265,7 @@ namespace Mono.CSharp { MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc) { // Use normal resolve rules - MethodGroupExpr mg = base.OverloadResolve (ec, arguments, ns != null, loc); + MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc); if (mg != null) return mg; @@ -3130,11 +3273,12 @@ namespace Mono.CSharp { return null; // Search continues - ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name); + ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc); if (e == null) - return base.OverloadResolve (ec, arguments, false, loc); + return base.OverloadResolve (ec, ref arguments, false, loc); e.ExtensionExpression = ExtensionExpression; + e.SetTypeArguments (type_arguments); return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc); } } @@ -3266,57 +3410,84 @@ namespace Mono.CSharp { return (MethodInfo)mg.best_candidate; } - /// - /// Determines "better conversion" as specified in 14.4.2.3 - /// - /// Returns : p if a->p is better, - /// q if a->q is better, - /// null if neither is better - /// - static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q) + // + // 7.4.3.3 Better conversion from expression + // Returns : 1 if a->p is better, + // 2 if a->q is better, + // 0 if neither is better + // + static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q) { Type argument_type = TypeManager.TypeToCoreType (a.Type); - Expression argument_expr = a.Expr; + if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) { + // + // Uwrap delegate from Expression + // + if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) { + p = TypeManager.GetTypeArguments (p) [0]; + } + if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) { + q = TypeManager.GetTypeArguments (q) [0]; + } + + p = Delegate.GetInvokeMethod (null, p).ReturnType; + q = Delegate.GetInvokeMethod (null, q).ReturnType; + if (p == TypeManager.void_type && q != TypeManager.void_type) + return 2; + if (q == TypeManager.void_type && p != TypeManager.void_type) + return 1; + } else { + if (argument_type == p) + return 1; - if (argument_type == null) - throw new Exception ("Expression of type " + a.Expr + - " does not resolve its type"); + if (argument_type == q) + return 2; + } - if (p == null || q == null) - throw new InternalErrorException ("BetterConversion Got a null conversion"); + return BetterTypeConversion (ec, p, q); + } - if (p == q) - return null; + // + // 7.4.3.4 Better conversion from type + // + public static int BetterTypeConversion (EmitContext ec, Type p, Type q) + { + if (p == null || q == null) + throw new InternalErrorException ("BetterTypeConversion got a null conversion"); - if (argument_expr is NullLiteral) - { - // - // 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. - // - // 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 (p == TypeManager.int32_type) { + if (q == TypeManager.uint32_type || q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.int64_type) { + if (q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.sbyte_type) { + if (q == TypeManager.byte_type || q == TypeManager.ushort_type || + q == TypeManager.uint32_type || q == TypeManager.uint64_type) + return 1; + } else if (p == TypeManager.short_type) { + if (q == TypeManager.ushort_type || q == TypeManager.uint32_type || + q == TypeManager.uint64_type) + return 1; } - - if (argument_type == p) - return p; - if (argument_type == q) - return q; + if (q == TypeManager.int32_type) { + if (p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return 2; + } if (q == TypeManager.int64_type) { + if (p == TypeManager.uint64_type) + return 2; + } else if (q == TypeManager.sbyte_type) { + if (p == TypeManager.byte_type || p == TypeManager.ushort_type || + p == TypeManager.uint32_type || p == TypeManager.uint64_type) + return 2; + } if (q == TypeManager.short_type) { + if (p == TypeManager.ushort_type || p == TypeManager.uint32_type || + p == TypeManager.uint64_type) + return 2; + } + // TODO: this is expensive Expression p_tmp = new EmptyExpression (p); Expression q_tmp = new EmptyExpression (q); @@ -3324,44 +3495,12 @@ namespace Mono.CSharp { bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p); if (p_to_q && !q_to_p) - return p; + return 1; 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 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 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 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 p; - if (q == TypeManager.int64_type) - if (p == TypeManager.uint64_type) - return q; + return 2; - return null; + return 0; } /// @@ -3405,16 +3544,16 @@ namespace Mono.CSharp { continue; same = false; - Type better = BetterConversion (ec, a, ct, bt); + int result = BetterExpressionConversion (ec, a, ct, bt); // for each argument, the conversion to 'ct' should be no worse than // the conversion to 'bt'. - if (better == bt) + if (result == 2) return false; // for at least one argument, the conversion to 'ct' should be better than // the conversion to 'bt'. - if (better == ct) + if (result != 0) better_at_least_one = true; } @@ -3520,7 +3659,20 @@ namespace Mono.CSharp { public override Expression CreateExpressionTree (EmitContext ec) { - return new Cast (new TypeExpression (typeof (MethodInfo), loc), new TypeOfMethod (this)); + if (best_candidate == null) { + Report.Error (1953, loc, "An expression tree cannot contain an expression with method group"); + return null; + } + + if (best_candidate.IsConstructor) + return new TypeOfConstructorInfo (best_candidate, loc); + + IMethodData md = TypeManager.GetMethod (best_candidate); + if (md != null && md.IsExcluded ()) + Report.Error (765, loc, + "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree"); + + return new TypeOfMethodInfo (best_candidate, loc); } override public Expression DoResolve (EmitContext ec) @@ -3547,7 +3699,7 @@ namespace Mono.CSharp { public virtual void EmitArguments (EmitContext ec, ArrayList arguments) { - Invocation.EmitArguments (ec, best_candidate, arguments, false, null); + Invocation.EmitArguments (ec, arguments, false, null); } public virtual void EmitCall (EmitContext ec, ArrayList arguments) @@ -3558,6 +3710,8 @@ namespace Mono.CSharp { protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method, Argument a, ParameterData expected_par, Type paramType) { + ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr; + if (a is CollectionElementInitializer.ElementInitializerArgument) { Report.SymbolRelatedToPreviousError (method); if ((expected_par.ParameterModifier (idx) & Parameter.Modifier.ISBYREF) != 0) { @@ -3569,8 +3723,15 @@ namespace Mono.CSharp { TypeManager.CSharpSignature (method)); } else if (delegate_type == null) { Report.SymbolRelatedToPreviousError (method); - Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments", - TypeManager.CSharpSignature (method)); + if (emg != null) { + Report.Error (1928, loc, + "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments", + emg.ExtensionExpression.GetSignatureForError (), + emg.Name, TypeManager.CSharpSignature (method)); + } else { + Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments", + TypeManager.CSharpSignature (method)); + } } else Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments", TypeManager.CSharpName (delegate_type)); @@ -3578,16 +3739,16 @@ namespace Mono.CSharp { Parameter.Modifier mod = expected_par.ParameterModifier (idx); string index = (idx + 1).ToString (); - if ((mod & Parameter.Modifier.ISBYREF) != (a.Modifier & Parameter.Modifier.ISBYREF) || - (mod & Parameter.Modifier.ISBYREF) != 0) { - if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0) - Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword", + if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^ + (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) { + if ((mod & Parameter.Modifier.ISBYREF) == 0) + Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier", index, Parameter.GetModifierSignature (a.Modifier)); else - Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword", + Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier", index, Parameter.GetModifierSignature (mod)); } else { - string p1 = Argument.FullDesc (a); + string p1 = a.GetSignatureForError (); string p2 = TypeManager.CSharpName (paramType); if (p1 == p2) { @@ -3595,9 +3756,22 @@ namespace Mono.CSharp { Report.SymbolRelatedToPreviousError (a.Expr.Type); Report.SymbolRelatedToPreviousError (paramType); } - Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2); + + if (idx == 0 && emg != null) { + Report.Error (1929, loc, + "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2); + } else { + Report.Error (1503, loc, + "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2); + } } } + + public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl) + { + Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method", + Name, TypeManager.CSharpName (target)); + } protected virtual int GetApplicableParametersCount (MethodBase method, ParameterData parameters) { @@ -3652,7 +3826,8 @@ namespace Mono.CSharp { return score - 20000; if (TypeManager.IsGenericMethodDefinition (candidate)) - throw new InternalErrorException ("a generic method definition took part in overload resolution"); + throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution", + TypeManager.CSharpSignature (candidate)); pd = TypeManager.GetParameterData (candidate); } @@ -3665,6 +3840,7 @@ namespace Mono.CSharp { // // 2. Each argument has to be implicitly convertible to method parameter // + method = candidate; Parameter.Modifier p_mod = 0; Type pt = null; for (int i = 0; i < arg_count; i++) { @@ -3698,14 +3874,16 @@ namespace Mono.CSharp { params_expanded_form = true; } - if (score != 0) + if (score != 0) { + if (params_expanded_form) + ++score; return (arg_count - i) * 2 + score; + } } if (arg_count != param_count) params_expanded_form = true; - method = candidate; return 0; } @@ -3724,26 +3902,16 @@ namespace Mono.CSharp { if (a_type != parameter) return 2; - - return 0; - } - - // FIXME: Kill this abomination (EmitContext.TempEc) - EmitContext prevec = EmitContext.TempEc; - EmitContext.TempEc = ec; - try { + } else { if (delegate_type != null ? !Delegate.IsTypeCovariant (argument.Expr, parameter) : !Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) return 2; - - if (arg_mod != param_mod) - return 1; - - } finally { - EmitContext.TempEc = prevec; } + if (arg_mod != param_mod) + return 1; + return 0; } @@ -3860,6 +4028,19 @@ namespace Mono.CSharp { return null; } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + base.MutateHoistedGenericType (storey); + + MethodInfo mi = best_candidate as MethodInfo; + if (mi != null) { + best_candidate = storey.MutateGenericMethod (mi); + return; + } + + best_candidate = storey.MutateConstructor ((ConstructorInfo) this); + } + /// /// Find the Applicable Function Members (7.4.2.1) /// @@ -3876,7 +4057,7 @@ namespace Mono.CSharp { /// that is the best match of me on Arguments. /// /// - public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ArrayList Arguments, + public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments, bool may_fail, Location loc) { bool method_params = false; @@ -3989,8 +4170,12 @@ namespace Mono.CSharp { } Report.SetMessageRecorder (prev_recorder); - if (msg_recorder != null && msg_recorder.PrintMessages ()) + if (msg_recorder != null && !msg_recorder.IsEmpty) { + if (!may_fail) + msg_recorder.PrintMessages (); + return null; + } int candidate_top = candidates.Count; @@ -4000,11 +4185,11 @@ namespace Mono.CSharp { // not an extension method. We start extension methods lookup from here // if (InstanceExpression != null) { - ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name); + ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc); if (ex_method_lookup != null) { ex_method_lookup.ExtensionExpression = InstanceExpression; ex_method_lookup.SetTypeArguments (type_arguments); - return ex_method_lookup.OverloadResolve (ec, Arguments, may_fail, loc); + return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc); } } @@ -4024,7 +4209,7 @@ namespace Mono.CSharp { ParameterData pd = TypeManager.GetParameterData (best_candidate); bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); if (arg_count == pd.Count || pd.HasParams) { - if (TypeManager.IsGenericMethod (best_candidate)) { + if (TypeManager.IsGenericMethodDefinition (best_candidate)) { if (type_arguments == null) { Report.Error (411, loc, "The type arguments for method `{0}' cannot be inferred from " + @@ -4042,15 +4227,14 @@ namespace Mono.CSharp { return null; } } else { - if (type_arguments != null) { + if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) { Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc); return null; } } - if (VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, cand_params, may_fail, loc)) - throw new InternalErrorException ("Overload verification expected failure"); - return null; + if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc)) + return null; } } @@ -4132,7 +4316,9 @@ namespace Mono.CSharp { // best_candidate = (MethodBase) candidates [0]; - method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); + if (delegate_type == null) + method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate); + for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; @@ -4153,7 +4339,7 @@ namespace Mono.CSharp { // should be better than all the others // MethodBase ambiguous = null; - for (int ix = 0; ix < candidate_top; ix++) { + for (int ix = 1; ix < candidate_top; ix++) { MethodBase candidate = (MethodBase) candidates [ix]; if (candidate == best_candidate) @@ -4223,7 +4409,7 @@ namespace Mono.CSharp { // necessary etc. and return if everything is // all right // - if (!VerifyArgumentsCompat (ec, Arguments, arg_count, best_candidate, + if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, method_params, may_fail, loc)) return null; @@ -4249,7 +4435,7 @@ namespace Mono.CSharp { type_arguments = ta; } - public bool VerifyArgumentsCompat (EmitContext ec, ArrayList arguments, + public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments, int arg_count, MethodBase method, bool chose_params_expanded, bool may_fail, Location loc) @@ -4259,9 +4445,11 @@ namespace Mono.CSharp { int errors = Report.Errors; Parameter.Modifier p_mod = 0; Type pt = null; - int a_idx = 0; + int a_idx = 0, a_pos = 0; Argument a = null; - for (; a_idx < arg_count; a_idx++) { + ArrayList params_initializers = null; + + for (; a_idx < arg_count; a_idx++, ++a_pos) { a = (Argument) arguments [a_idx]; if (p_mod != Parameter.Modifier.PARAMS) { p_mod = pd.ParameterModifier (a_idx); @@ -4281,8 +4469,10 @@ namespace Mono.CSharp { } if (p_mod == Parameter.Modifier.PARAMS) { - if (chose_params_expanded) + if (chose_params_expanded) { + params_initializers = new ArrayList (arg_count - a_idx); pt = TypeManager.GetElementType (pt); + } } else if (p_mod != 0) { pt = TypeManager.GetElementType (pt); } @@ -4300,26 +4490,62 @@ namespace Mono.CSharp { continue; } - - if (TypeManager.IsEqual (a.Type, pt)) - continue; - - Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc); - if (conv == null) - break; - if (!chose_params_expanded && (p_mod & Parameter.Modifier.PARAMS) != 0 && a.Type == TypeManager.null_type) - conv.Type = pd.ParameterType (a_idx); + Expression conv; + if (TypeManager.IsEqual (a.Type, pt)) { + conv = a.Expr; + } else { + conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc); + if (conv == null) + break; + } + + // + // Convert params arguments to an array initializer + // + if (params_initializers != null) { + // we choose to use 'a.Expr' rather than 'conv' so that + // we don't hide the kind of expression we have (esp. CompoundAssign.Helper) + params_initializers.Add (a.Expr); + arguments.RemoveAt (a_idx--); + --arg_count; + continue; + } // Update the argument with the implicit conversion a.Expr = conv; } - if (a_idx == arg_count) + // + // Fill not provided arguments required by params modifier + // + if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) { + if (arguments == null) + arguments = new ArrayList (1); + + pt = pd.Types [GetApplicableParametersCount (method, pd) - 1]; + pt = TypeManager.GetElementType (pt); + params_initializers = new ArrayList (0); + } + + if (a_idx == arg_count) { + // + // Append an array argument with all params arguments + // + if (params_initializers != null) { + arguments.Add (new Argument ( + new ArrayCreation (new TypeExpression (pt, loc), "[]", + params_initializers, loc).Resolve (ec))); + } return true; + } - if (!may_fail && Report.Errors == errors) - Error_InvalidArguments (ec, loc, a_idx, method, a, pd, pt); + if (!may_fail && Report.Errors == errors) { + if (CustomErrorHandler != null) + CustomErrorHandler.NoExactMatch (ec, best_candidate); + else + Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt); + } return false; } } @@ -4370,6 +4596,11 @@ namespace Mono.CSharp { return base.ResolveMemberAccess (ec, left, loc, original); } + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + public override Expression DoResolve (EmitContext ec) { IConstant ic = TypeManager.GetConstant (constant); @@ -4396,7 +4627,8 @@ namespace Mono.CSharp { /// Fully resolved expression that evaluates to a Field /// public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable { - public readonly FieldInfo FieldInfo; + public FieldInfo FieldInfo; + readonly Type constructed_generic_type; VariableInfo variable_info; LocalTemporary temp; @@ -4417,6 +4649,12 @@ namespace Mono.CSharp { loc = l; } + public FieldExpr (FieldInfo fi, Type genericType, Location l) + : this (fi, l) + { + this.constructed_generic_type = genericType; + } + public override string Name { get { return FieldInfo.Name; @@ -4465,6 +4703,26 @@ namespace Mono.CSharp { return base.ResolveMemberAccess (ec, left, loc, original); } + public override Expression CreateExpressionTree (EmitContext ec) + { + Expression instance; + if (InstanceExpression == null) { + instance = new NullLiteral (loc); + } else { + instance = InstanceExpression.CreateExpressionTree (ec); + } + + ArrayList args = new ArrayList (2); + args.Add (new Argument (instance)); + args.Add (new Argument (CreateTypeOfExpression ())); + return CreateExpressionFactoryCall ("Field", args); + } + + public Expression CreateTypeOfExpression () + { + return new TypeOfField (FieldInfo, loc); + } + override public Expression DoResolve (EmitContext ec) { return DoResolve (ec, false, false); @@ -4520,18 +4778,6 @@ namespace Mono.CSharp { } } - AnonymousContainer am = ec.CurrentAnonymousMethod; - if (am != null){ - if (!FieldInfo.IsStatic){ - if (!am.IsIterator && (ec.TypeContainer is Struct)){ - Report.Error (1673, loc, - "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead", - "this"); - return null; - } - } - } - IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo); if (fb != null) { if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) { @@ -4549,7 +4795,7 @@ namespace Mono.CSharp { // If the instance expression is a local variable or parameter. IVariable var = InstanceExpression as IVariable; - if ((var == null) || (var.VariableInfo == null)) + if (var == null || var.VariableInfo == null) return this; VariableInfo vi = var.VariableInfo; @@ -4600,7 +4846,7 @@ namespace Mono.CSharp { override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { IVariable var = InstanceExpression as IVariable; - if ((var != null) && (var.VariableInfo != null)) + if (var != null && var.VariableInfo != null) var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name); bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType; @@ -4638,7 +4884,7 @@ namespace Mono.CSharp { } if (right_side == EmptyExpression.OutAccess && - !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) { + !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) { Report.SymbolRelatedToPreviousError (DeclaringType); Report.Warning (197, 1, loc, "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class", @@ -4648,28 +4894,34 @@ namespace Mono.CSharp { return this; } + bool is_marshal_by_ref () + { + return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type); + } + public override void CheckMarshalByRefAccess (EmitContext ec) { - if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) { + if (is_marshal_by_ref () && !(InstanceExpression is This)) { Report.SymbolRelatedToPreviousError (DeclaringType); Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class", GetSignatureForError ()); } } - public bool VerifyFixed () - { - IVariable variable = InstanceExpression as IVariable; - // A variable of the form V.I is fixed when V is a fixed variable of a struct type. - // We defer the InstanceExpression check after the variable check to avoid a - // separate null check on InstanceExpression. - return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed (); - } - public override int GetHashCode () { return FieldInfo.GetHashCode (); } + + public bool IsFixed { + get { + IVariable variable = InstanceExpression as IVariable; + // A variable of the form V.I is fixed when V is a fixed variable of a struct type. + // We defer the InstanceExpression check after the variable check to avoid a + // separate null check on InstanceExpression. + return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed; + } + } public override bool Equals (object obj) { @@ -4702,21 +4954,21 @@ namespace Mono.CSharp { if (FieldInfo.IsStatic){ if (is_volatile) ig.Emit (OpCodes.Volatile); - - ig.Emit (OpCodes.Ldsfld, FieldInfo); + + ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ()); } else { if (!prepared) EmitInstance (ec, false); IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo); if (ff != null) { - ig.Emit (OpCodes.Ldflda, FieldInfo); + ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ()); ig.Emit (OpCodes.Ldflda, ff.Element); } else { if (is_volatile) ig.Emit (OpCodes.Volatile); - ig.Emit (OpCodes.Ldfld, FieldInfo); + ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ()); } } @@ -4741,10 +4993,7 @@ namespace Mono.CSharp { return; } - // - // String concatenation creates a new string instance - // - prepared = prepare_for_load && !(source is StringConcat); + prepared = prepare_for_load; EmitInstance (ec, prepared); source.Emit (ec); @@ -4765,13 +5014,14 @@ namespace Mono.CSharp { } if (is_static) - ig.Emit (OpCodes.Stsfld, FieldInfo); - else - ig.Emit (OpCodes.Stfld, FieldInfo); + ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ()); + else + ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ()); if (temp != null) { temp.Emit (ec); temp.Release (ec); + temp = null; } } @@ -4780,6 +5030,15 @@ namespace Mono.CSharp { Emit (ec, false); } + public override void EmitSideEffect (EmitContext ec) + { + FieldBase f = TypeManager.GetField (FieldInfo); + bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0; + + if (is_volatile || is_marshal_by_ref ()) + base.EmitSideEffect (ec); + } + public void AddressOf (EmitContext ec, AddressOp mode) { ILGenerator ig = ec.ig; @@ -4825,13 +5084,30 @@ namespace Mono.CSharp { if (FieldInfo.IsStatic){ - ig.Emit (OpCodes.Ldsflda, FieldInfo); + ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ()); } else { if (!prepared) EmitInstance (ec, false); - ig.Emit (OpCodes.Ldflda, FieldInfo); + ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ()); } } + + FieldInfo GetConstructedFieldInfo () + { + if (constructed_generic_type == null) + return FieldInfo; +#if GMCS_SOURCE + return TypeBuilder.GetField (constructed_generic_type, FieldInfo); +#else + throw new NotSupportedException (); +#endif + } + + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + FieldInfo = storey.MutateField (FieldInfo); + base.MutateHoistedGenericType (storey); + } } @@ -4884,18 +5160,30 @@ namespace Mono.CSharp { public override Expression CreateExpressionTree (EmitContext ec) { + ArrayList args; if (IsSingleDimensionalArrayLength ()) { - ArrayList args = new ArrayList (1); + args = new ArrayList (1); args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec))); return CreateExpressionFactoryCall ("ArrayLength", args); } - // TODO: it's waiting for PropertyExpr refactoring - //ArrayList args = new ArrayList (2); - //args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec))); - //args.Add (getter expression); - //return CreateExpressionFactoryCall ("Property", args); - return base.CreateExpressionTree (ec); + if (is_base) { + Error_BaseAccessInExpressionTree (loc); + return null; + } + + args = new ArrayList (2); + if (InstanceExpression == null) + args.Add (new Argument (new NullLiteral (loc))); + else + args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec))); + args.Add (new Argument (new TypeOfMethodInfo (getter, loc))); + return CreateExpressionFactoryCall ("Property", args); + } + + public Expression CreateSetterTypeOfExpression () + { + return new TypeOfMethodInfo (setter, loc); } public override Type DeclaringType { @@ -4971,6 +5259,15 @@ namespace Mono.CSharp { } } + public override void MutateHoistedGenericType (AnonymousMethodStorey storey) + { + if (InstanceExpression != null) + InstanceExpression.MutateHoistedGenericType (storey); + + type = storey.MutateType (type); + getter = storey.MutateGenericMethod (getter); + } + bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check) { if (is_static) { @@ -5011,7 +5308,7 @@ namespace Mono.CSharp { Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name); return; } - + StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType)); sig.Append ('.'); ParameterData iparams = TypeManager.GetParameterData (mi); @@ -5035,18 +5332,12 @@ namespace Mono.CSharp { bool IsSingleDimensionalArrayLength () { - if (getter == TypeManager.system_int_array_get_length || - getter == TypeManager.int_array_get_length) { - Type iet = InstanceExpression.Type; - - // - // System.Array.Length can be called, but the Type does not - // support invoking GetArrayRank, so test for that case first - // - return iet != TypeManager.array_type && (iet.GetArrayRank () == 1); - } + if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length") + return false; - return false; + string t_name = InstanceExpression.Type.Name; + int t_name_len = t_name.Length; + return t_name_len > 2 && t_name [t_name_len - 2] == '['; } override public Expression DoResolve (EmitContext ec) @@ -5217,14 +5508,9 @@ namespace Mono.CSharp { Expression my_source = source; if (prepare_for_load) { - if (source is StringConcat) - EmitInstance (ec, false); - else - prepared = true; - + prepared = true; source.Emit (ec); - prepared = true; if (leave_copy) { ec.ig.Emit (OpCodes.Dup); if (!is_static) { @@ -5341,7 +5627,6 @@ namespace Mono.CSharp { return base.ResolveMemberAccess (ec, left, loc, original); } - bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check) { if (is_static) { @@ -5369,7 +5654,7 @@ namespace Mono.CSharp { // if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null && InstanceExpression.Type != ec.ContainerType && - ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) { + TypeManager.IsSubclassOf (ec.ContainerType, InstanceExpression.Type)) { Report.SymbolRelatedToPreviousError (EventInfo); ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo)); return false; @@ -5385,9 +5670,16 @@ namespace Mono.CSharp { IsAccessorAccessible (invocation_type, remove_accessor, out dummy); } + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { - return DoResolve (ec); + // contexts where an LValue is valid have already devolved to FieldExprs + Error_CannotAssign (); + return null; } public override Expression DoResolve (EmitContext ec) @@ -5402,14 +5694,25 @@ namespace Mono.CSharp { if (!InstanceResolve (ec, must_do_cs1540_check)) return null; + + if (!ec.IsInCompoundAssignment) { + Error_CannotAssign (); + return null; + } return this; } public override void Emit (EmitContext ec) { - Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+ - "(except on the defining type)", GetSignatureForError ()); + Error_CannotAssign (); + } + + public void Error_CannotAssign () + { + Report.Error (70, loc, + "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'", + GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType)); } public override string GetSignatureForError () @@ -5417,96 +5720,76 @@ namespace Mono.CSharp { return TypeManager.CSharpSignature (EventInfo); } - public void EmitAddOrRemove (EmitContext ec, Expression source) + public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source) { - BinaryDelegate source_del = source as BinaryDelegate; - if (source_del == null) { - Emit (ec); - return; - } - Expression handler = source_del.Right; - - Argument arg = new Argument (handler, Argument.AType.Expression); - ArrayList args = new ArrayList (); - - args.Add (arg); - - if (source_del.IsAddition) - Invocation.EmitCall ( - ec, IsBase, InstanceExpression, add_accessor, args, loc); - else - Invocation.EmitCall ( - ec, IsBase, InstanceExpression, remove_accessor, args, loc); + ArrayList args = new ArrayList (1); + args.Add (new Argument (source, Argument.AType.Expression)); + Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc); } } - public class TemporaryVariable : Expression, IMemoryLocation + public class TemporaryVariable : VariableReference { LocalInfo li; - Variable var; - + public TemporaryVariable (Type type, Location loc) { this.type = type; this.loc = loc; - eclass = ExprClass.Value; + eclass = ExprClass.Variable; } - + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + public override Expression DoResolve (EmitContext ec) { if (li != null) return this; - + TypeExpr te = new TypeExpression (type, loc); li = ec.CurrentBlock.AddTemporaryVariable (te, loc); if (!li.Resolve (ec)) return null; - if (ec.MustCaptureVariable (li)) { - ScopeInfo scope = li.Block.CreateScopeInfo (); - var = scope.AddLocal (li); - type = var.Type; + if (ec.MustCaptureVariable (li) && !ec.IsInProbingMode) { + AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec); + storey.CaptureLocalVariable (ec, li); } - - return this; - } - public Variable Variable { - get { return var != null ? var : li.Variable; } + return this; } public override void Emit (EmitContext ec) { - Variable.EmitInstance (ec); - Variable.Emit (ec); + Emit (ec, false); } - - public void EmitLoadAddress (EmitContext ec) + + public void EmitAssign (EmitContext ec, Expression source) { - Variable.EmitInstance (ec); - Variable.EmitAddressOf (ec); + EmitAssign (ec, source, false, false); } - - public void Store (EmitContext ec, Expression right_side) - { - Variable.EmitInstance (ec); - right_side.Emit (ec); - Variable.EmitAssign (ec); + + public override HoistedVariable HoistedVariable { + get { return li.HoistedVariableReference; } } - - public void EmitThis (EmitContext ec) - { - Variable.EmitInstance (ec); + + public override bool IsFixed { + get { return true; } } - - public void EmitStore (EmitContext ec) - { - Variable.EmitAssign (ec); + + public override bool IsRef { + get { return false; } } - - public void AddressOf (EmitContext ec, AddressOp mode) - { - EmitLoadAddress (ec); + + protected override ILocalVariable Variable { + get { return li; } + } + + public override VariableInfo VariableInfo { + get { throw new NotImplementedException (); } } } @@ -5530,7 +5813,7 @@ namespace Mono.CSharp { } } - public override Expression DoResolveLValue (EmitContext ec, Expression right_side) + public bool InferType (EmitContext ec, Expression right_side) { if (type != null) throw new InternalErrorException ("An implicitly typed local variable could not be redefined"); @@ -5539,11 +5822,11 @@ namespace Mono.CSharp { if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) { Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'", right_side.GetSignatureForError ()); - return null; + return false; } eclass = ExprClass.Variable; - return this; + return true; } protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)