X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=8a3819a3ca7a6b9b4b40350f2dc64ddc252bc69e;hb=876ac0a67e052209908ec57fedf7ad19cdd25d8e;hp=fdc62db84ff71e6111efe155cb259b152565736b;hpb=5f0e61d090767fe672f0f5178b841df8b624b8b2;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index fdc62db84ff..8a3819a3ca7 100755 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -318,16 +318,8 @@ namespace Mono.CSharp { 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 + "'"); + MemberLookupFailed (ec, null, ec.ContainerType, s.Name, + ec.DeclSpace.Name, loc); return null; } @@ -406,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; } @@ -512,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); } @@ -548,38 +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) { - return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc); + return MemberLookup (ec, ec.ContainerType, null, queried_type, 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)). - // + // 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 invocation_type, Type t, - string name, MemberTypes mt, BindingFlags bf, - Location loc) + 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 (invocation_type, t, mt, bf, name); + 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); } @@ -596,15 +583,24 @@ 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, t, name, + return MemberLookup (ec, ec.ContainerType, null, queried_type, name, AllMemberTypes, AllBindingFlags, loc); } - public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc) + public static Expression MemberLookup (EmitContext ec, Type qualifier_type, + Type queried_type, string name, Location loc) { - return MemberLookup (ec, ec.ContainerType, t, name, + return MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type, + name, AllMemberTypes, AllBindingFlags, loc); + } + + public static Expression MethodLookup (EmitContext ec, Type queried_type, + string name, Location loc) + { + return MemberLookup (ec, ec.ContainerType, null, queried_type, name, MemberTypes.Method, AllBindingFlags, loc); } @@ -614,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, ec.ContainerType, t, name, mt, bf, loc); + e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type, + name, mt, bf, loc); if (e != null) return e; @@ -635,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) @@ -682,11 +725,19 @@ 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)) + } 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 { + } else { // This code is kind of mirrored inside StandardConversionExists // with the small distinction that we only probe there @@ -695,7 +746,7 @@ 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 (target_type.IsInterface) { @@ -740,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); @@ -756,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. /// @@ -785,24 +824,27 @@ 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); + } } - + Type real_target_type = target_type; if (expr_type == TypeManager.sbyte_type){ @@ -819,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 @@ -839,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 @@ -853,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 @@ -872,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 @@ -884,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 @@ -900,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 @@ -910,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 @@ -922,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 @@ -940,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 @@ -965,14 +989,11 @@ 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 @@ -1012,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; @@ -1049,6 +1073,13 @@ 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 @@ -1215,7 +1246,9 @@ 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) @@ -1557,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; @@ -1581,6 +1614,7 @@ namespace Mono.CSharp { int count = 0; + foreach (MethodBase mb in union.Methods){ ParameterData pd = Invocation.GetParameterData (mb); MethodInfo mi = (MethodInfo) mb; @@ -1592,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 @@ -1618,7 +1651,8 @@ namespace Mono.CSharp { e = ConvertImplicitStandard (ec, e, target, loc); else e = ConvertExplicitStandard (ec, e, target, loc); - } + } + return e; } @@ -1677,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) { @@ -1695,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); } } @@ -1718,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); @@ -1744,7 +1780,10 @@ 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)){ Type underlying = TypeManager.EnumToUnderlying (target_type); @@ -1792,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; @@ -1981,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, @@ -2009,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. @@ -2218,6 +2253,30 @@ 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) @@ -2230,32 +2289,14 @@ namespace Mono.CSharp { // // 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, loc); + return new UnboxCast (expr, target_type); } + ne = ConvertReferenceExplicit (expr, target_type); if (ne != null) @@ -2310,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; } @@ -2885,7 +2926,7 @@ namespace Mono.CSharp { /// public class EmptyCast : Expression { protected Expression child; - + public EmptyCast (Expression child, Type return_type) { eclass = child.eclass; @@ -3041,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 @@ -3396,11 +3437,24 @@ namespace Mono.CSharp { /// 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 (EmitContext ec, Location l, string name) @@ -3453,14 +3507,26 @@ namespace Mono.CSharp { public Expression DoResolveType (EmitContext ec) { - // - // Stage 3: Lookup symbol in the various namespaces. - // 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) @@ -3470,27 +3536,24 @@ namespace Mono.CSharp { 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. + // First, the using aliases // - // 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 (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. @@ -3522,7 +3585,7 @@ namespace Mono.CSharp { // Stage 1: Performed by the parser (binding to locals or parameters). // Block current_block = ec.CurrentBlock; - if (current_block != null && current_block.IsVariableDefined (Name)){ + if (current_block != null && current_block.GetVariableInfo (Name) != null){ LocalVariableReference var; var = new LocalVariableReference (ec.CurrentBlock, Name, loc); @@ -3556,11 +3619,6 @@ namespace Mono.CSharp { // 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) @@ -3570,13 +3628,7 @@ namespace Mono.CSharp { if (e != null) break; - // - // Classes/structs keep looking, enums break - // - if (lookup_ds is TypeContainer) - lookup_ds = ((TypeContainer) lookup_ds).Parent; - else - break; + lookup_ds =lookup_ds.Parent; } while (lookup_ds != null); if (e == null && ec.ContainerType != null) @@ -3919,9 +3971,12 @@ 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; } // Resolve the field's instance expression while flow analysis is turned @@ -3973,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); @@ -4098,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); @@ -4133,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 { @@ -4198,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"); @@ -4208,25 +4263,159 @@ namespace Mono.CSharp { return true; } - override public Expression DoResolve (EmitContext ec) + MethodInfo GetAccessor (Type invocation_type, string accessor_name) { - if (!PropertyInfo.CanRead){ - Report.Error (154, loc, - "The property `" + PropertyInfo.Name + - "' can not be used in " + - "this context because it lacks a get accessor"); + 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 null; + 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 (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; } return this; @@ -4234,7 +4423,16 @@ namespace Mono.CSharp { override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { - if (!PropertyInfo.CanWrite){ + 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 " + @@ -4242,24 +4440,27 @@ namespace Mono.CSharp { return null; } - if (instance_expr != null) { - instance_expr = instance_expr.DoResolve (ec); - if (instance_expr == null) - 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.system_int_array_get_length) || - (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; // @@ -4273,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); } @@ -4286,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) @@ -4318,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; } @@ -4366,12 +4569,13 @@ namespace Mono.CSharp { 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)