X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=027ea74aa31fb171d13700d5f9b388ceefff1e03;hb=93d626fb4b3c50847e43a27b94ee4378fc9070b3;hp=51c6dc77642fe5e5b2f15cdd710b8f5415770638;hpb=6a2255bf98f055084c7cc7560635d8040e06f8c5;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 51c6dc77642..027ea74aa31 100755 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -36,6 +36,34 @@ namespace Mono.CSharp { Nothing, } + /// + /// This is used to tell Resolve in which types of expressions we're + /// interested. + /// + [Flags] + public enum ResolveFlags { + // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess. + VariableOrValue = 1, + + // Returns a type expression. + Type = 2, + + // Returns a method group. + MethodGroup = 4, + + // Allows SimpleNames to be returned. + // This is used by MemberAccess to construct long names that can not be + // partially resolved (namespace-qualified names for example). + SimpleName = 8, + + // Mask of all the expression class flags. + MaskExprClass = 15, + + // Disable control flow analysis while resolving the expression. + // This is used when resolving the instance expression of a field expression. + DisableFlowAnalysis = 16 + } + // // This is just as a hint to AddressOf of what will be done with the // address. @@ -64,12 +92,103 @@ namespace Mono.CSharp { void AddressOf (EmitContext ec, AddressOp mode); } + /// + /// This interface is implemented by variables + /// + public interface IVariable { + /// + /// Checks whether the variable has already been assigned at + /// the current position of the method's control flow and + /// reports an appropriate error message if not. + /// + /// If the variable is a struct, then this call checks whether + /// all of its fields (including all private ones) have been + /// assigned. + /// + bool IsAssigned (EmitContext ec, Location loc); + + /// + /// Checks whether field `name' in this struct has been assigned. + /// + bool IsFieldAssigned (EmitContext ec, string name, Location loc); + + /// + /// Tells the flow analysis code that the variable has already + /// been assigned at the current code position. + /// + /// If the variable is a struct, this call marks all its fields + /// (including private fields) as being assigned. + /// + void SetAssigned (EmitContext ec); + + /// + /// Tells the flow analysis code that field `name' in this struct + /// has already been assigned atthe current code position. + /// + void SetFieldAssigned (EmitContext ec, string name); + } + + /// + /// This interface denotes an expression which evaluates to a member + /// of a struct or a class. + /// + public interface IMemberExpr + { + /// + /// The name of this member. + /// + string Name { + get; + } + + /// + /// Whether this is an instance member. + /// + bool IsInstance { + get; + } + + /// + /// Whether this is a static member. + /// + bool IsStatic { + get; + } + + /// + /// The type which declares this member. + /// + Type DeclaringType { + get; + } + + /// + /// The instance expression associated with this member, if it's a + /// non-static member. + /// + Expression InstanceExpression { + get; set; + } + } + + /// + /// Expression which resolves to a type. + /// + public interface ITypeExpression + { + /// + /// Resolve the expression, but only lookup types. + /// + Expression DoResolveType (EmitContext ec); + } + /// /// Base class for expressions /// public abstract class Expression { public ExprClass eclass; - protected Type type; + protected Type type; + protected Location loc; public Type Type { get { @@ -81,25 +200,42 @@ namespace Mono.CSharp { } } + public Location Location { + get { + return loc; + } + } + /// /// Utility wrapper routine for Error, just to beautify the code /// - static protected void Error (int error, string s) + public void Error (int error, string s) { - Report.Error (error, s); + if (!Location.IsNull (loc)) + Report.Error (error, loc, s); + else + Report.Error (error, s); } - static protected void Error (int error, Location loc, string s) + /// + /// Utility wrapper routine for Warning, just to beautify the code + /// + public void Warning (int warning, string s) { - Report.Error (error, loc, s); + if (!Location.IsNull (loc)) + Report.Warning (warning, loc, s); + else + Report.Warning (warning, s); } - + /// - /// Utility wrapper routine for Warning, just to beautify the code + /// Utility wrapper routine for Warning, only prints the warning if + /// warnings of level `level' are enabled. /// - static protected void Warning (int warning, string s) + public void Warning (int warning, int level, string s) { - Report.Warning (warning, s); + if (level <= RootContext.WarningLevel) + Warning (warning, s); } static public void Error_CannotConvertType (Location loc, Type source, Type target) @@ -151,72 +287,110 @@ namespace Mono.CSharp { /// Currently Resolve wraps DoResolve to perform sanity /// checking and assertion checking on what we expect from Resolve. /// - public Expression Resolve (EmitContext ec) + public Expression Resolve (EmitContext ec, ResolveFlags flags) { - Expression e = DoResolve (ec); - - if (e != null){ - - if (e is SimpleName){ - SimpleName s = (SimpleName) e; + // Are we doing a types-only search ? + if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) { + ITypeExpression type_expr = this as ITypeExpression; - Report.Error ( - 103, s.Location, - "The name `" + s.Name + "' could not be found in `" + - ec.DeclSpace.Name + "'"); + if (type_expr == null) return null; - } - - if (e.eclass == ExprClass.Invalid) - throw new Exception ("Expression " + e.GetType () + - " ExprClass is Invalid after resolve"); - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ( - "Expression " + e.GetType () + - " did not set its type after Resolve\n" + - "called from: " + this.GetType ()); + return type_expr.DoResolveType (ec); } - return e; - } + bool old_do_flow_analysis = ec.DoFlowAnalysis; + if ((flags & ResolveFlags.DisableFlowAnalysis) != 0) + ec.DoFlowAnalysis = false; - /// - /// Performs expression resolution and semantic analysis, but - /// allows SimpleNames to be returned. - /// - /// - /// - /// This is used by MemberAccess to construct long names that can not be - /// partially resolved (namespace-qualified names for example). - /// - public Expression ResolveWithSimpleName (EmitContext ec) - { Expression e; - if (this is SimpleName) e = ((SimpleName) this).DoResolveAllowStatic (ec); else e = DoResolve (ec); - if (e != null){ - if (e is SimpleName) - return e; + ec.DoFlowAnalysis = old_do_flow_analysis; - if (e.eclass == ExprClass.Invalid) - throw new Exception ("Expression " + e + - " ExprClass is Invalid after resolve"); + if (e == null) + return null; + + if (e is SimpleName){ + SimpleName s = (SimpleName) e; + + if ((flags & ResolveFlags.SimpleName) == 0) { + + object lookup = TypeManager.MemberLookup ( + ec.ContainerType, ec.ContainerType, AllMemberTypes, + AllBindingFlags | BindingFlags.NonPublic, s.Name); + if (lookup != null) + Error (122, "`" + s.Name + "' " + + "is inaccessible because of its protection level"); + else + Error (103, "The name `" + s.Name + "' could not be " + + "found in `" + ec.DeclSpace.Name + "'"); + return null; + } + + return s; + } + + if ((e is TypeExpr) || (e is ComposedCast)) { + if ((flags & ResolveFlags.Type) == 0) { + e.Error118 (flags); + return null; + } + + return e; + } + + switch (e.eclass) { + case ExprClass.Type: + if ((flags & ResolveFlags.VariableOrValue) == 0) { + e.Error118 (flags); + return null; + } + break; + + case ExprClass.MethodGroup: + if ((flags & ResolveFlags.MethodGroup) == 0) { + ((MethodGroupExpr) e).ReportUsageError (); + return null; + } + break; + + case ExprClass.Value: + case ExprClass.Variable: + case ExprClass.PropertyAccess: + case ExprClass.EventAccess: + case ExprClass.IndexerAccess: + if ((flags & ResolveFlags.VariableOrValue) == 0) { + e.Error118 (flags); + return null; + } + break; - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); + default: + throw new Exception ("Expression " + e.GetType () + + " ExprClass is Invalid after resolve"); } + if (e.type == null) + throw new Exception ( + "Expression " + e.GetType () + + " did not set its type after Resolve\n" + + "called from: " + this.GetType ()); + return e; } - + + /// + /// Resolves an expression and performs semantic analysis on it. + /// + public Expression Resolve (EmitContext ec) + { + return Resolve (ec, ResolveFlags.VariableOrValue); + } + /// /// Resolves an expression for LValue assignment /// @@ -234,7 +408,7 @@ namespace Mono.CSharp { SimpleName s = (SimpleName) e; Report.Error ( - 103, s.Location, + 103, loc, "The name `" + s.Name + "' could not be found in `" + ec.DeclSpace.Name + "'"); return null; @@ -244,10 +418,14 @@ namespace Mono.CSharp { throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve"); - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); + if (e.eclass == ExprClass.MethodGroup) { + ((MethodGroupExpr) e).ReportUsageError (); + return null; + } + + if (e.type == null) + throw new Exception ("Expression " + e + + " did not set its type after Resolve"); } return e; @@ -336,7 +514,7 @@ namespace Mono.CSharp { else if (mi is PropertyInfo) return new PropertyExpr ((PropertyInfo) mi, loc); else if (mi is Type){ - return new TypeExpr ((System.Type) mi); + return new TypeExpr ((System.Type) mi, loc); } return null; @@ -373,7 +551,23 @@ namespace Mono.CSharp { public static Expression MemberLookup (EmitContext ec, Type t, string name, MemberTypes mt, BindingFlags bf, Location loc) { - MemberInfo [] mi = TypeManager.MemberLookup (ec.ContainerType, t, mt, bf, name); + return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc); + } + + // + // Lookup type `t' for code in class `invocation_type'. Note that it's important + // to set `invocation_type' correctly since this method also checks whether the + // invoking class is allowed to access the member in class `t'. When you want to + // explicitly do a lookup in the base class, you must set both `t' and `invocation_type' + // to the base class (although a derived class can access protected members of its base + // class it cannot do so through an instance of the base class (error CS1540)). + // + + public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t, + string name, MemberTypes mt, BindingFlags bf, + Location loc) + { + MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name); if (mi == null) return null; @@ -404,12 +598,14 @@ namespace Mono.CSharp { public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc) { - return MemberLookup (ec, t, name, AllMemberTypes, AllBindingFlags, loc); + return MemberLookup (ec, ec.ContainerType, t, name, + AllMemberTypes, AllBindingFlags, loc); } public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc) { - return MemberLookup (ec, t, name, MemberTypes.Method, AllBindingFlags, loc); + return MemberLookup (ec, ec.ContainerType, t, name, + MemberTypes.Method, AllBindingFlags, loc); } /// @@ -429,10 +625,16 @@ namespace Mono.CSharp { { Expression e; - e = MemberLookup (ec, t, name, mt, bf, loc); + int errors = Report.Errors; + + e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc); if (e != null) return e; + + // Error has already been reported. + if (errors < Report.Errors) + return null; e = MemberLookup (ec, t, name, AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic, loc); @@ -447,7 +649,14 @@ namespace Mono.CSharp { } return null; - } + } + + static public MemberInfo GetFieldFromEvent (EventExpr event_expr) + { + EventInfo ei = event_expr.EventInfo; + + return TypeManager.GetPrivateFieldOfEvent (ei); + } static EmptyExpression MyEmptyExpr; static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) @@ -459,8 +668,12 @@ namespace Mono.CSharp { expr.Emit (null); } - - if (target_type == TypeManager.object_type) { + + // + // notice that it is possible to write "ValueType v = 1", the ValueType here + // is an abstract class, and not really a value type, so we apply the same rules. + // + if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) { // // A pointer type cannot be converted to object // @@ -471,9 +684,9 @@ namespace Mono.CSharp { return new BoxedCast (expr); if (expr_type.IsClass || expr_type.IsInterface) return new EmptyCast (expr, target_type); - } else if (expr_type.IsSubclassOf (target_type)) { + } else if (expr_type.IsSubclassOf (target_type)) return new EmptyCast (expr, target_type); - } else { + else { // This code is kind of mirrored inside StandardConversionExists // with the small distinction that we only probe there @@ -485,16 +698,17 @@ namespace Mono.CSharp { return new EmptyCast (expr, target_type); // from any class-type S to any interface-type T. - if (expr_type.IsClass && target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return new EmptyCast (expr, target_type); - else - return null; + if (target_type.IsInterface) { + if (TypeManager.ImplementsInterface (expr_type, target_type)){ + if (expr_type.IsClass) + return new EmptyCast (expr, target_type); + else if (expr_type.IsValueType) + return new BoxedCast (expr); + } } // from any interface type S to interface-type T. if (expr_type.IsInterface && target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) return new EmptyCast (expr, target_type); else @@ -542,22 +756,6 @@ namespace Mono.CSharp { return null; } - /// - /// Handles expressions like this: decimal d; d = 1; - /// and changes them into: decimal d; d = new System.Decimal (1); - /// - static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target) - { - ArrayList args = new ArrayList (); - - args.Add (new Argument (expr, Argument.AType.Expression)); - - Expression ne = new New (target.FullName, args, - new Location (-1)); - - return ne.Resolve (ec); - } - /// /// Implicit Numeric Conversions. /// @@ -590,19 +788,8 @@ namespace Mono.CSharp { return new ULongConstant ((ulong) v); } - // - // If we have an enumeration, extract the underlying type, - // use this during the comparission, but wrap around the original - // target_type - // - Type real_target_type = target_type; - - if (TypeManager.IsEnumType (real_target_type)) - real_target_type = TypeManager.EnumToUnderlying (real_target_type); + Type real_target_type = target_type; - if (expr_type == real_target_type) - return new EmptyCast (expr, target_type); - if (expr_type == TypeManager.sbyte_type){ // // From sbyte to short, int, long, float, double. @@ -617,8 +804,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.short_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.byte_type){ // // From byte to short, ushort, int, uint, long, ulong, float, double @@ -637,8 +822,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.short_type){ // // From short to int, long, float, double @@ -651,8 +834,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.ushort_type){ // // From ushort to int, uint, long, ulong, float, double @@ -670,8 +851,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.int32_type){ // // From int to long, float, double @@ -682,8 +861,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.uint32_type){ // // From uint to long, ulong, float, double @@ -698,21 +875,24 @@ namespace Mono.CSharp { if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)){ + } else if (expr_type == TypeManager.int64_type){ // // From long/ulong to float, double // + if (real_target_type == TypeManager.double_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (real_target_type == TypeManager.float_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + } else if (expr_type == TypeManager.uint64_type){ + // + // From ulong to float, double + // if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.char_type){ // // From char to ushort, int, uint, long, ulong, float, double @@ -729,8 +909,6 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.float_type){ // // float to double @@ -767,7 +945,7 @@ namespace Mono.CSharp { // from ImplicitReferenceConversion so make sure code remains in sync // from any class-type S to any interface-type T. - if (expr_type.IsClass && target_type.IsInterface) { + if (target_type.IsInterface) { if (TypeManager.ImplementsInterface (expr_type, target_type)) return true; } @@ -837,7 +1015,7 @@ namespace Mono.CSharp { return false; } - + /// /// Determines if a standard implicit conversion exists from /// expr_type to target_type @@ -845,6 +1023,9 @@ namespace Mono.CSharp { public static bool StandardConversionExists (Expression expr, Type target_type) { Type expr_type = expr.Type; + + if (expr_type == TypeManager.void_type) + return false; if (expr_type == target_type) return true; @@ -1007,6 +1188,10 @@ namespace Mono.CSharp { if (i.Value == 0) return true; } + + if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) + return true; + return false; } @@ -1086,7 +1271,7 @@ namespace Mono.CSharp { /// by making use of FindMostEncomp* methods. Applies the correct rules separately /// for explicit and implicit conversion operators. /// - static public Type FindMostSpecificSource (MethodGroupExpr me, Type source_type, + static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source, bool apply_explicit_conv_rules, Location loc) { @@ -1094,10 +1279,11 @@ namespace Mono.CSharp { if (priv_fms_expr == null) priv_fms_expr = new EmptyExpression (); - + // // If any operator converts from S then Sx = S // + Type source_type = source.Type; foreach (MethodBase mb in me.Methods){ ParameterData pd = Invocation.GetParameterData (mb); Type param_type = pd.ParameterType (0); @@ -1118,16 +1304,14 @@ namespace Mono.CSharp { if (StandardConversionExists (priv_fms_expr, source_type)) src_types_set.Add (param_type); else { - priv_fms_expr.SetType (source_type); - if (StandardConversionExists (priv_fms_expr, param_type)) + if (StandardConversionExists (source, param_type)) src_types_set.Add (param_type); } } else { // // Only if S is encompassed by param_type // - priv_fms_expr.SetType (source_type); - if (StandardConversionExists (priv_fms_expr, param_type)) + if (StandardConversionExists (source, param_type)) src_types_set.Add (param_type); } } @@ -1139,9 +1323,7 @@ namespace Mono.CSharp { ArrayList candidate_set = new ArrayList (); foreach (Type param_type in src_types_set){ - priv_fms_expr.SetType (source_type); - - if (StandardConversionExists (priv_fms_expr, param_type)) + if (StandardConversionExists (source, param_type)) candidate_set.Add (param_type); } @@ -1234,7 +1416,7 @@ namespace Mono.CSharp { // if (apply_explicit_conv_rules) return FindMostEncompassedType (tgt_types_set); - else + else return FindMostEncompassingType (tgt_types_set); } @@ -1356,14 +1538,14 @@ namespace Mono.CSharp { } #endif - most_specific_source = FindMostSpecificSource (union, source_type, look_for_explicit, loc); + most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc); if (most_specific_source == null) return null; most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc); if (most_specific_target == null) return null; - + int count = 0; foreach (MethodBase mb in union.Methods){ @@ -1397,7 +1579,7 @@ namespace Mono.CSharp { return null; Expression e; - e = new UserCast ((MethodInfo) method, source); + e = new UserCast ((MethodInfo) method, source, loc); if (e.Type != target){ if (!look_for_explicit) e = ConvertImplicitStandard (ec, e, target, loc); @@ -1531,9 +1713,21 @@ namespace Mono.CSharp { return new ULongConstant ((ulong) value); } - if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)) - return new EnumConstant (ic, target_type); - + if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){ + Type underlying = TypeManager.EnumToUnderlying (target_type); + Constant e = (Constant) ic; + + // + // Possibly, we need to create a different 0 literal before passing + // to EnumConstant + //n + if (underlying == TypeManager.int64_type) + e = new LongLiteral (0); + else if (underlying == TypeManager.uint64_type) + e = new ULongLiteral (0); + + return new EnumConstant (e, target_type); + } return null; } @@ -1543,7 +1737,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (source) + "' to `" + TypeManager.CSharpName (target) + "'"; - Error (29, loc, msg); + Report.Error (29, loc, msg); } /// @@ -1561,11 +1755,11 @@ namespace Mono.CSharp { return e; if (source is DoubleLiteral && target_type == TypeManager.float_type){ - Error (664, loc, - "Double literal cannot be implicitly converted to " + - "float type, use F suffix to create a float literal"); + Report.Error (664, loc, + "Double literal cannot be implicitly converted to " + + "float type, use F suffix to create a float literal"); } - + Error_CannotConvertImplicit (loc, source.Type, target_type); return null; @@ -1574,14 +1768,13 @@ namespace Mono.CSharp { /// /// Performs the explicit numeric conversions /// - static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, - Type target_type) + static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc) { Type expr_type = expr.Type; // // If we have an enumeration, extract the underlying type, - // use this during the comparission, but wrap around the original + // use this during the comparison, but wrap around the original // target_type // Type real_target_type = target_type; @@ -1589,6 +1782,14 @@ namespace Mono.CSharp { if (TypeManager.IsEnumType (real_target_type)) real_target_type = TypeManager.EnumToUnderlying (real_target_type); + if (StandardConversionExists (expr, real_target_type)){ + Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc); + + if (real_target_type != target_type) + return new EmptyCast (ce, target_type); + return ce; + } + if (expr_type == TypeManager.sbyte_type){ // // From sbyte to byte, ushort, uint, ulong, char @@ -1747,8 +1948,6 @@ namespace Mono.CSharp { return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8); if (real_target_type == TypeManager.char_type) return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.double_type){ // // From double to byte, byte, short, @@ -1775,8 +1974,6 @@ namespace Mono.CSharp { return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH); if (real_target_type == TypeManager.float_type) return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } // decimal is taken care of by the op_Explicit methods. @@ -1989,7 +2186,7 @@ namespace Mono.CSharp { if (ne != null) return ne; - ne = ConvertNumericExplicit (ec, expr, target_type); + ne = ConvertNumericExplicit (ec, expr, target_type, loc); if (ne != null) return ne; @@ -2020,7 +2217,12 @@ namespace Mono.CSharp { if (t != null) return t; - return ConvertNumericExplicit (ec, e, target_type); + t = ConvertNumericExplicit (ec, e, target_type, loc); + if (t != null) + return t; + + Error_CannotConvertType (loc, expr_type, target_type); + return null; } ne = ConvertReferenceExplicit (expr, target_type); @@ -2059,7 +2261,7 @@ namespace Mono.CSharp { if (ci != null) return ci; - ce = ConvertNumericExplicit (ec, e, target_type); + ce = ConvertNumericExplicit (ec, e, target_type, loc); if (ce != null) return ce; // @@ -2091,7 +2293,7 @@ namespace Mono.CSharp { if (ne != null) return ne; - ne = ConvertNumericExplicit (ec, expr, target_type); + ne = ConvertNumericExplicit (ec, expr, target_type, l); if (ne != null) return ne; @@ -2133,17 +2335,52 @@ namespace Mono.CSharp { /// /// Reports that we were expecting `expr' to be of class `expected' /// - protected void report118 (Location loc, Expression expr, string expected) + public void Error118 (string expected) { string kind = "Unknown"; - if (expr != null) - kind = ExprClassName (expr.eclass); + kind = ExprClassName (eclass); - Error (118, loc, "Expression denotes a `" + kind + + Error (118, "Expression denotes a `" + kind + "' where a `" + expected + "' was expected"); } + public void Error118 (ResolveFlags flags) + { + ArrayList valid = new ArrayList (10); + + if ((flags & ResolveFlags.VariableOrValue) != 0) { + valid.Add ("variable"); + valid.Add ("value"); + } + + if ((flags & ResolveFlags.Type) != 0) + valid.Add ("type"); + + if ((flags & ResolveFlags.MethodGroup) != 0) + valid.Add ("method group"); + + if ((flags & ResolveFlags.SimpleName) != 0) + valid.Add ("simple name"); + + if (valid.Count == 0) + valid.Add ("unknown"); + + StringBuilder sb = new StringBuilder (); + for (int i = 0; i < valid.Count; i++) { + if (i > 0) + sb.Append (", "); + else if (i == valid.Count) + sb.Append (" or "); + sb.Append (valid [i]); + } + + string kind = ExprClassName (eclass); + + Error (119, "Expression denotes a `" + kind + "' where " + + "a `" + sb.ToString () + "' was expected"); + } + static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t) { Report.Error (31, l, "Constant value `" + val + "' cannot be converted to " + @@ -2455,9 +2692,12 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldind_I1); else if (t == TypeManager.intptr_type) ig.Emit (OpCodes.Ldind_I); - else if (TypeManager.IsEnumType (t)) - LoadFromPtr (ig, TypeManager.EnumToUnderlying (t)); - else if (t.IsValueType) + else if (TypeManager.IsEnumType (t)) { + if (t == TypeManager.enum_type) + ig.Emit (OpCodes.Ldind_Ref); + else + LoadFromPtr (ig, TypeManager.EnumToUnderlying (t)); + } else if (t.IsValueType) ig.Emit (OpCodes.Ldobj, t); else ig.Emit (OpCodes.Ldind_Ref); @@ -2468,7 +2708,7 @@ namespace Mono.CSharp { // public static void StoreFromPtr (ILGenerator ig, Type type) { - if (type.IsEnum) + if (TypeManager.IsEnumType (type)) type = TypeManager.EnumToUnderlying (type); if (type == TypeManager.int32_type || type == TypeManager.uint32_type) ig.Emit (OpCodes.Stind_I4); @@ -2497,6 +2737,7 @@ namespace Mono.CSharp { // public static int GetTypeSize (Type t) { + t = TypeManager.TypeToCoreType (t); if (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.float_type) @@ -2513,6 +2754,8 @@ namespace Mono.CSharp { t == TypeManager.char_type || t == TypeManager.ushort_type) return 2; + else if (t == TypeManager.decimal_type) + return 16; else return 0; } @@ -2523,24 +2766,77 @@ namespace Mono.CSharp { public void CacheTemporaries (EmitContext ec) { } - } - /// - /// This is just a base class for expressions that can - /// appear on statements (invocations, object creation, - /// assignments, post/pre increment and decrement). The idea - /// being that they would support an extra Emition interface that - /// does not leave a result on the stack. - /// - public abstract class ExpressionStatement : Expression { - - /// - /// Requests the expression to be emitted in a `statement' - /// context. This means that no new value is left on the - /// stack after invoking this method (constrasted with - /// Emit that will always leave a value on the stack). - /// - public abstract void EmitStatement (EmitContext ec); + static void Error_NegativeArrayIndex (Location loc) + { + Report.Error (284, loc, "Can not create array with a negative size"); + } + + // + // Converts `source' to an int, uint, long or ulong. + // + public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc) + { + Expression target; + + bool old_checked = ec.CheckState; + ec.CheckState = true; + + target = ConvertImplicit (ec, source, TypeManager.int32_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.int64_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc); + if (target == null) + Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type); + } + } + } + ec.CheckState = old_checked; + + // + // Only positive constants are allowed at compile time + // + if (target is Constant){ + if (target is IntConstant){ + if (((IntConstant) target).Value < 0){ + Error_NegativeArrayIndex (loc); + return null; + } + } + + if (target is LongConstant){ + if (((LongConstant) target).Value < 0){ + Error_NegativeArrayIndex (loc); + return null; + } + } + + } + + return target; + } + + } + + /// + /// This is just a base class for expressions that can + /// appear on statements (invocations, object creation, + /// assignments, post/pre increment and decrement). The idea + /// being that they would support an extra Emition interface that + /// does not leave a result on the stack. + /// + public abstract class ExpressionStatement : Expression { + + /// + /// Requests the expression to be emitted in a `statement' + /// context. This means that no new value is left on the + /// stack after invoking this method (constrasted with + /// Emit that will always leave a value on the stack). + /// + public abstract void EmitStatement (EmitContext ec); } /// @@ -2787,8 +3083,8 @@ namespace Mono.CSharp { public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m) : base (child, return_type) { - mode = m; checked_state = ec.CheckState; + mode = m; } public override Expression DoResolve (EmitContext ec) @@ -3066,53 +3362,40 @@ namespace Mono.CSharp { /// The downside of this is that we might be hitting `LookupType' too many /// times with this scheme. /// - public class SimpleName : Expression { + public class SimpleName : Expression, ITypeExpression { public readonly string Name; - public readonly Location Location; public SimpleName (string name, Location l) { Name = name; - Location = l; + loc = l; } - public static void Error120 (Location l, string name) + public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name) { - Report.Error ( - 120, l, - "An object reference is required " + - "for the non-static field `"+name+"'"); + if (ec.IsFieldInitializer) + Report.Error ( + 236, l, + "A field initializer cannot reference the non-static field, " + + "method or property `"+name+"'"); + else + Report.Error ( + 120, l, + "An object reference is required " + + "for the non-static field `"+name+"'"); } // // Checks whether we are trying to access an instance // property, method or field from a static body. // - Expression MemberStaticCheck (Expression e) + Expression MemberStaticCheck (EmitContext ec, Expression e) { - if (e is FieldExpr){ - FieldInfo fi = ((FieldExpr) e).FieldInfo; + if (e is IMemberExpr){ + IMemberExpr member = (IMemberExpr) e; - if (!fi.IsStatic){ - Error120 (Location, Name); - return null; - } - } else if (e is MethodGroupExpr){ - MethodGroupExpr mg = (MethodGroupExpr) e; - - if (!mg.RemoveInstanceMethods ()){ - Error120 (Location, mg.Methods [0].Name); - return null; - } - return e; - } else if (e is PropertyExpr){ - if (!((PropertyExpr) e).IsStatic){ - Error120 (Location, Name); - return null; - } - } else if (e is EventExpr) { - if (!((EventExpr) e).IsStatic) { - Error120 (Location, Name); + if (!member.IsStatic){ + Error_ObjectRefRequired (ec, loc, Name); return null; } } @@ -3136,6 +3419,52 @@ namespace Mono.CSharp { return SimpleNameResolve (ec, null, true); } + public Expression DoResolveType (EmitContext ec) + { + // + // Stage 3: Lookup symbol in the various namespaces. + // + DeclSpace ds = ec.DeclSpace; + Type t; + string alias_value; + + if (ec.ResolvingTypeTree){ + int errors = Report.Errors; + Type dt = ec.DeclSpace.FindType (loc, Name); + if (Report.Errors != errors) + return null; + + if (dt != null) + return new TypeExpr (dt, loc); + } + + if ((t = RootContext.LookupType (ds, Name, true, loc)) != null) + return new TypeExpr (t, loc); + + + // + // Stage 2 part b: Lookup up if we are an alias to a type + // or a namespace. + // + // Since we are cheating: we only do the Alias lookup for + // namespaces if the name does not include any dots in it + // + + alias_value = ec.DeclSpace.LookupAlias (Name); + + if (Name.IndexOf ('.') == -1 && alias_value != null) { + if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null) + return new TypeExpr (t, loc); + + // we have alias value, but it isn't Type, so try if it's namespace + return new SimpleName (alias_value, loc); + } + + // No match, maybe our parent can compose us + // into something meaningful. + return this; + } + /// /// 7.5.2: Simple Names. /// @@ -3160,233 +3489,112 @@ namespace Mono.CSharp { // // Stage 1: Performed by the parser (binding to locals or parameters). // - if (!ec.OnlyLookupTypes){ - Block current_block = ec.CurrentBlock; - if (current_block != null && current_block.IsVariableDefined (Name)){ - LocalVariableReference var; - - var = new LocalVariableReference (ec.CurrentBlock, Name, Location); - - if (right_side != null) - return var.ResolveLValue (ec, right_side); - else - return var.Resolve (ec); - } - - // - // Stage 2: Lookup members - // - - // - // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder - // Hence we have two different cases - // - - DeclSpace lookup_ds = ec.DeclSpace; - do { - if (lookup_ds.TypeBuilder == null) - break; + Block current_block = ec.CurrentBlock; + if (current_block != null && current_block.IsVariableDefined (Name)){ + LocalVariableReference var; - e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, Location); - if (e != null) - break; - - // - // Classes/structs keep looking, enums break - // - if (lookup_ds is TypeContainer) - lookup_ds = ((TypeContainer) lookup_ds).Parent; - else - break; - } while (lookup_ds != null); - - if (e == null && ec.ContainerType != null) - e = MemberLookup (ec, ec.ContainerType, Name, Location); - } - - // Continuation of stage 2 - if (e == null){ - // - // Stage 3: Lookup symbol in the various namespaces. - // - DeclSpace ds = ec.DeclSpace; - Type t; - string alias_value; + var = new LocalVariableReference (ec.CurrentBlock, Name, loc); - if ((t = RootContext.LookupType (ds, Name, true, Location)) != null) - return new TypeExpr (t); - - // - // Stage 2 part b: Lookup up if we are an alias to a type - // or a namespace. - // - // Since we are cheating: we only do the Alias lookup for - // namespaces if the name does not include any dots in it - // - - if (Name.IndexOf ('.') == -1 && (alias_value = ec.TypeContainer.LookupAlias (Name)) != null) { - // System.Console.WriteLine (Name + " --> " + alias_value); - if ((t = RootContext.LookupType (ds, alias_value, true, Location)) - != null) - return new TypeExpr (t); - - // we have alias value, but it isn't Type, so try if it's namespace - return new SimpleName (alias_value, Location); - } - - // No match, maybe our parent can compose us - // into something meaningful. - return this; + if (right_side != null) + return var.ResolveLValue (ec, right_side); + else + return var.Resolve (ec); } - - // - // Stage 2 continues here. - // - if (e is TypeExpr) - return e; - - if (ec.OnlyLookupTypes) - return null; - - if (e is FieldExpr){ - FieldExpr fe = (FieldExpr) e; - FieldInfo fi = fe.FieldInfo; - - if (fi.FieldType.IsPointer && !ec.InUnsafe){ - UnsafeError (Location); - } - - if (ec.IsStatic){ - if (!allow_static && !fi.IsStatic){ - Error120 (Location, Name); - return null; - } - } else { - // If we are not in static code and this - // field is not static, set the instance to `this'. - if (!fi.IsStatic) - fe.InstanceExpression = ec.This; - } + if (current_block != null){ + int idx = -1; + Parameter par = null; + Parameters pars = current_block.Parameters; + if (pars != null) + par = pars.GetParameterByName (Name, out idx); - - if (fi is FieldBuilder) { - Const c = TypeManager.LookupConstant ((FieldBuilder) fi); + if (par != null) { + ParameterReference param; - if (c != null) { - object o = c.LookupConstantValue (ec); - object real_value = ((Constant)c.Expr).GetValue (); - return Constantify (real_value, fi.FieldType); - } - } + param = new ParameterReference (pars, idx, Name, loc); - if (fi.IsLiteral) { - Type t = fi.FieldType; - Type decl_type = fi.DeclaringType; - object o; - - if (fi is FieldBuilder) - o = TypeManager.GetValue ((FieldBuilder) fi); + if (right_side != null) + return param.ResolveLValue (ec, right_side); else - o = fi.GetValue (fi); - - if (decl_type.IsSubclassOf (TypeManager.enum_type)) { - Expression enum_member = MemberLookup ( - ec, decl_type, "value__", MemberTypes.Field, - AllBindingFlags, Location); - - Enum en = TypeManager.LookupEnum (decl_type); - - Constant c; - if (en != null) - c = Constantify (o, en.UnderlyingType); - else - c = Constantify (o, enum_member.Type); - - return new EnumConstant (c, decl_type); - } - - Expression exp = Constantify (o, t); + return param.Resolve (ec); } - - return e; } - if (e is PropertyExpr) { - PropertyExpr pe = (PropertyExpr) e; - - if (ec.IsStatic){ - if (allow_static) - return e; + // + // Stage 2: Lookup members + // - return MemberStaticCheck (e); - } else { - // If we are not in static code and this - // field is not static, set the instance to `this'. + // + // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder + // Hence we have two different cases + // - if (!pe.IsStatic) - pe.InstanceExpression = ec.This; - } + DeclSpace lookup_ds = ec.DeclSpace; + do { + if (lookup_ds.TypeBuilder == null) + break; - return e; - } + e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc); + if (e != null) + break; - if (e is EventExpr) { // - // If the event is local to this class, we transform ourselves into - // a FieldExpr + // Classes/structs keep looking, enums break // - EventExpr ee = (EventExpr) e; + if (lookup_ds is TypeContainer) + lookup_ds = ((TypeContainer) lookup_ds).Parent; + else + break; + } while (lookup_ds != null); + + if (e == null && ec.ContainerType != null) + e = MemberLookup (ec, ec.ContainerType, Name, loc); - Expression ml = MemberLookup ( - ec, ec.DeclSpace.TypeBuilder, ee.EventInfo.Name, - MemberTypes.Event, AllBindingFlags, Location); + if (e == null) + return DoResolveType (ec); - if (ml != null) { - MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml); + if (e is TypeExpr) + return e; - if (mi == null) { - // - // If this happens, then we have an event with its own - // accessors and private field etc so there's no need - // to transform ourselves : we should instead flag an error - // - Assign.error70 (ee.EventInfo, Location); - return null; - } + if (e is IMemberExpr) { + e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this); + if (e == null) + return null; - ml = ExprClassFromMemberInfo (ec, mi, Location); - - if (ml == null) { - Report.Error (-200, Location, "Internal error!!"); - return null; - } + IMemberExpr me = e as IMemberExpr; + if (me == null) + return e; - Expression instance_expr; - - FieldInfo fi = ((FieldExpr) ml).FieldInfo; + // This fails if ResolveMemberAccess() was unable to decide whether + // it's a field or a type of the same name. + if (!me.IsStatic && (me.InstanceExpression == null)) + return e; - if (fi.IsStatic) - instance_expr = null; - else { - instance_expr = ec.This; - instance_expr = instance_expr.Resolve (ec); - } - - return MemberAccess.ResolveMemberAccess (ec, ml, instance_expr, Location, null); + if (!me.IsStatic && + TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) { + Error (38, "Cannot access nonstatic member `" + me.Name + "' of " + + "outer type `" + me.DeclaringType + "' via nested type `" + + me.InstanceExpression.Type + "'"); + return null; } + + if (right_side != null) + e = e.DoResolveLValue (ec, right_side); + else + e = e.DoResolve (ec); + + return e; } - - - if (ec.IsStatic){ + + if (ec.IsStatic || ec.IsFieldInitializer){ if (allow_static) return e; - return MemberStaticCheck (e); + return MemberStaticCheck (ec, e); } else return e; } - + public override void Emit (EmitContext ec) { // @@ -3394,20 +3602,31 @@ namespace Mono.CSharp { // find the name as a namespace // - Error (103, Location, "The name `" + Name + + Error (103, "The name `" + Name + "' does not exist in the class `" + ec.DeclSpace.Name + "'"); } + + public override string ToString () + { + return Name; + } } /// /// Fully resolved expression that evaluates to a type /// - public class TypeExpr : Expression { - public TypeExpr (Type t) + public class TypeExpr : Expression, ITypeExpression { + public TypeExpr (Type t, Location l) { Type = t; eclass = ExprClass.Type; + loc = l; + } + + public virtual Expression DoResolveType (EmitContext ec) + { + return this; } override public Expression DoResolve (EmitContext ec) @@ -3417,7 +3636,48 @@ namespace Mono.CSharp { override public void Emit (EmitContext ec) { - throw new Exception ("Implement me"); + throw new Exception ("Should never be called"); + } + + public override string ToString () + { + return Type.ToString (); + } + } + + /// + /// Used to create types from a fully qualified name. These are just used + /// by the parser to setup the core types. A TypeLookupExpression is always + /// classified as a type. + /// + public class TypeLookupExpression : TypeExpr { + string name; + + public TypeLookupExpression (string name) : base (null, Location.Null) + { + this.name = name; + } + + public override Expression DoResolveType (EmitContext ec) + { + if (type == null) + type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null); + return this; + } + + public override Expression DoResolve (EmitContext ec) + { + return DoResolveType (ec); + } + + public override void Emit (EmitContext ec) + { + throw new Exception ("Should never be called"); + } + + public override string ToString () + { + return name; } } @@ -3426,10 +3686,10 @@ namespace Mono.CSharp { /// /// This is a fully resolved expression that evaluates to a type /// - public class MethodGroupExpr : Expression { + public class MethodGroupExpr : Expression, IMemberExpr { public MethodBase [] Methods; - Location loc; Expression instance_expression = null; + bool is_explicit_impl = false; public MethodGroupExpr (MemberInfo [] mi, Location l) { @@ -3459,6 +3719,12 @@ namespace Mono.CSharp { eclass = ExprClass.MethodGroup; type = TypeManager.object_type; } + + public Type DeclaringType { + get { + return Methods [0].DeclaringType; + } + } // // `A method group may have associated an instance expression' @@ -3472,9 +3738,51 @@ namespace Mono.CSharp { instance_expression = value; } } + + public bool IsExplicitImpl { + get { + return is_explicit_impl; + } + + set { + is_explicit_impl = value; + } + } + + public string Name { + get { + return Methods [0].Name; + } + } + + public bool IsInstance { + get { + foreach (MethodBase mb in Methods) + if (!mb.IsStatic) + return true; + + return false; + } + } + + public bool IsStatic { + get { + foreach (MethodBase mb in Methods) + if (mb.IsStatic) + return true; + + return false; + } + } override public Expression DoResolve (EmitContext ec) { + if (instance_expression != null) { + instance_expression = instance_expression.DoResolve (ec); + if (instance_expression == null) + return null; + } + return this; } @@ -3529,10 +3837,9 @@ namespace Mono.CSharp { /// /// Fully resolved expression that evaluates to a Field /// - public class FieldExpr : Expression, IAssignMethod, IMemoryLocation { + public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr { public readonly FieldInfo FieldInfo; - public Expression InstanceExpression; - Location loc; + Expression instance_expr; public FieldExpr (FieldInfo fi, Location l) { @@ -3542,20 +3849,63 @@ namespace Mono.CSharp { loc = l; } + public string Name { + get { + return FieldInfo.Name; + } + } + + public bool IsInstance { + get { + return !FieldInfo.IsStatic; + } + } + + public bool IsStatic { + get { + return FieldInfo.IsStatic; + } + } + + public Type DeclaringType { + get { + return FieldInfo.DeclaringType; + } + } + + public Expression InstanceExpression { + get { + return instance_expr; + } + + set { + instance_expr = value; + } + } + override public Expression DoResolve (EmitContext ec) { if (!FieldInfo.IsStatic){ - if (InstanceExpression == null){ + if (instance_expr == null){ throw new Exception ("non-static FieldExpr without instance var\n" + "You have to assign the Instance variable\n" + "Of the FieldExpr to set this\n"); } - InstanceExpression = InstanceExpression.Resolve (ec); - if (InstanceExpression == null) + // Resolve the field's instance expression while flow analysis is turned + // off: when accessing a field "a.b", we must check whether the field + // "a.b" is initialized, not whether the whole struct "a" is initialized. + instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue | + ResolveFlags.DisableFlowAnalysis); + if (instance_expr == null) return null; } + // If the instance expression is a local variable or parameter. + IVariable var = instance_expr as IVariable; + if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc)) + return null; + return this; } @@ -3575,6 +3925,10 @@ namespace Mono.CSharp { override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { + IVariable var = instance_expr as IVariable; + if (var != null) + var.SetFieldAssigned (ec, FieldInfo.Name); + Expression e = DoResolve (ec); if (e == null) @@ -3599,7 +3953,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; bool is_volatile = false; - + if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); @@ -3615,23 +3969,23 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldsfld, FieldInfo); } else { - if (InstanceExpression.Type.IsValueType){ + if (instance_expr.Type.IsValueType){ IMemoryLocation ml; LocalTemporary tempo = null; - if (!(InstanceExpression is IMemoryLocation)){ + if (!(instance_expr is IMemoryLocation)){ tempo = new LocalTemporary ( - ec, InstanceExpression.Type); + ec, instance_expr.Type); InstanceExpression.Emit (ec); tempo.Store (ec); ml = tempo; } else - ml = (IMemoryLocation) InstanceExpression; + ml = (IMemoryLocation) instance_expr; ml.AddressOf (ec, AddressOp.Load); } else - InstanceExpression.Emit (ec); + instance_expr.Emit (ec); if (is_volatile) ig.Emit (OpCodes.Volatile); @@ -3653,7 +4007,7 @@ namespace Mono.CSharp { } if (!is_static){ - Expression instance = InstanceExpression; + Expression instance = instance_expr; if (instance.Type.IsValueType){ if (instance is IMemoryLocation){ @@ -3713,19 +4067,26 @@ namespace Mono.CSharp { // get the address of the copy. // if (FieldInfo.IsInitOnly){ - LocalBuilder local; + if (ec.IsConstructor) { + ig.Emit (OpCodes.Ldsflda, FieldInfo); + } else { + LocalBuilder local; - Emit (ec); - local = ig.DeclareLocal (type); - ig.Emit (OpCodes.Stloc, local); - ig.Emit (OpCodes.Ldloca, local); + Emit (ec); + local = ig.DeclareLocal (type); + ig.Emit (OpCodes.Stloc, local); + ig.Emit (OpCodes.Ldloca, local); + } return; - } + } if (FieldInfo.IsStatic) ig.Emit (OpCodes.Ldsflda, FieldInfo); else { - InstanceExpression.Emit (ec); + if (instance_expr is IMemoryLocation) + ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore); + else + instance_expr.Emit (ec); ig.Emit (OpCodes.Ldflda, FieldInfo); } } @@ -3738,20 +4099,19 @@ namespace Mono.CSharp { /// This is not an LValue because we need to re-write the expression, we /// can not take data from the stack and store it. /// - public class PropertyExpr : ExpressionStatement, IAssignMethod { + public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr { public readonly PropertyInfo PropertyInfo; - public readonly bool IsStatic; public bool IsBase; MethodInfo [] Accessors; - Location loc; + bool is_static; Expression instance_expr; - + public PropertyExpr (PropertyInfo pi, Location l) { PropertyInfo = pi; eclass = ExprClass.PropertyAccess; - IsStatic = false; + is_static = false; loc = l; Accessors = TypeManager.GetAccessors (pi); @@ -3759,7 +4119,7 @@ namespace Mono.CSharp { foreach (MethodInfo mi in Accessors){ if (mi != null) if (mi.IsStatic) - IsStatic = true; + is_static = true; } else Accessors = new MethodInfo [2]; @@ -3767,6 +4127,30 @@ namespace Mono.CSharp { type = TypeManager.TypeToCoreType (pi.PropertyType); } + public string Name { + get { + return PropertyInfo.Name; + } + } + + public bool IsInstance { + get { + return !is_static; + } + } + + public bool IsStatic { + get { + return is_static; + } + } + + public Type DeclaringType { + get { + return PropertyInfo.DeclaringType; + } + } + // // The instance expression associated with this expression // @@ -3802,7 +4186,35 @@ namespace Mono.CSharp { return null; } - type = PropertyInfo.PropertyType; + if ((instance_expr == null) && ec.IsStatic && !is_static) { + SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name); + return null; + } + + if (instance_expr != null) { + instance_expr = instance_expr.DoResolve (ec); + if (instance_expr == null) + return null; + } + + return this; + } + + override public Expression DoResolveLValue (EmitContext ec, Expression right_side) + { + if (!PropertyInfo.CanWrite){ + Report.Error (154, loc, + "The property `" + PropertyInfo.Name + + "' can not be used in " + + "this context because it lacks a set accessor"); + return null; + } + + if (instance_expr != null) { + instance_expr = instance_expr.DoResolve (ec); + if (instance_expr == null) + return null; + } return this; } @@ -3814,7 +4226,8 @@ namespace Mono.CSharp { // // Special case: length of single dimension array is turned into ldlen // - if (method == TypeManager.int_array_get_length){ + if ((method == TypeManager.system_int_array_get_length) || + (method == TypeManager.int_array_get_length)){ Type iet = instance_expr.Type; // @@ -3854,13 +4267,11 @@ namespace Mono.CSharp { /// /// Fully resolved expression that evaluates to an Event /// - public class EventExpr : Expression { + public class EventExpr : Expression, IMemberExpr { public readonly EventInfo EventInfo; - Location loc; - public Expression InstanceExpression; - - public readonly bool IsStatic; + public Expression instance_expr; + bool is_static; MethodInfo add_accessor, remove_accessor; public EventExpr (EventInfo ei, Location loc) @@ -3873,7 +4284,7 @@ namespace Mono.CSharp { remove_accessor = TypeManager.GetRemoveMethod (ei); if (add_accessor.IsStatic || remove_accessor.IsStatic) - IsStatic = true; + is_static = true; if (EventInfo is MyEventBuilder) type = ((MyEventBuilder) EventInfo).EventType; @@ -3881,15 +4292,54 @@ namespace Mono.CSharp { type = EventInfo.EventHandlerType; } - override public Expression DoResolve (EmitContext ec) + public string Name { + get { + return EventInfo.Name; + } + } + + public bool IsInstance { + get { + return !is_static; + } + } + + public bool IsStatic { + get { + return is_static; + } + } + + public Type DeclaringType { + get { + return EventInfo.DeclaringType; + } + } + + public Expression InstanceExpression { + get { + return instance_expr; + } + + set { + instance_expr = value; + } + } + + public override Expression DoResolve (EmitContext ec) { - // We are born fully resolved + if (instance_expr != null) { + instance_expr = instance_expr.DoResolve (ec); + if (instance_expr == null) + return null; + } + return this; } - override public void Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - throw new Exception ("Should not happen I think"); + Report.Error (70, loc, "The event `" + Name + "' can only appear on the left hand side of += or -= (except on the defining type)"); } public void EmitAddOrRemove (EmitContext ec, Expression source) @@ -3903,10 +4353,10 @@ namespace Mono.CSharp { if (((Binary) source).Oper == Binary.Operator.Addition) Invocation.EmitCall ( - ec, false, IsStatic, InstanceExpression, add_accessor, args, loc); + ec, false, IsStatic, instance_expr, add_accessor, args, loc); else Invocation.EmitCall ( - ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc); + ec, false, IsStatic, instance_expr, remove_accessor, args, loc); } } }