X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=8a3819a3ca7a6b9b4b40350f2dc64ddc252bc69e;hb=876ac0a67e052209908ec57fedf7ad19cdd25d8e;hp=d99f254dae3b4547068325b7e6c66a044459e5d8;hpb=e5d585c6764e818a2eb9b727911f75796f91104f;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index d99f254dae3..8a3819a3ca7 100755 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -36,6 +36,34 @@ namespace Mono.CSharp { Nothing, } + /// + /// This is used to tell Resolve in which types of expressions we're + /// interested. + /// + [Flags] + public enum ResolveFlags { + // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess. + VariableOrValue = 1, + + // Returns a type expression. + Type = 2, + + // Returns a method group. + MethodGroup = 4, + + // Allows SimpleNames to be returned. + // This is used by MemberAccess to construct long names that can not be + // partially resolved (namespace-qualified names for example). + SimpleName = 8, + + // Mask of all the expression class flags. + MaskExprClass = 15, + + // Disable control flow analysis while resolving the expression. + // This is used when resolving the instance expression of a field expression. + DisableFlowAnalysis = 16 + } + // // This is just as a hint to AddressOf of what will be done with the // address. @@ -64,12 +92,103 @@ namespace Mono.CSharp { void AddressOf (EmitContext ec, AddressOp mode); } + /// + /// This interface is implemented by variables + /// + public interface IVariable { + /// + /// Checks whether the variable has already been assigned at + /// the current position of the method's control flow and + /// reports an appropriate error message if not. + /// + /// If the variable is a struct, then this call checks whether + /// all of its fields (including all private ones) have been + /// assigned. + /// + bool IsAssigned (EmitContext ec, Location loc); + + /// + /// Checks whether field `name' in this struct has been assigned. + /// + bool IsFieldAssigned (EmitContext ec, string name, Location loc); + + /// + /// Tells the flow analysis code that the variable has already + /// been assigned at the current code position. + /// + /// If the variable is a struct, this call marks all its fields + /// (including private fields) as being assigned. + /// + void SetAssigned (EmitContext ec); + + /// + /// Tells the flow analysis code that field `name' in this struct + /// has already been assigned atthe current code position. + /// + void SetFieldAssigned (EmitContext ec, string name); + } + + /// + /// This interface denotes an expression which evaluates to a member + /// of a struct or a class. + /// + public interface IMemberExpr + { + /// + /// The name of this member. + /// + string Name { + get; + } + + /// + /// Whether this is an instance member. + /// + bool IsInstance { + get; + } + + /// + /// Whether this is a static member. + /// + bool IsStatic { + get; + } + + /// + /// The type which declares this member. + /// + Type DeclaringType { + get; + } + + /// + /// The instance expression associated with this member, if it's a + /// non-static member. + /// + Expression InstanceExpression { + get; set; + } + } + + /// + /// Expression which resolves to a type. + /// + public interface ITypeExpression + { + /// + /// Resolve the expression, but only lookup types. + /// + Expression DoResolveType (EmitContext ec); + } + /// /// Base class for expressions /// public abstract class Expression { public ExprClass eclass; - protected Type type; + protected Type type; + protected Location loc; public Type Type { get { @@ -81,25 +200,42 @@ namespace Mono.CSharp { } } + public Location Location { + get { + return loc; + } + } + /// /// Utility wrapper routine for Error, just to beautify the code /// - static protected void Error (int error, string s) + public void Error (int error, string s) { - Report.Error (error, s); + if (!Location.IsNull (loc)) + Report.Error (error, loc, s); + else + Report.Error (error, s); } - static protected void Error (int error, Location loc, string s) + /// + /// Utility wrapper routine for Warning, just to beautify the code + /// + public void Warning (int warning, string s) { - Report.Error (error, loc, s); + if (!Location.IsNull (loc)) + Report.Warning (warning, loc, s); + else + Report.Warning (warning, s); } - + /// - /// Utility wrapper routine for Warning, just to beautify the code + /// Utility wrapper routine for Warning, only prints the warning if + /// warnings of level `level' are enabled. /// - static protected void Warning (int warning, string s) + public void Warning (int warning, int level, string s) { - Report.Warning (warning, s); + if (level <= RootContext.WarningLevel) + Warning (warning, s); } static public void Error_CannotConvertType (Location loc, Type source, Type target) @@ -151,72 +287,102 @@ namespace Mono.CSharp { /// Currently Resolve wraps DoResolve to perform sanity /// checking and assertion checking on what we expect from Resolve. /// - public Expression Resolve (EmitContext ec) + public Expression Resolve (EmitContext ec, ResolveFlags flags) { - Expression e = DoResolve (ec); - - if (e != null){ - - if (e is SimpleName){ - SimpleName s = (SimpleName) e; + // Are we doing a types-only search ? + if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) { + ITypeExpression type_expr = this as ITypeExpression; - Report.Error ( - 103, s.Location, - "The name `" + s.Name + "' could not be found in `" + - ec.DeclSpace.Name + "'"); + if (type_expr == null) return null; - } - - if (e.eclass == ExprClass.Invalid) - throw new Exception ("Expression " + e.GetType () + - " ExprClass is Invalid after resolve"); - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ( - "Expression " + e.GetType () + - " did not set its type after Resolve\n" + - "called from: " + this.GetType ()); + return type_expr.DoResolveType (ec); } - return e; - } + bool old_do_flow_analysis = ec.DoFlowAnalysis; + if ((flags & ResolveFlags.DisableFlowAnalysis) != 0) + ec.DoFlowAnalysis = false; - /// - /// Performs expression resolution and semantic analysis, but - /// allows SimpleNames to be returned. - /// - /// - /// - /// This is used by MemberAccess to construct long names that can not be - /// partially resolved (namespace-qualified names for example). - /// - public Expression ResolveWithSimpleName (EmitContext ec) - { Expression e; - if (this is SimpleName) e = ((SimpleName) this).DoResolveAllowStatic (ec); else e = DoResolve (ec); - if (e != null){ - if (e is SimpleName) - return e; + ec.DoFlowAnalysis = old_do_flow_analysis; - if (e.eclass == ExprClass.Invalid) - throw new Exception ("Expression " + e + - " ExprClass is Invalid after resolve"); + if (e == null) + return null; + + if (e is SimpleName){ + SimpleName s = (SimpleName) e; + + if ((flags & ResolveFlags.SimpleName) == 0) { + MemberLookupFailed (ec, null, ec.ContainerType, s.Name, + ec.DeclSpace.Name, loc); + return null; + } + + return s; + } + + if ((e is TypeExpr) || (e is ComposedCast)) { + if ((flags & ResolveFlags.Type) == 0) { + e.Error118 (flags); + return null; + } + + return e; + } + + switch (e.eclass) { + case ExprClass.Type: + if ((flags & ResolveFlags.VariableOrValue) == 0) { + e.Error118 (flags); + return null; + } + break; + + case ExprClass.MethodGroup: + if ((flags & ResolveFlags.MethodGroup) == 0) { + ((MethodGroupExpr) e).ReportUsageError (); + return null; + } + break; + + case ExprClass.Value: + case ExprClass.Variable: + case ExprClass.PropertyAccess: + case ExprClass.EventAccess: + case ExprClass.IndexerAccess: + if ((flags & ResolveFlags.VariableOrValue) == 0) { + e.Error118 (flags); + return null; + } + break; - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); + default: + throw new Exception ("Expression " + e.GetType () + + " ExprClass is Invalid after resolve"); } + if (e.type == null) + throw new Exception ( + "Expression " + e.GetType () + + " did not set its type after Resolve\n" + + "called from: " + this.GetType ()); + return e; } - + + /// + /// Resolves an expression and performs semantic analysis on it. + /// + public Expression Resolve (EmitContext ec) + { + return Resolve (ec, ResolveFlags.VariableOrValue); + } + /// /// Resolves an expression for LValue assignment /// @@ -232,11 +398,8 @@ namespace Mono.CSharp { if (e != null){ if (e is SimpleName){ SimpleName s = (SimpleName) e; - - Report.Error ( - 103, s.Location, - "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; } @@ -244,10 +407,14 @@ namespace Mono.CSharp { throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve"); - if (e.eclass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); + if (e.eclass == ExprClass.MethodGroup) { + ((MethodGroupExpr) e).ReportUsageError (); + return null; + } + + if (e.type == null) + throw new Exception ("Expression " + e + + " did not set its type after Resolve"); } return e; @@ -334,9 +501,9 @@ 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); + return new TypeExpr ((System.Type) mi, loc); } return null; @@ -370,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); } @@ -402,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); } /// @@ -418,36 +610,96 @@ 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; - e = MemberLookup (ec, t, name, mt, bf, loc); + int errors = Report.Errors; + + e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type, + name, mt, bf, loc); if (e != null) return e; - - e = MemberLookup (ec, t, name, AllMemberTypes, - AllBindingFlags | BindingFlags.NonPublic, loc); - if (e == null){ + + // Error has already been reported. + if (errors < Report.Errors) + return 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) + { + EventInfo ei = event_expr.EventInfo; + + return TypeManager.GetPrivateFieldOfEvent (ei); + } static EmptyExpression MyEmptyExpr; static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) @@ -459,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 // @@ -469,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 { @@ -482,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 @@ -526,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); @@ -542,22 +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 (target.FullName, args, - new Location (-1)); - - return ne.Resolve (ec); - } - /// /// Implicit Numeric Conversions. /// @@ -572,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. @@ -617,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 @@ -637,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 @@ -651,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 @@ -670,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 @@ -682,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 @@ -698,21 +932,24 @@ namespace Mono.CSharp { if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)){ + } else if (expr_type == TypeManager.int64_type){ // // From long/ulong to float, double // + if (real_target_type == TypeManager.double_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (real_target_type == TypeManager.float_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + } else if (expr_type == TypeManager.uint64_type){ + // + // From ulong to float, double + // if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); - if (real_target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.char_type){ // // From char to ushort, int, uint, long, ulong, float, double @@ -729,8 +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 @@ -754,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; } @@ -801,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; @@ -837,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 @@ -845,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; @@ -1001,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; } @@ -1086,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) { @@ -1094,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); @@ -1118,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); } } @@ -1139,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); } @@ -1234,7 +1482,7 @@ namespace Mono.CSharp { // if (apply_explicit_conv_rules) return FindMostEncompassedType (tgt_types_set); - else + else return FindMostEncompassingType (tgt_types_set); } @@ -1342,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; @@ -1356,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; @@ -1377,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 @@ -1397,13 +1645,14 @@ namespace Mono.CSharp { return null; Expression e; - e = new UserCast ((MethodInfo) method, source); + e = new UserCast ((MethodInfo) method, source, loc); if (e.Type != target){ if (!look_for_explicit) e = ConvertImplicitStandard (ec, e, target, loc); else e = ConvertExplicitStandard (ec, e, target, loc); - } + } + return e; } @@ -1462,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) { @@ -1480,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); } } @@ -1503,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); @@ -1529,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; } @@ -1543,7 +1809,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (source) + "' to `" + TypeManager.CSharpName (target) + "'"; - Error (29, loc, msg); + Report.Error (29, loc, msg); } /// @@ -1561,11 +1827,11 @@ namespace Mono.CSharp { return e; if (source is DoubleLiteral && target_type == TypeManager.float_type){ - Error (664, loc, - "Double literal cannot be implicitly converted to " + - "float type, use F suffix to create a float literal"); + Report.Error (664, loc, + "Double literal cannot be implicitly converted to " + + "float type, use F suffix to create a float literal"); } - + Error_CannotConvertImplicit (loc, source.Type, target_type); return null; @@ -1574,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; @@ -1588,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 @@ -1746,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, @@ -1774,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. @@ -1983,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) @@ -2058,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; // @@ -2075,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; } @@ -2090,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; @@ -2132,17 +2408,52 @@ namespace Mono.CSharp { /// /// Reports that we were expecting `expr' to be of class `expected' /// - protected void report118 (Location loc, Expression expr, string expected) + public void Error118 (string expected) { string kind = "Unknown"; - if (expr != null) - kind = ExprClassName (expr.eclass); + kind = ExprClassName (eclass); - Error (118, loc, "Expression denotes a `" + kind + + Error (118, "Expression denotes a `" + kind + "' where a `" + expected + "' was expected"); } + public void Error118 (ResolveFlags flags) + { + ArrayList valid = new ArrayList (10); + + if ((flags & ResolveFlags.VariableOrValue) != 0) { + valid.Add ("variable"); + valid.Add ("value"); + } + + if ((flags & ResolveFlags.Type) != 0) + valid.Add ("type"); + + if ((flags & ResolveFlags.MethodGroup) != 0) + valid.Add ("method group"); + + if ((flags & ResolveFlags.SimpleName) != 0) + valid.Add ("simple name"); + + if (valid.Count == 0) + valid.Add ("unknown"); + + StringBuilder sb = new StringBuilder (); + for (int i = 0; i < valid.Count; i++) { + if (i > 0) + sb.Append (", "); + else if (i == valid.Count) + sb.Append (" or "); + sb.Append (valid [i]); + } + + string kind = ExprClassName (eclass); + + Error (119, "Expression denotes a `" + kind + "' where " + + "a `" + sb.ToString () + "' was expected"); + } + static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t) { Report.Error (31, l, "Constant value `" + val + "' cannot be converted to " + @@ -2470,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); @@ -2499,6 +2810,7 @@ namespace Mono.CSharp { // public static int GetTypeSize (Type t) { + t = TypeManager.TypeToCoreType (t); if (t == TypeManager.int32_type || t == TypeManager.uint32_type || t == TypeManager.float_type) @@ -2515,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; } @@ -2525,6 +2839,59 @@ namespace Mono.CSharp { public void CacheTemporaries (EmitContext ec) { } + + static void Error_NegativeArrayIndex (Location loc) + { + Report.Error (284, loc, "Can not create array with a negative size"); + } + + // + // Converts `source' to an int, uint, long or ulong. + // + public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc) + { + Expression target; + + bool old_checked = ec.CheckState; + ec.CheckState = true; + + target = ConvertImplicit (ec, source, TypeManager.int32_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.int64_type, loc); + if (target == null){ + target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc); + if (target == null) + Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type); + } + } + } + ec.CheckState = old_checked; + + // + // Only positive constants are allowed at compile time + // + if (target is Constant){ + if (target is IntConstant){ + if (((IntConstant) target).Value < 0){ + Error_NegativeArrayIndex (loc); + return null; + } + } + + if (target is LongConstant){ + if (((LongConstant) target).Value < 0){ + Error_NegativeArrayIndex (loc); + return null; + } + } + + } + + return target; + } + } /// @@ -2559,7 +2926,7 @@ namespace Mono.CSharp { /// public class EmptyCast : Expression { protected Expression child; - + public EmptyCast (Expression child, Type return_type) { eclass = child.eclass; @@ -2715,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 @@ -3068,53 +3435,53 @@ namespace Mono.CSharp { /// The downside of this is that we might be hitting `LookupType' too many /// times with this scheme. /// - public class SimpleName : Expression { + public class SimpleName : Expression, ITypeExpression { public readonly string Name; - public readonly Location Location; + + // + // 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; - Location = l; + loc = l; + is_base = true; } - public static void Error120 (Location l, string name) + public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name) { - Report.Error ( - 120, l, - "An object reference is required " + - "for the non-static field `"+name+"'"); + if (ec.IsFieldInitializer) + Report.Error ( + 236, l, + "A field initializer cannot reference the non-static field, " + + "method or property `"+name+"'"); + else + Report.Error ( + 120, l, + "An object reference is required " + + "for the non-static field `"+name+"'"); } // // Checks whether we are trying to access an instance // property, method or field from a static body. // - Expression MemberStaticCheck (Expression e) + Expression MemberStaticCheck (EmitContext ec, Expression e) { - if (e is FieldExpr){ - FieldInfo fi = ((FieldExpr) e).FieldInfo; + if (e is IMemberExpr){ + IMemberExpr member = (IMemberExpr) e; - if (!fi.IsStatic){ - Error120 (Location, Name); - return null; - } - } else if (e is MethodGroupExpr){ - MethodGroupExpr mg = (MethodGroupExpr) e; - - if (!mg.RemoveInstanceMethods ()){ - Error120 (Location, mg.Methods [0].Name); - return null; - } - return e; - } else if (e is PropertyExpr){ - if (!((PropertyExpr) e).IsStatic){ - Error120 (Location, Name); - return null; - } - } else if (e is EventExpr) { - if (!((EventExpr) e).IsStatic) { - Error120 (Location, Name); + if (!member.IsStatic){ + Error_ObjectRefRequired (ec, loc, Name); return null; } } @@ -3138,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. /// @@ -3162,233 +3584,101 @@ namespace Mono.CSharp { // // Stage 1: Performed by the parser (binding to locals or parameters). // - if (!ec.OnlyLookupTypes){ - Block current_block = ec.CurrentBlock; - if (current_block != null && current_block.IsVariableDefined (Name)){ - LocalVariableReference var; - - var = new LocalVariableReference (ec.CurrentBlock, Name, Location); + Block current_block = ec.CurrentBlock; + if (current_block != null && current_block.GetVariableInfo (Name) != null){ + LocalVariableReference var; - if (right_side != null) - return var.ResolveLValue (ec, right_side); - else - return var.Resolve (ec); - } - - // - // Stage 2: Lookup members - // - - // - // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder - // Hence we have two different cases - // + var = new LocalVariableReference (ec.CurrentBlock, Name, loc); - DeclSpace lookup_ds = ec.DeclSpace; - do { - if (lookup_ds.TypeBuilder == null) - break; - - e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, Location); - if (e != null) - break; - - // - // Classes/structs keep looking, enums break - // - if (lookup_ds is TypeContainer) - lookup_ds = ((TypeContainer) lookup_ds).Parent; - else - break; - } while (lookup_ds != null); - - if (e == null && ec.ContainerType != null) - e = MemberLookup (ec, ec.ContainerType, Name, Location); + if (right_side != null) + return var.ResolveLValue (ec, right_side); + else + return var.Resolve (ec); } - // Continuation of stage 2 - if (e == null){ - // - // Stage 3: Lookup symbol in the various namespaces. - // - DeclSpace ds = ec.DeclSpace; - Type t; - string alias_value; + 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 ((t = RootContext.LookupType (ds, Name, true, Location)) != null) - return new TypeExpr (t); - - // - // Stage 2 part b: Lookup up if we are an alias to a type - // or a namespace. - // - // Since we are cheating: we only do the Alias lookup for - // namespaces if the name does not include any dots in it - // - - if (Name.IndexOf ('.') == -1 && (alias_value = ec.TypeContainer.LookupAlias (Name)) != null) { - // System.Console.WriteLine (Name + " --> " + alias_value); - if ((t = RootContext.LookupType (ds, alias_value, true, Location)) - != null) - return new TypeExpr (t); + if (par != null) { + ParameterReference param; - // we have alias value, but it isn't Type, so try if it's namespace - return new SimpleName (alias_value, Location); + param = new ParameterReference (pars, idx, Name, loc); + + if (right_side != null) + return param.ResolveLValue (ec, right_side); + else + return param.Resolve (ec); } - - // 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 (e is FieldExpr){ - FieldExpr fe = (FieldExpr) e; - FieldInfo fi = fe.FieldInfo; + // + // Stage 2: Lookup members + // - if (fi.FieldType.IsPointer && !ec.InUnsafe){ - UnsafeError (Location); - } - - if (ec.IsStatic){ - if (!allow_static && !fi.IsStatic){ - Error120 (Location, Name); - return null; - } - } else { - // If we are not in static code and this - // field is not static, set the instance to `this'. + DeclSpace lookup_ds = ec.DeclSpace; + do { + if (lookup_ds.TypeBuilder == null) + break; - if (!fi.IsStatic) - fe.InstanceExpression = ec.This; - } + e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc); + if (e != null) + break; + lookup_ds =lookup_ds.Parent; + } while (lookup_ds != null); - if (fi is FieldBuilder) { - Const c = TypeManager.LookupConstant ((FieldBuilder) fi); - - if (c != null) { - object o = c.LookupConstantValue (ec); - object real_value = ((Constant)c.Expr).GetValue (); - return Constantify (real_value, fi.FieldType); - } - } + if (e == null && ec.ContainerType != null) + e = MemberLookup (ec, ec.ContainerType, Name, loc); - if (fi.IsLiteral) { - Type t = fi.FieldType; - Type decl_type = fi.DeclaringType; - object o; + if (e == null) + return DoResolveType (ec); - if (fi is FieldBuilder) - o = TypeManager.GetValue ((FieldBuilder) fi); - else - o = fi.GetValue (fi); - - if (decl_type.IsSubclassOf (TypeManager.enum_type)) { - Expression enum_member = MemberLookup ( - ec, decl_type, "value__", MemberTypes.Field, - AllBindingFlags, Location); - - Enum en = TypeManager.LookupEnum (decl_type); - - Constant c; - if (en != null) - c = Constantify (o, en.UnderlyingType); - else - c = Constantify (o, enum_member.Type); - - return new EnumConstant (c, decl_type); - } - - Expression exp = Constantify (o, t); - } - + if (e is TypeExpr) return e; - } - if (e is PropertyExpr) { - PropertyExpr pe = (PropertyExpr) e; + if (e is IMemberExpr) { + e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this); + if (e == null) + return null; - if (ec.IsStatic){ - if (allow_static) - return e; + IMemberExpr me = e as IMemberExpr; + if (me == null) + return e; - return MemberStaticCheck (e); - } else { - // If we are not in static code and this - // field is not static, set the instance to `this'. + // 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 (!pe.IsStatic) - pe.InstanceExpression = ec.This; + 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; } - return e; - } - - if (e is EventExpr) { - // - // If the event is local to this class, we transform ourselves into - // a FieldExpr - // - EventExpr ee = (EventExpr) e; - - Expression ml = MemberLookup ( - ec, ec.DeclSpace.TypeBuilder, ee.EventInfo.Name, - MemberTypes.Event, AllBindingFlags, Location); - - if (ml != null) { - MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml); - - if (mi == null) { - // - // If this happens, then we have an event with its own - // accessors and private field etc so there's no need - // to transform ourselves : we should instead flag an error - // - Assign.error70 (ee.EventInfo, Location); - return null; - } - - ml = ExprClassFromMemberInfo (ec, mi, Location); - - if (ml == null) { - Report.Error (-200, Location, "Internal error!!"); - return null; - } - - Expression instance_expr; - - FieldInfo fi = ((FieldExpr) ml).FieldInfo; + if (right_side != null) + e = e.DoResolveLValue (ec, right_side); + else + e = e.DoResolve (ec); - if (fi.IsStatic) - instance_expr = null; - else { - instance_expr = ec.This; - instance_expr = instance_expr.Resolve (ec); - } - - return MemberAccess.ResolveMemberAccess (ec, ml, instance_expr, Location, null); - } + return e; } - - - if (ec.IsStatic){ + + if (ec.IsStatic || ec.IsFieldInitializer){ if (allow_static) return e; - return MemberStaticCheck (e); + return MemberStaticCheck (ec, e); } else return e; } - + public override void Emit (EmitContext ec) { // @@ -3396,20 +3686,31 @@ namespace Mono.CSharp { // find the name as a namespace // - Error (103, Location, "The name `" + Name + + Error (103, "The name `" + Name + "' does not exist in the class `" + ec.DeclSpace.Name + "'"); } + + public override string ToString () + { + return Name; + } } /// /// Fully resolved expression that evaluates to a type /// - public class TypeExpr : Expression { - public TypeExpr (Type t) + public class TypeExpr : Expression, ITypeExpression { + public TypeExpr (Type t, Location l) { Type = t; eclass = ExprClass.Type; + loc = l; + } + + public virtual Expression DoResolveType (EmitContext ec) + { + return this; } override public Expression DoResolve (EmitContext ec) @@ -3419,7 +3720,48 @@ namespace Mono.CSharp { override public void Emit (EmitContext ec) { - throw new Exception ("Implement me"); + throw new Exception ("Should never be called"); + } + + public override string ToString () + { + return Type.ToString (); + } + } + + /// + /// Used to create types from a fully qualified name. These are just used + /// by the parser to setup the core types. A TypeLookupExpression is always + /// classified as a type. + /// + public class TypeLookupExpression : TypeExpr { + string name; + + public TypeLookupExpression (string name) : base (null, Location.Null) + { + this.name = name; + } + + public override Expression DoResolveType (EmitContext ec) + { + if (type == null) + type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null); + return this; + } + + public override Expression DoResolve (EmitContext ec) + { + return DoResolveType (ec); + } + + public override void Emit (EmitContext ec) + { + throw new Exception ("Should never be called"); + } + + public override string ToString () + { + return name; } } @@ -3428,10 +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; - Location loc; Expression instance_expression = null; + bool is_explicit_impl = false; public MethodGroupExpr (MemberInfo [] mi, Location l) { @@ -3461,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' @@ -3474,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; } @@ -3531,10 +3921,9 @@ namespace Mono.CSharp { /// /// Fully resolved expression that evaluates to a Field /// - public class FieldExpr : Expression, IAssignMethod, IMemoryLocation { + public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr { public readonly FieldInfo FieldInfo; - public Expression InstanceExpression; - Location loc; + Expression instance_expr; public FieldExpr (FieldInfo fi, Location l) { @@ -3544,20 +3933,66 @@ namespace Mono.CSharp { loc = l; } + public string Name { + get { + return FieldInfo.Name; + } + } + + public bool IsInstance { + get { + return !FieldInfo.IsStatic; + } + } + + public bool IsStatic { + get { + return FieldInfo.IsStatic; + } + } + + public Type DeclaringType { + get { + return FieldInfo.DeclaringType; + } + } + + public Expression InstanceExpression { + get { + return instance_expr; + } + + set { + instance_expr = value; + } + } + override public Expression DoResolve (EmitContext ec) { if (!FieldInfo.IsStatic){ - if (InstanceExpression == null){ - 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"); + if (instance_expr == null){ + // + // 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; } - InstanceExpression = InstanceExpression.Resolve (ec); - if (InstanceExpression == null) + // Resolve the field's instance expression while flow analysis is turned + // off: when accessing a field "a.b", we must check whether the field + // "a.b" is initialized, not whether the whole struct "a" is initialized. + instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue | + ResolveFlags.DisableFlowAnalysis); + if (instance_expr == null) return null; } + // If the instance expression is a local variable or parameter. + IVariable var = instance_expr as IVariable; + if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc)) + return null; + return this; } @@ -3577,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) @@ -3589,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); @@ -3601,7 +4042,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; bool is_volatile = false; - + if (FieldInfo is FieldBuilder){ FieldBase f = TypeManager.GetField (FieldInfo); @@ -3617,23 +4058,23 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldsfld, FieldInfo); } else { - if (InstanceExpression.Type.IsValueType){ + if (instance_expr.Type.IsValueType){ IMemoryLocation ml; LocalTemporary tempo = null; - if (!(InstanceExpression is IMemoryLocation)){ + if (!(instance_expr is IMemoryLocation)){ tempo = new LocalTemporary ( - ec, InstanceExpression.Type); + ec, instance_expr.Type); InstanceExpression.Emit (ec); tempo.Store (ec); ml = tempo; } else - ml = (IMemoryLocation) InstanceExpression; + ml = (IMemoryLocation) instance_expr; ml.AddressOf (ec, AddressOp.Load); } else - InstanceExpression.Emit (ec); + instance_expr.Emit (ec); if (is_volatile) ig.Emit (OpCodes.Volatile); @@ -3655,7 +4096,7 @@ namespace Mono.CSharp { } if (!is_static){ - Expression instance = InstanceExpression; + Expression instance = instance_expr; if (instance.Type.IsValueType){ if (instance is IMemoryLocation){ @@ -3714,7 +4155,7 @@ namespace Mono.CSharp { // Handle initonly fields specially: make a copy and then // get the address of the copy. // - if (FieldInfo.IsInitOnly){ + if (FieldInfo.IsInitOnly && !ec.IsConstructor){ LocalBuilder local; Emit (ec); @@ -3722,12 +4163,20 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Stloc, local); ig.Emit (OpCodes.Ldloca, local); return; - } + } if (FieldInfo.IsStatic) ig.Emit (OpCodes.Ldsflda, FieldInfo); else { - InstanceExpression.Emit (ec); + // + // 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); } } @@ -3740,33 +4189,53 @@ namespace Mono.CSharp { /// This is not an LValue because we need to re-write the expression, we /// can not take data from the stack and store it. /// - public class PropertyExpr : ExpressionStatement, IAssignMethod { + public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr { public readonly PropertyInfo PropertyInfo; - public readonly bool IsStatic; + + // + // This is set externally by the `BaseAccess' class + // public bool IsBase; - MethodInfo [] Accessors; - Location loc; + 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; - IsStatic = false; + is_static = false; loc = l; - Accessors = TypeManager.GetAccessors (pi); - if (Accessors != null) - foreach (MethodInfo mi in Accessors){ - if (mi != null) - if (mi.IsStatic) - IsStatic = true; - } - else - Accessors = new MethodInfo [2]; - type = TypeManager.TypeToCoreType (pi.PropertyType); + + ResolveAccessors (ec); + } + + public string Name { + get { + return PropertyInfo.Name; + } + } + + public bool IsInstance { + get { + return !is_static; + } + } + + public bool IsStatic { + get { + return is_static; + } + } + + public Type DeclaringType { + get { + return PropertyInfo.DeclaringType; + } } // @@ -3784,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"); @@ -3794,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; // @@ -3830,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); } @@ -3843,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) @@ -3856,13 +4500,11 @@ namespace Mono.CSharp { /// /// Fully resolved expression that evaluates to an Event /// - public class EventExpr : Expression { + public class EventExpr : Expression, IMemberExpr { public readonly EventInfo EventInfo; - Location loc; - public Expression InstanceExpression; - - public readonly bool IsStatic; + public Expression instance_expr; + bool is_static; MethodInfo add_accessor, remove_accessor; public EventExpr (EventInfo ei, Location loc) @@ -3875,23 +4517,65 @@ namespace Mono.CSharp { remove_accessor = TypeManager.GetRemoveMethod (ei); if (add_accessor.IsStatic || remove_accessor.IsStatic) - IsStatic = true; + is_static = true; - if (EventInfo is MyEventBuilder) - type = ((MyEventBuilder) EventInfo).EventType; - else + if (EventInfo is MyEventBuilder){ + MyEventBuilder eb = (MyEventBuilder) EventInfo; + type = eb.EventType; + eb.SetUsed (); + } else type = EventInfo.EventHandlerType; } - override public Expression DoResolve (EmitContext ec) + public string Name { + get { + return EventInfo.Name; + } + } + + public bool IsInstance { + get { + return !is_static; + } + } + + public bool IsStatic { + get { + return is_static; + } + } + + public Type DeclaringType { + get { + return EventInfo.DeclaringType; + } + } + + public Expression InstanceExpression { + get { + return instance_expr; + } + + set { + instance_expr = value; + } + } + + public override Expression DoResolve (EmitContext ec) { - // We are born fully resolved + if (instance_expr != null) { + instance_expr = instance_expr.DoResolve (ec); + if (instance_expr == null) + return null; + } + + return this; } - override public void Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - throw new Exception ("Should not happen I think"); + Report.Error (70, loc, "The event `" + Name + "' can only appear on the left hand side of += or -= (except on the defining type)"); } public void EmitAddOrRemove (EmitContext ec, Expression source) @@ -3905,10 +4589,10 @@ namespace Mono.CSharp { if (((Binary) source).Oper == Binary.Operator.Addition) Invocation.EmitCall ( - ec, false, IsStatic, InstanceExpression, add_accessor, args, loc); + ec, false, IsStatic, instance_expr, add_accessor, args, loc); else Invocation.EmitCall ( - ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc); + ec, false, IsStatic, instance_expr, remove_accessor, args, loc); } } }