X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=8a3819a3ca7a6b9b4b40350f2dc64ddc252bc69e;hb=876ac0a67e052209908ec57fedf7ad19cdd25d8e;hp=1d79636abe026ccf9086b759eb4fcb959880803b;hpb=5d695895ac88bb265c98faf381026a27bf30b6f3;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 1d79636abe0..8a3819a3ca7 100755 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -54,7 +54,14 @@ namespace Mono.CSharp { // 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 + 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 } // @@ -85,6 +92,42 @@ 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. @@ -98,6 +141,13 @@ namespace Mono.CSharp { get; } + /// + /// Whether this is an instance member. + /// + bool IsInstance { + get; + } + /// /// Whether this is a static member. /// @@ -105,6 +155,13 @@ namespace Mono.CSharp { get; } + /// + /// The type which declares this member. + /// + Type DeclaringType { + get; + } + /// /// The instance expression associated with this member, if it's a /// non-static member. @@ -114,6 +171,17 @@ namespace Mono.CSharp { } } + /// + /// Expression which resolves to a type. + /// + public interface ITypeExpression + { + /// + /// Resolve the expression, but only lookup types. + /// + Expression DoResolveType (EmitContext ec); + } + /// /// Base class for expressions /// @@ -221,13 +289,28 @@ namespace Mono.CSharp { /// public Expression Resolve (EmitContext ec, ResolveFlags flags) { - Expression e; + // Are we doing a types-only search ? + if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) { + ITypeExpression type_expr = this as ITypeExpression; + + if (type_expr == null) + return null; + return type_expr.DoResolveType (ec); + } + + bool old_do_flow_analysis = ec.DoFlowAnalysis; + if ((flags & ResolveFlags.DisableFlowAnalysis) != 0) + ec.DoFlowAnalysis = false; + + Expression e; if (this is SimpleName) e = ((SimpleName) this).DoResolveAllowStatic (ec); else e = DoResolve (ec); + ec.DoFlowAnalysis = old_do_flow_analysis; + if (e == null) return null; @@ -235,10 +318,8 @@ namespace Mono.CSharp { SimpleName s = (SimpleName) e; if ((flags & ResolveFlags.SimpleName) == 0) { - Report.Error ( - 103, loc, - "The name `" + s.Name + "' could not be found in `" + - ec.DeclSpace.Name + "'"); + MemberLookupFailed (ec, null, ec.ContainerType, s.Name, + ec.DeclSpace.Name, loc); return null; } @@ -317,11 +398,8 @@ namespace Mono.CSharp { if (e != null){ if (e is SimpleName){ SimpleName s = (SimpleName) e; - - Report.Error ( - 103, loc, - "The name `" + s.Name + "' could not be found in `" + - ec.DeclSpace.Name + "'"); + MemberLookupFailed (ec, null, ec.ContainerType, s.Name, + ec.DeclSpace.Name, loc); return null; } @@ -423,7 +501,7 @@ namespace Mono.CSharp { else if (mi is FieldInfo) return new FieldExpr ((FieldInfo) mi, loc); else if (mi is PropertyInfo) - return new PropertyExpr ((PropertyInfo) mi, loc); + return new PropertyExpr (ec, (PropertyInfo) mi, loc); else if (mi is Type){ return new TypeExpr ((System.Type) mi, loc); } @@ -459,22 +537,36 @@ namespace Mono.CSharp { // FIXME: Potential optimization, have a static ArrayList // - public static Expression MemberLookup (EmitContext ec, Type t, string name, + public static Expression MemberLookup (EmitContext ec, Type queried_type, string name, MemberTypes mt, BindingFlags bf, Location loc) { - MemberInfo [] mi = TypeManager.MemberLookup (ec.ContainerType, t, mt, bf, name); + return MemberLookup (ec, ec.ContainerType, null, queried_type, name, mt, bf, loc); + } + + // + // Lookup type `queried_type' for code in class `container_type' with a qualifier of + // `qualifier_type' or null to lookup members in the current class. + // + + public static Expression MemberLookup (EmitContext ec, Type container_type, + Type qualifier_type, Type queried_type, + string name, MemberTypes mt, + BindingFlags bf, Location loc) + { + MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type, + queried_type, mt, bf, name); if (mi == null) return null; int count = mi.Length; - if (count > 1) - return new MethodGroupExpr (mi, loc); - if (mi [0] is MethodBase) return new MethodGroupExpr (mi, loc); + if (count > 1) + return null; + return ExprClassFromMemberInfo (ec, mi [0], loc); } @@ -491,14 +583,25 @@ namespace Mono.CSharp { BindingFlags.Static | BindingFlags.Instance; - public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc) + public static Expression MemberLookup (EmitContext ec, Type queried_type, + string name, Location loc) + { + return MemberLookup (ec, ec.ContainerType, null, queried_type, name, + AllMemberTypes, AllBindingFlags, loc); + } + + public static Expression MemberLookup (EmitContext ec, Type qualifier_type, + Type queried_type, string name, Location loc) { - return MemberLookup (ec, t, name, AllMemberTypes, AllBindingFlags, loc); + return MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type, + name, AllMemberTypes, AllBindingFlags, loc); } - public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc) + public static Expression MethodLookup (EmitContext ec, Type queried_type, + string name, Location loc) { - return MemberLookup (ec, t, name, MemberTypes.Method, AllBindingFlags, loc); + return MemberLookup (ec, ec.ContainerType, null, queried_type, name, + MemberTypes.Method, AllBindingFlags, loc); } /// @@ -507,20 +610,24 @@ namespace Mono.CSharp { /// look for private members and display a useful debugging message if we /// find it. /// - public static Expression MemberLookupFinal (EmitContext ec, Type t, string name, - Location loc) + public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type, + Type queried_type, string name, Location loc) { - return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc); + return MemberLookupFinal (ec, qualifier_type, queried_type, name, + AllMemberTypes, AllBindingFlags, loc); } - public static Expression MemberLookupFinal (EmitContext ec, Type t, string name, - MemberTypes mt, BindingFlags bf, Location loc) + public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type, + Type queried_type, string name, + MemberTypes mt, BindingFlags bf, + Location loc) { Expression e; int errors = Report.Errors; - e = MemberLookup (ec, t, name, mt, bf, loc); + e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type, + name, mt, bf, loc); if (e != null) return e; @@ -528,20 +635,63 @@ namespace Mono.CSharp { // Error has already been reported. if (errors < Report.Errors) return null; - - e = MemberLookup (ec, t, name, AllMemberTypes, - AllBindingFlags | BindingFlags.NonPublic, loc); - if (e == null){ + + MemberLookupFailed (ec, qualifier_type, queried_type, name, null, loc); + return null; + } + + public static void MemberLookupFailed (EmitContext ec, Type qualifier_type, + Type queried_type, string name, + string class_name, Location loc) + { + object lookup = TypeManager.MemberLookup (queried_type, null, queried_type, + AllMemberTypes, AllBindingFlags | + BindingFlags.NonPublic, name); + + if (lookup == null) { + if (class_name != null) + Report.Error (103, loc, "The name `" + name + "' could not be " + + "found in `" + class_name + "'"); + else + Report.Error ( + 117, loc, "`" + queried_type + "' does not contain a " + + "definition for `" + name + "'"); + return; + } + + if ((qualifier_type != null) && (qualifier_type != ec.ContainerType) && + ec.ContainerType.IsSubclassOf (qualifier_type)) { + // Although a derived class can access protected members of + // its base class it cannot do so through an instance of the + // base class (CS1540). If the qualifier_type is a parent of the + // ec.ContainerType and the lookup succeeds with the latter one, + // then we are in this situation. + + lookup = TypeManager.MemberLookup ( + ec.ContainerType, ec.ContainerType, ec.ContainerType, + AllMemberTypes, AllBindingFlags, name); + + if (lookup != null) { + Report.Error ( + 1540, loc, "Cannot access protected member `" + + TypeManager.CSharpName (qualifier_type) + "." + + name + "' " + "via a qualifier of type `" + + TypeManager.CSharpName (qualifier_type) + "'; the " + + "qualifier must be of type `" + + TypeManager.CSharpName (ec.ContainerType) + "' " + + "(or derived from it)"); + return; + } + } + + if (qualifier_type != null) Report.Error ( - 117, loc, "`" + t + "' does not contain a definition " + - "for `" + name + "'"); - } else { + 122, loc, "`" + TypeManager.CSharpName (qualifier_type) + "." + + name + "' is inaccessible due to its protection level"); + else Report.Error ( - 122, loc, "`" + t + "." + name + - "' is inaccessible due to its protection level"); - } - - return null; + 122, loc, "`" + name + "' is inaccessible due to its " + + "protection level"); } static public MemberInfo GetFieldFromEvent (EventExpr event_expr) @@ -561,8 +711,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 // @@ -571,9 +725,17 @@ namespace Mono.CSharp { if (expr_type.IsValueType) return new BoxedCast (expr); - if (expr_type.IsClass || expr_type.IsInterface) + if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type) return new EmptyCast (expr, target_type); } else if (expr_type.IsSubclassOf (target_type)) { + // + // Special case: enumeration to System.Enum. + // System.Enum is not a value type, it is a class, so we need + // a boxing conversion + // + if (expr_type.IsEnum) + return new BoxedCast (expr); + return new EmptyCast (expr, target_type); } else { @@ -584,19 +746,20 @@ namespace Mono.CSharp { // from the null type to any reference-type. if (expr is NullLiteral && !target_type.IsValueType) - return new EmptyCast (expr, target_type); + return new NullLiteralTyped (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 @@ -628,12 +791,15 @@ namespace Mono.CSharp { return new EmptyCast (expr, target_type); // from any delegate type to System.Delegate - if (expr_type.IsSubclassOf (TypeManager.delegate_type) && + if ((expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) && target_type == TypeManager.delegate_type) return new EmptyCast (expr, target_type); // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type)) + if (expr_type.IsArray || + expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) if (target_type == TypeManager.icloneable_type) return new EmptyCast (expr, target_type); @@ -644,21 +810,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 (new TypeExpr (target, Location.Null), args, Location.Null); - - return ne.Resolve (ec); - } - /// /// Implicit Numeric Conversions. /// @@ -673,37 +824,29 @@ namespace Mono.CSharp { // // Attempt to do the implicit constant expression conversions - if (expr is IntConstant){ - Expression e; + if (expr is Constant){ - e = TryImplicitIntConversion (target_type, (IntConstant) expr); - - if (e != null) - return e; - } else if (expr is LongConstant && target_type == TypeManager.uint64_type){ - // - // Try the implicit constant expression conversion - // from long to ulong, instead of a nice routine, - // we just inline it - // - long v = ((LongConstant) expr).Value; - if (v > 0) - return new ULongConstant ((ulong) v); + if (expr is IntConstant){ + Expression e; + + e = TryImplicitIntConversion (target_type, (IntConstant) expr); + + if (e != null) + return e; + } else if (expr is LongConstant && target_type == TypeManager.uint64_type){ + // + // Try the implicit constant expression conversion + // from long to ulong, instead of a nice routine, + // we just inline it + // + long v = ((LongConstant) expr).Value; + if (v > 0) + 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); - - if (expr_type == real_target_type) - return new EmptyCast (expr, target_type); + Type real_target_type = target_type; + if (expr_type == TypeManager.sbyte_type){ // // From sbyte to short, int, long, float, double. @@ -718,8 +861,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 @@ -738,8 +879,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 @@ -752,8 +891,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 @@ -771,8 +908,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 @@ -783,8 +918,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 @@ -799,8 +932,6 @@ 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.int64_type){ // // From long/ulong to float, double @@ -809,8 +940,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.uint64_type){ // // From ulong to float, double @@ -821,8 +950,6 @@ 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.char_type){ // // From char to ushort, int, uint, long, ulong, float, double @@ -839,8 +966,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 @@ -864,20 +989,17 @@ namespace Mono.CSharp { // This is the boxed case. // if (target_type == TypeManager.object_type) { - if ((expr_type.IsClass) || - (expr_type.IsValueType) || - (expr_type.IsInterface)) + if (expr_type.IsClass || expr_type.IsValueType || + expr_type.IsInterface || expr_type == TypeManager.enum_type) return true; - } else if (expr_type.IsSubclassOf (target_type)) { return true; - } else { // Please remember that all code below actually comes // 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; } @@ -911,13 +1033,16 @@ namespace Mono.CSharp { return true; // from any delegate type to System.Delegate - if (expr_type.IsSubclassOf (TypeManager.delegate_type) && + if ((expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) && target_type == TypeManager.delegate_type) if (target_type.IsAssignableFrom (expr_type)) return true; // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type)) + if (expr_type.IsArray || + expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) if (target_type == TypeManager.icloneable_type) return true; @@ -947,7 +1072,14 @@ namespace Mono.CSharp { return false; } - + + public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target) + { + Expression dummy = ImplicitUserConversion ( + ec, new EmptyExpression (source), target, Location.Null); + return dummy != null; + } + /// /// Determines if a standard implicit conversion exists from /// expr_type to target_type @@ -955,6 +1087,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; @@ -1111,12 +1246,18 @@ namespace Mono.CSharp { return true; } - if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){ + if ((target_type == TypeManager.enum_type || + target_type.IsSubclassOf (TypeManager.enum_type)) && + expr is IntLiteral){ IntLiteral i = (IntLiteral) expr; if (i.Value == 0) return true; } + + if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) + return true; + return false; } @@ -1196,7 +1337,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) { @@ -1204,10 +1345,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); @@ -1228,16 +1370,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); } } @@ -1249,9 +1389,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); } @@ -1344,7 +1482,7 @@ namespace Mono.CSharp { // if (apply_explicit_conv_rules) return FindMostEncompassedType (tgt_types_set); - else + else return FindMostEncompassingType (tgt_types_set); } @@ -1452,7 +1590,7 @@ namespace Mono.CSharp { MethodGroupExpr union; Type source_type = source.Type; MethodBase method = null; - + union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit); if (union == null) return null; @@ -1466,16 +1604,17 @@ 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){ ParameterData pd = Invocation.GetParameterData (mb); MethodInfo mi = (MethodInfo) mb; @@ -1487,10 +1626,9 @@ namespace Mono.CSharp { } } - if (method == null || count > 1) { - Report.Error (-11, loc, "Ambiguous user defined conversion"); + if (method == null || count > 1) return null; - } + // // This will do the conversion to the best match that we @@ -1513,7 +1651,8 @@ namespace Mono.CSharp { e = ConvertImplicitStandard (ec, e, target, loc); else e = ConvertExplicitStandard (ec, e, target, loc); - } + } + return e; } @@ -1572,12 +1711,14 @@ namespace Mono.CSharp { e = ImplicitReferenceConversion (expr, target_type); if (e != null) return e; - - if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){ + + if ((target_type == TypeManager.enum_type || + target_type.IsSubclassOf (TypeManager.enum_type)) && + expr is IntLiteral){ IntLiteral i = (IntLiteral) expr; if (i.Value == 0) - return new EmptyCast (expr, target_type); + return new EnumConstant ((Constant) expr, target_type); } if (ec.InUnsafe) { @@ -1590,14 +1731,17 @@ namespace Mono.CSharp { // t1 == t2, we have to compare their element types. // if (target_type.IsPointer){ - if (target_type.GetElementType()==expr_type.GetElementType()) + if (target_type.GetElementType() == expr_type.GetElementType()) return expr; } } - if (target_type.IsPointer){ + if (target_type.IsPointer) { if (expr is NullLiteral) return new EmptyCast (expr, target_type); + + if (expr_type == TypeManager.void_ptr_type) + return new EmptyCast (expr, target_type); } } @@ -1613,9 +1757,6 @@ namespace Mono.CSharp { { int value = ic.Value; - // - // FIXME: This could return constants instead of EmptyCasts - // if (target_type == TypeManager.sbyte_type){ if (value >= SByte.MinValue && value <= SByte.MaxValue) return new SByteConstant ((sbyte) value); @@ -1639,11 +1780,26 @@ namespace Mono.CSharp { // if (value >= 0) return new ULongConstant ((ulong) value); - } + } else if (target_type == TypeManager.double_type) + return new DoubleConstant ((double) value); + else if (target_type == TypeManager.float_type) + return new FloatConstant ((float) 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; } @@ -1675,7 +1831,7 @@ namespace Mono.CSharp { "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; @@ -1684,13 +1840,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; @@ -1698,6 +1854,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 @@ -1856,8 +2020,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, @@ -1884,8 +2046,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. @@ -2093,44 +2253,50 @@ namespace Mono.CSharp { Type target_type, Location loc) { Type expr_type = expr.Type; + Type original_expr_type = expr_type; + + if (expr_type.IsSubclassOf (TypeManager.enum_type)){ + if (target_type == TypeManager.enum_type || + target_type == TypeManager.object_type) { + if (expr is EnumConstant) + expr = ((EnumConstant) expr).Child; + // We really need all these casts here .... :-( + expr = new BoxedCast (new EmptyCast (expr, expr_type)); + return new EmptyCast (expr, target_type); + } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType && + target_type.IsSubclassOf (TypeManager.enum_type)) + return new UnboxCast (expr, target_type); + + // + // Notice that we have kept the expr_type unmodified, which is only + // used later on to + if (expr is EnumConstant) + expr = ((EnumConstant) expr).Child; + else + expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)); + expr_type = expr.Type; + } + Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc); if (ne != null) return ne; - ne = ConvertNumericExplicit (ec, expr, target_type); + ne = ConvertNumericExplicit (ec, expr, target_type, loc); if (ne != null) return ne; // // Unboxing conversion. // - if (expr_type == TypeManager.object_type && target_type.IsValueType) - return new UnboxCast (expr, target_type); - - // - // Enum types - // - if (expr_type.IsSubclassOf (TypeManager.enum_type)) { - Expression e; - - // - // FIXME: Is there any reason we should have EnumConstant - // dealt with here instead of just using always the - // UnderlyingSystemType to wrap the type? - // - if (expr is EnumConstant) - e = ((EnumConstant) expr).Child; - else { - e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)); + if (expr_type == TypeManager.object_type && target_type.IsValueType){ + if (expr is NullLiteral){ + Report.Error (37, "Cannot convert null to value type `" + TypeManager.CSharpName (expr_type) + "'"); + return null; } - - Expression t = ConvertImplicit (ec, e, target_type, loc); - if (t != null) - return t; - - return ConvertNumericExplicit (ec, e, target_type); + return new UnboxCast (expr, target_type); } + ne = ConvertReferenceExplicit (expr, target_type); if (ne != null) @@ -2168,7 +2334,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; // @@ -2185,7 +2351,7 @@ namespace Mono.CSharp { if (ne != null) return ne; - Error_CannotConvertType (loc, expr_type, target_type); + Error_CannotConvertType (loc, original_expr_type, target_type); return null; } @@ -2200,7 +2366,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; @@ -2615,7 +2781,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); @@ -2661,6 +2827,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; } @@ -2758,7 +2926,7 @@ namespace Mono.CSharp { /// public class EmptyCast : Expression { protected Expression child; - + public EmptyCast (Expression child, Type return_type) { eclass = child.eclass; @@ -2914,10 +3082,10 @@ namespace Mono.CSharp { public class BoxedCast : EmptyCast { public BoxedCast (Expression expr) - : base (expr, TypeManager.object_type) + : base (expr, TypeManager.object_type) { } - + public override Expression DoResolve (EmitContext ec) { // This should never be invoked, we are born in fully @@ -3267,44 +3435,55 @@ 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; + + // + // If true, then we are a simple name, not composed with a ". + // + bool is_base; + + public SimpleName (string a, string b, Location l) + { + Name = String.Concat (a, ".", b); + loc = l; + is_base = false; + } public SimpleName (string name, Location l) { Name = name; loc = l; + is_base = true; } - public static void Error_ObjectRefRequired (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 IMemberExpr){ IMemberExpr member = (IMemberExpr) e; if (!member.IsStatic){ - Error_ObjectRefRequired (loc, Name); - return null; - } - } else if (e is MethodGroupExpr){ - MethodGroupExpr mg = (MethodGroupExpr) e; - - if (!mg.RemoveInstanceMethods ()){ - Error_ObjectRefRequired (loc, mg.Methods [0].Name); + Error_ObjectRefRequired (ec, loc, Name); return null; } - return e; } return e; @@ -3326,6 +3505,61 @@ namespace Mono.CSharp { return SimpleNameResolve (ec, null, true); } + public Expression DoResolveType (EmitContext ec) + { + DeclSpace ds = ec.DeclSpace; + Namespace ns = ds.Namespace; + Type t; + string alias_value; + + // + // Since we are cheating: we only do the Alias lookup for + // namespaces if the name does not include any dots in it + // + if (ns != null && is_base) + alias_value = ns.LookupAlias (Name); + else + alias_value = null; + + if (ec.ResolvingTypeTree){ + if (alias_value != null){ + if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null) + return new TypeExpr (t, loc); + } + + 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); + } + + // + // First, the using aliases + // + if (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); + } + + // + // Stage 2: Lookup up if we are an alias to a type + // or a namespace. + // + + if ((t = RootContext.LookupType (ds, Name, true, loc)) != null) + return new TypeExpr (t, loc); + + // No match, maybe our parent can compose us + // into something meaningful. + return this; + } + /// /// 7.5.2: Simple Names. /// @@ -3350,128 +3584,97 @@ 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; + Block current_block = ec.CurrentBlock; + if (current_block != null && current_block.GetVariableInfo (Name) != null){ + LocalVariableReference var; + + var = new LocalVariableReference (ec.CurrentBlock, Name, loc); + + if (right_side != null) + return var.ResolveLValue (ec, right_side); + else + return var.Resolve (ec); + } + + 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 (par != null) { + ParameterReference param; - var = new LocalVariableReference (ec.CurrentBlock, Name, loc); + param = new ParameterReference (pars, idx, Name, loc); if (right_side != null) - return var.ResolveLValue (ec, right_side); + return param.ResolveLValue (ec, right_side); else - return var.Resolve (ec); + return param.Resolve (ec); } + } - if (current_block != null){ - int idx = -1; - Parameter par = null; - Parameters pars = current_block.Parameters; - if (pars != null) - par = pars.GetParameterByName (Name, out idx); + // + // Stage 2: Lookup members + // - if (par != null) { - ParameterReference param; - - param = new ParameterReference (pars, idx, Name, loc); + DeclSpace lookup_ds = ec.DeclSpace; + do { + if (lookup_ds.TypeBuilder == null) + break; - if (right_side != null) - return param.ResolveLValue (ec, right_side); - else - return param.Resolve (ec); - } - } + e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc); + if (e != null) + break; - // - // Stage 2: Lookup members - // + lookup_ds =lookup_ds.Parent; + } while (lookup_ds != null); + + if (e == null && ec.ContainerType != null) + e = MemberLookup (ec, ec.ContainerType, Name, loc); - // - // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder - // Hence we have two different cases - // + if (e == null) + return DoResolveType (ec); - DeclSpace lookup_ds = ec.DeclSpace; - do { - if (lookup_ds.TypeBuilder == null) - break; + if (e is TypeExpr) + return e; - e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc); - if (e != null) - break; + if (e is IMemberExpr) { + e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this); + if (e == null) + return null; - // - // 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, loc); - } + IMemberExpr me = e as IMemberExpr; + if (me == null) + return e; - // Continuation of stage 2 - if (e == null){ - // - // Stage 3: Lookup symbol in the various namespaces. - // - DeclSpace ds = ec.DeclSpace; - Type t; - string alias_value; + // 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 ((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); - } - - if (ec.ResolvingTypeTree){ - Type dt = ec.DeclSpace.FindType (Name); - if (dt != null) - return new TypeExpr (dt, loc); + 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; } - - // No match, maybe our parent can compose us - // into something meaningful. - return this; - } - // - // Stage 2 continues here. - // - if (e is TypeExpr) - return e; - - if (ec.OnlyLookupTypes) - return null; + if (right_side != null) + e = e.DoResolveLValue (ec, right_side); + else + e = e.DoResolve (ec); - if (e is IMemberExpr) - return MemberAccess.ResolveMemberAccess (ec, e, null, loc, this); + 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; } @@ -3497,7 +3700,7 @@ namespace Mono.CSharp { /// /// Fully resolved expression that evaluates to a type /// - public class TypeExpr : Expression { + public class TypeExpr : Expression, ITypeExpression { public TypeExpr (Type t, Location l) { Type = t; @@ -3505,6 +3708,11 @@ namespace Mono.CSharp { loc = l; } + public virtual Expression DoResolveType (EmitContext ec) + { + return this; + } + override public Expression DoResolve (EmitContext ec) { return this; @@ -3514,31 +3722,41 @@ namespace Mono.CSharp { { 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 TypeExpression is always + /// by the parser to setup the core types. A TypeLookupExpression is always /// classified as a type. /// - public class TypeExpression : TypeExpr { + public class TypeLookupExpression : TypeExpr { string name; - public TypeExpression (string name) : base (null, Location.Null) + public TypeLookupExpression (string name) : base (null, Location.Null) { this.name = name; } - public override Expression DoResolve (EmitContext ec) + 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"); + throw new Exception ("Should never be called"); } public override string ToString () @@ -3552,9 +3770,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; Expression instance_expression = null; + bool is_explicit_impl = false; public MethodGroupExpr (MemberInfo [] mi, Location l) { @@ -3584,6 +3803,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' @@ -3597,9 +3822,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; } @@ -3672,12 +3939,24 @@ namespace Mono.CSharp { } } + 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; @@ -3692,16 +3971,28 @@ namespace Mono.CSharp { { if (!FieldInfo.IsStatic){ 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"); + // + // This can happen when referencing an instance field using + // a fully qualified type expression: TypeName.InstanceField = xxx + // + SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name); + return null; } - instance_expr = instance_expr.Resolve (ec); + // 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; } @@ -3721,6 +4012,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) @@ -3733,8 +4028,10 @@ namespace Mono.CSharp { // InitOnly fields can only be assigned in constructors // - if (ec.IsConstructor) - return this; + if (ec.IsConstructor){ + if (ec.ContainerType == FieldInfo.DeclaringType) + return this; + } Report_AssignToReadonly (true); @@ -3745,7 +4042,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; bool is_volatile = false; - + if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); @@ -3858,25 +4155,26 @@ namespace Mono.CSharp { // Handle initonly fields specially: make a copy and then // get the address of the copy. // - if (FieldInfo.IsInitOnly){ - if (ec.IsConstructor) { - ig.Emit (OpCodes.Ldsflda, FieldInfo); - } else { - LocalBuilder local; + if (FieldInfo.IsInitOnly && !ec.IsConstructor){ + 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 { - if (instance_expr is IMemoryLocation) - ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore); + // + // In the case of `This', we call the AddressOf method, which will + // only load the pointer, and not perform an Ldobj immediately after + // the value has been loaded into the stack. + // + if (instance_expr is This) + ((This)instance_expr).AddressOf (ec, AddressOp.LoadStore); else instance_expr.Emit (ec); ig.Emit (OpCodes.Ldflda, FieldInfo); @@ -3893,30 +4191,27 @@ namespace Mono.CSharp { /// public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr { public readonly PropertyInfo PropertyInfo; + + // + // This is set externally by the `BaseAccess' class + // public bool IsBase; - MethodInfo [] Accessors; + MethodInfo getter, setter; bool is_static; + bool must_do_cs1540_check; Expression instance_expr; - public PropertyExpr (PropertyInfo pi, Location l) + public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l) { PropertyInfo = pi; eclass = ExprClass.PropertyAccess; is_static = false; loc = l; - Accessors = TypeManager.GetAccessors (pi); - if (Accessors != null) - foreach (MethodInfo mi in Accessors){ - if (mi != null) - if (mi.IsStatic) - is_static = true; - } - else - Accessors = new MethodInfo [2]; - type = TypeManager.TypeToCoreType (pi.PropertyType); + + ResolveAccessors (ec); } public string Name { @@ -3925,12 +4220,24 @@ namespace Mono.CSharp { } } + 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 // @@ -3946,7 +4253,7 @@ namespace Mono.CSharp { public bool VerifyAssignable () { - if (!PropertyInfo.CanWrite){ + if (setter == null) { Report.Error (200, loc, "The property `" + PropertyInfo.Name + "' can not be assigned to, as it has not set accessor"); @@ -3956,29 +4263,204 @@ namespace Mono.CSharp { return true; } + MethodInfo GetAccessor (Type invocation_type, string accessor_name) + { + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | + BindingFlags.Static | BindingFlags.Instance; + MemberInfo[] group; + + group = TypeManager.MemberLookup ( + invocation_type, invocation_type, PropertyInfo.DeclaringType, + MemberTypes.Method, flags, accessor_name + "_" + PropertyInfo.Name); + + // + // The first method is the closest to us + // + if (group == null) + return null; + + foreach (MethodInfo mi in group) { + MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask; + + // + // If only accessible to the current class or children + // + if (ma == MethodAttributes.Private) { + Type declaring_type = mi.DeclaringType; + + if (invocation_type != declaring_type){ + if (TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType)) + return mi; + else + continue; + } else + return mi; + } + // + // FamAndAssem requires that we not only derivate, but we are on the + // same assembly. + // + if (ma == MethodAttributes.FamANDAssem){ + if (mi.DeclaringType.Assembly != invocation_type.Assembly) + continue; + else + return mi; + } + + // Assembly and FamORAssem succeed if we're in the same assembly. + if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){ + if (mi.DeclaringType.Assembly != invocation_type.Assembly) + continue; + else + return mi; + } + + // We already know that we aren't in the same assembly. + if (ma == MethodAttributes.Assembly) + continue; + + // Family and FamANDAssem require that we derive. + if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){ + if (!TypeManager.IsSubclassOrNestedChildOf (invocation_type, mi.DeclaringType)) + continue; + else { + must_do_cs1540_check = true; + + return mi; + } + } + + return mi; + } + + return null; + } + + // + // We also perform the permission checking here, as the PropertyInfo does not + // hold the information for the accessibility of its setter/getter + // + void ResolveAccessors (EmitContext ec) + { + getter = GetAccessor (ec.ContainerType, "get"); + if ((getter != null) && getter.IsStatic) + is_static = true; + + setter = GetAccessor (ec.ContainerType, "set"); + if ((setter != null) && setter.IsStatic) + is_static = true; + + if (setter == null && getter == null){ + Error (122, "`" + PropertyInfo.Name + "' " + + "is inaccessible because of its protection level"); + + } + } + + bool InstanceResolve (EmitContext ec) + { + if ((instance_expr == null) && ec.IsStatic && !is_static) { + SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name); + return false; + } + + if (instance_expr != null) { + instance_expr = instance_expr.DoResolve (ec); + if (instance_expr == null) + return false; + } + + if (must_do_cs1540_check && (instance_expr != null)) { + if ((instance_expr.Type != ec.ContainerType) && + ec.ContainerType.IsSubclassOf (instance_expr.Type)) { + Report.Error (1540, loc, "Cannot access protected member `" + + PropertyInfo.DeclaringType + "." + PropertyInfo.Name + + "' via a qualifier of type `" + + TypeManager.CSharpName (instance_expr.Type) + + "'; the qualifier must be of type `" + + TypeManager.CSharpName (ec.ContainerType) + + "' (or derived from it)"); + return false; + } + } + + return true; + } + override public Expression DoResolve (EmitContext ec) { - if (!PropertyInfo.CanRead){ + if (getter == null){ + // + // The following condition happens if the PropertyExpr was + // created, but is invalid (ie, the property is inaccessible), + // and we did not want to embed the knowledge about this in + // the caller routine. This only avoids double error reporting. + // + if (setter == null) + return null; + Report.Error (154, loc, "The property `" + PropertyInfo.Name + "' can not be used in " + "this context because it lacks a get accessor"); return null; + } + + if (!InstanceResolve (ec)) + return null; + + // + // Only base will allow this invocation to happen. + // + if (IsBase && getter.IsAbstract){ + Report.Error (205, loc, "Cannot call an abstract base property: " + + PropertyInfo.DeclaringType + "." +PropertyInfo.Name); + return null; } - type = PropertyInfo.PropertyType; + return this; + } + + override public Expression DoResolveLValue (EmitContext ec, Expression right_side) + { + if (setter == null){ + // + // The following condition happens if the PropertyExpr was + // created, but is invalid (ie, the property is inaccessible), + // and we did not want to embed the knowledge about this in + // the caller routine. This only avoids double error reporting. + // + if (getter == null) + return null; + + Report.Error (154, loc, + "The property `" + PropertyInfo.Name + + "' can not be used in " + + "this context because it lacks a set accessor"); + return null; + } + if (!InstanceResolve (ec)) + return null; + + // + // Only base will allow this invocation to happen. + // + if (IsBase && setter.IsAbstract){ + Report.Error (205, loc, "Cannot call an abstract base property: " + + PropertyInfo.DeclaringType + "." +PropertyInfo.Name); + return null; + } return this; } override public void Emit (EmitContext ec) { - MethodInfo method = Accessors [0]; - // - // Special case: length of single dimension array is turned into ldlen + // Special case: length of single dimension array property is turned into ldlen // - if (method == TypeManager.int_array_get_length){ + if ((getter == TypeManager.system_int_array_get_length) || + (getter == TypeManager.int_array_get_length)){ Type iet = instance_expr.Type; // @@ -3992,7 +4474,7 @@ namespace Mono.CSharp { } } - Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, method, null, loc); + Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, loc); } @@ -4005,7 +4487,7 @@ namespace Mono.CSharp { ArrayList args = new ArrayList (); args.Add (arg); - Invocation.EmitCall (ec, false, IsStatic, instance_expr, Accessors [1], args, loc); + Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, loc); } override public void EmitStatement (EmitContext ec) @@ -4037,9 +4519,11 @@ namespace Mono.CSharp { if (add_accessor.IsStatic || remove_accessor.IsStatic) is_static = true; - if (EventInfo is MyEventBuilder) - type = ((MyEventBuilder) EventInfo).EventType; - else + if (EventInfo is MyEventBuilder){ + MyEventBuilder eb = (MyEventBuilder) EventInfo; + type = eb.EventType; + eb.SetUsed (); + } else type = EventInfo.EventHandlerType; } @@ -4049,12 +4533,24 @@ namespace Mono.CSharp { } } + 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; @@ -4067,13 +4563,19 @@ namespace Mono.CSharp { 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; } 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)