X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fecore.cs;h=c0bf5f2dce26a71c230aa99d5320e12f8df05126;hb=8d8a05805dae1ef9651003da0a0adf39724ad84f;hp=2ea1b81fa57d3201b4da9d1fa0ddb6c72c66ba4c;hpb=62c576c2b65b0de6a2c4944085c1ef8d1b13fcae;p=mono.git diff --git a/mcs/mcs/ecore.cs b/mcs/mcs/ecore.cs index 2ea1b81fa57..c0bf5f2dce2 100755 --- a/mcs/mcs/ecore.cs +++ b/mcs/mcs/ecore.cs @@ -8,7 +8,7 @@ // // -namespace CIR { +namespace Mono.CSharp { using System; using System.Collections; using System.Diagnostics; @@ -16,13 +16,13 @@ namespace CIR { using System.Reflection.Emit; using System.Text; - // - // The ExprClass class contains the is used to pass the - // classification of an expression (value, variable, namespace, - // type, method group, property access, event access, indexer access, - // nothing). - // - public enum ExprClass { + /// + /// The ExprClass class contains the is used to pass the + /// classification of an expression (value, variable, namespace, + /// type, method group, property access, event access, indexer access, + /// nothing). + /// + public enum ExprClass : byte { Invalid, Value, @@ -36,37 +36,22 @@ namespace CIR { Nothing, } - // - // An interface provided by expressions that can be used as - // LValues and can store the value on the top of the stack on - // their storage - // - public interface IStackStore { - - // - // The Store method should store the contents of the top - // of the stack into the storage that is implemented by - // the particular implementation of LValue - // - void Store (EmitContext ec); - } - - // - // This interface is implemented by variables - // + /// + /// This interface is implemented by variables + /// public interface IMemoryLocation { - // - // The AddressOf method should generate code that loads - // the address of the object and leaves it on the stack - // + /// + /// The AddressOf method should generate code that loads + /// the address of the object and leaves it on the stack + /// void AddressOf (EmitContext ec); } - // - // Base class for expressions - // + /// + /// Base class for expressions + /// public abstract class Expression { - protected ExprClass eclass; + public ExprClass eclass; protected Type type; public Type Type { @@ -79,19 +64,9 @@ namespace CIR { } } - public ExprClass ExprClass { - get { - return eclass; - } - - set { - eclass = value; - } - } - - // - // Utility wrapper routine for Error, just to beautify the code - // + /// + /// Utility wrapper routine for Error, just to beautify the code + /// static protected void Error (int error, string s) { Report.Error (error, s); @@ -102,42 +77,48 @@ namespace CIR { Report.Error (error, loc, s); } - // - // Utility wrapper routine for Warning, just to beautify the code - // + /// + /// Utility wrapper routine for Warning, just to beautify the code + /// static protected void Warning (int warning, string s) { Report.Warning (warning, s); } - // - // Performs semantic analysis on the Expression - // - // - // - // The Resolve method is invoked to perform the semantic analysis - // on the node. - // - // The return value is an expression (it can be the - // same expression in some cases) or a new - // expression that better represents this node. - // - // For example, optimizations of Unary (LiteralInt) - // would return a new LiteralInt with a negated - // value. - // - // If there is an error during semantic analysis, - // then an error should be reported (using Report) - // and a null value should be returned. - // - // There are two side effects expected from calling - // Resolve(): the the field variable "eclass" should - // be set to any value of the enumeration - // `ExprClass' and the type variable should be set - // to a valid type (this is the type of the - // expression). - // - + static public void error30 (Location loc, Type source, Type target) + { + Report.Error (30, loc, "Cannot convert type '" + + TypeManager.CSharpName (source) + "' to '" + + TypeManager.CSharpName (target) + "'"); + } + + /// + /// Performs semantic analysis on the Expression + /// + /// + /// + /// The Resolve method is invoked to perform the semantic analysis + /// on the node. + /// + /// The return value is an expression (it can be the + /// same expression in some cases) or a new + /// expression that better represents this node. + /// + /// For example, optimizations of Unary (LiteralInt) + /// would return a new LiteralInt with a negated + /// value. + /// + /// If there is an error during semantic analysis, + /// then an error should be reported (using Report) + /// and a null value should be returned. + /// + /// There are two side effects expected from calling + /// Resolve(): the the field variable "eclass" should + /// be set to any value of the enumeration + /// `ExprClass' and the type variable should be set + /// to a valid type (this is the type of the + /// expression). + /// public abstract Expression DoResolve (EmitContext ec); public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side) @@ -145,10 +126,14 @@ namespace CIR { return DoResolve (ec); } - // - // Currently Resolve wraps DoResolve to perform sanity - // checking and assertion checking on what we expect from Resolve - // + /// + /// Resolves an expression and performs semantic analysis on it. + /// + /// + /// + /// Currently Resolve wraps DoResolve to perform sanity + /// checking and assertion checking on what we expect from Resolve. + /// public Expression Resolve (EmitContext ec) { Expression e = DoResolve (ec); @@ -164,37 +149,48 @@ namespace CIR { return null; } - if (e.ExprClass == ExprClass.Invalid) - throw new Exception ("Expression " + e + + if (e.eclass == ExprClass.Invalid) + throw new Exception ("Expression " + e.GetType () + " ExprClass is Invalid after resolve"); - if (e.ExprClass != ExprClass.MethodGroup) + if (e.eclass != ExprClass.MethodGroup) if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); + throw new Exception ( + "Expression " + e.GetType () + + " did not set its type after Resolve\n" + + "called from: " + this.GetType ()); } return e; } - // - // Just like `Resolve' above, but this 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). - // + /// + /// 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 = DoResolve (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; - if (e.ExprClass == ExprClass.Invalid) + if (e.eclass == ExprClass.Invalid) throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve"); - if (e.ExprClass != ExprClass.MethodGroup) + if (e.eclass != ExprClass.MethodGroup) if (e.type == null) throw new Exception ("Expression " + e + " did not set its type after Resolve"); @@ -203,10 +199,14 @@ namespace CIR { return e; } - // - // Currently ResolveLValue wraps DoResolveLValue to perform sanity - // checking and assertion checking on what we expect from Resolve - // + /// + /// Resolves an expression for LValue assignment + /// + /// + /// + /// Currently ResolveLValue wraps DoResolveLValue to perform sanity + /// checking and assertion checking on what we expect from Resolve + /// public Expression ResolveLValue (EmitContext ec, Expression right_side) { Expression e = DoResolveLValue (ec, right_side); @@ -222,11 +222,11 @@ namespace CIR { return null; } - if (e.ExprClass == ExprClass.Invalid) + if (e.eclass == ExprClass.Invalid) throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve"); - if (e.ExprClass != ExprClass.MethodGroup) + if (e.eclass != ExprClass.MethodGroup) if (e.type == null) throw new Exception ("Expression " + e + " did not set its type after Resolve"); @@ -235,31 +235,20 @@ namespace CIR { return e; } - // - // Emits the code for the expression - // - // - // - // - // The Emit method is invoked to generate the code - // for the expression. - // - // + /// + /// Emits the code for the expression + /// + /// + /// + /// The Emit method is invoked to generate the code + /// for the expression. + /// public abstract void Emit (EmitContext ec); - // - // This method should perform a reduction of the expression. This should - // never return null. - // - public virtual Expression Reduce (EmitContext ec) - { - return this; - } - - // - // Protected constructor. Only derivate types should - // be able to be created - // + /// + /// Protected constructor. Only derivate types should + /// be able to be created + /// protected Expression () { @@ -267,48 +256,58 @@ namespace CIR { type = null; } - // - // Returns a literalized version of a literal FieldInfo - // - public static Expression Literalize (object v, Type t) + /// + /// Returns a literalized version of a literal FieldInfo + /// + /// + /// + /// The possible return values are: + /// IntConstant, UIntConstant + /// LongLiteral, ULongConstant + /// FloatConstant, DoubleConstant + /// StringConstant + /// + /// The value returned is already resolved. + /// + public static Constant Constantify (object v, Type t) { - //Type t = fi.FieldType; - // object v = fi.GetValue (fi); - // Type t = v.GetType (); - if (t == TypeManager.int32_type) - return new IntLiteral ((int) v); + return new IntConstant ((int) v); else if (t == TypeManager.uint32_type) - return new UIntLiteral ((uint) v); + return new UIntConstant ((uint) v); else if (t == TypeManager.int64_type) - return new LongLiteral ((long) v); + return new LongConstant ((long) v); else if (t == TypeManager.uint64_type) - return new ULongLiteral ((ulong) v); + return new ULongConstant ((ulong) v); else if (t == TypeManager.float_type) - return new FloatLiteral ((float) v); + return new FloatConstant ((float) v); else if (t == TypeManager.double_type) - return new DoubleLiteral ((double) v); + return new DoubleConstant ((double) v); else if (t == TypeManager.string_type) - return new StringLiteral ((string) v); + return new StringConstant ((string) v); else if (t == TypeManager.short_type) - return new IntLiteral ((int) ((short)v)); + return new ShortConstant ((short)v); else if (t == TypeManager.ushort_type) - return new IntLiteral ((int) ((ushort)v)); + return new UShortConstant ((ushort)v); else if (t == TypeManager.sbyte_type) - return new IntLiteral ((int) ((sbyte)v)); + return new SByteConstant (((sbyte)v)); else if (t == TypeManager.byte_type) - return new IntLiteral ((int) ((byte)v)); + return new ByteConstant ((byte)v); else if (t == TypeManager.char_type) - return new IntLiteral ((int) ((char)v)); - else - throw new Exception ("Unknown type for literal (" + t + + return new CharConstant ((char)v); + else if (TypeManager.IsEnumType (t)){ + Expression e = Constantify (v, v.GetType ()); + + return new EnumConstant ((Constant) e, t); + } else + throw new Exception ("Unknown type for constant (" + t + "), details: " + v); } - // - // Returns a fully formed expression after a MemberLookup - // - static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc) + /// + /// Returns a fully formed expression after a MemberLookup + /// + public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc) { if (mi is EventInfo) return new EventExpr ((EventInfo) mi, loc); @@ -316,17 +315,58 @@ namespace CIR { return new FieldExpr ((FieldInfo) mi, loc); else if (mi is PropertyInfo) return new PropertyExpr ((PropertyInfo) mi, loc); - else if (mi is Type) - return new TypeExpr ((Type) mi); + else if (mi is Type){ + return new TypeExpr ((System.Type) mi); + } return null; } // - // FIXME: Probably implement a cache for (t,name,current_access_set)? + // We copy methods from `new_members' into `target_list' if the signature + // for the method from in the new list does not exist in the target_list + // + // The name is assumed to be the same. + // + static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members) + { + if (target_list == null){ + target_list = new ArrayList (); + + target_list.AddRange (new_members); + return target_list; + } + + MemberInfo [] target_array = new MemberInfo [target_list.Count]; + target_list.CopyTo (target_array, 0); + + foreach (MemberInfo mi in new_members){ + MethodBase new_method = (MethodBase) mi; + Type [] new_args = TypeManager.GetArgumentTypes (new_method); + + foreach (MethodBase method in target_array){ + Type [] old_args = TypeManager.GetArgumentTypes (method); + int new_count = new_args.Length; + int old_count = old_args.Length; + + if (new_count != old_count){ + target_list.Add (method); + continue; + } + + for (int i = 0; i < old_count; i++){ + if (old_args [i] == new_args [i]) + continue; + target_list.Add (method); + break; + } + } + } + return target_list; + } + // - // FIXME: We need to cope with access permissions here, or this wont - // work! + // FIXME: Probably implement a cache for (t,name,current_access_set)? // // This code could use some optimizations, but we need to do some // measurements. For example, we could use a delegate to `flag' when @@ -349,45 +389,74 @@ namespace CIR { // This is so we can catch correctly attempts to invoke instance methods // from a static body (scan for error 120 in ResolveSimpleName). // + // + // FIXME: Potential optimization, have a static ArrayList + // + public static Expression MemberLookup (EmitContext ec, Type t, string name, - bool same_type, MemberTypes mt, - BindingFlags bf, Location loc) + MemberTypes mt, BindingFlags bf, Location loc) { - if (same_type) + Type source_type = ec.ContainerType; + + if (source_type == t || source_type.IsSubclassOf (t)) bf |= BindingFlags.NonPublic; - MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers ( - t, mt, bf, Type.FilterName, name); + // + // Lookup for members starting in the type requested and going + // up the hierarchy until a match is found. + // + // As soon as a non-method match is found, we return. + // + // If methods are found though, then the search proceeds scanning + // for more public methods in the hierarchy with signatures that + // do not match any of the signatures found so far. + // + ArrayList method_list = null; + Type current_type = t; + bool searching = true; + do { + MemberInfo [] mi; + + mi = RootContext.TypeManager.FindMembers ( + current_type, mt, bf | BindingFlags.DeclaredOnly, + System.Type.FilterName, name); + + if (current_type == TypeManager.object_type) + searching = false; + else { + current_type = current_type.BaseType; + + // + // This happens with interfaces, they have a null + // basetype + // + if (current_type == null) + searching = false; + } - if (mi == null) - return null; + if (mi == null) + continue; + + int count = mi.Length; - // Empty array ... - if (mi.Length == 0) - return null; + if (count == 0) + continue; + + if (count == 1 && !(mi [0] is MethodBase)) + return Expression.ExprClassFromMemberInfo (ec, mi [0], loc); - - if (mi.Length == 1 && !(mi [0] is MethodBase)) - return Expression.ExprClassFromMemberInfo (ec, mi [0], loc); - - for (int i = 0; i < mi.Length; i++) - if (!(mi [i] is MethodBase)){ - Error (-5, "Do not know how to reproduce this case: " + - "Methods and non-Method with the same name, " + - "report this please"); - - for (i = 0; i < mi.Length; i++){ - Type tt = mi [i].GetType (); - - Console.WriteLine (i + ": " + mi [i]); - while (tt != TypeManager.object_type){ - Console.WriteLine (tt); - tt = tt.BaseType; - } - } - } + // + // We found methods, turn the search into "method scan" + // mode. + // + method_list = CopyNewMethods (method_list, mi); + mt &= (MemberTypes.Method | MemberTypes.Constructor); + } while (searching); + + if (method_list != null && method_list.Count > 0) + return new MethodGroupExpr (method_list); - return new MethodGroupExpr (mi); + return null; } public const MemberTypes AllMemberTypes = @@ -398,17 +467,47 @@ namespace CIR { MemberTypes.NestedType | MemberTypes.Property; - public const BindingFlags AllBindingsFlags = + public const BindingFlags AllBindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance; - public static Expression MemberLookup (EmitContext ec, Type t, string name, - bool same_type, Location loc) + public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc) { - return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags, loc); + return MemberLookup (ec, t, name, AllMemberTypes, AllBindingFlags, loc); } + /// + /// This is a wrapper for MemberLookup that is not used to "probe", but + /// to find a final definition. If the final definition is not found, we + /// 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) + { + Expression e; + + e = MemberLookup (ec, t, name, AllMemberTypes, AllBindingFlags, loc); + + if (e != null) + return e; + + e = MemberLookup (ec, t, name, AllMemberTypes, + AllBindingFlags | BindingFlags.NonPublic, loc); + if (e == null){ + Report.Error ( + 117, loc, "`" + t + "' does not contain a definition " + + "for `" + name + "'"); + } else { + Report.Error ( + 122, loc, "`" + t + "." + name + + "' is inaccessible due to its protection level"); + } + + return null; + } + static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) { Type expr_type = expr.Type; @@ -421,9 +520,12 @@ namespace CIR { } else if (expr_type.IsSubclassOf (target_type)) { return new EmptyCast (expr, target_type); } else { + // from the null type to any reference-type. + if (expr is NullLiteral && !target_type.IsValueType) + return new EmptyCast (expr, target_type); + // from any class-type S to any interface-type T. if (expr_type.IsClass && target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) return new EmptyCast (expr, target_type); else @@ -468,10 +570,6 @@ namespace CIR { if (target_type == TypeManager.icloneable_type) return new EmptyCast (expr, target_type); - // from the null type to any reference-type. - if (expr is NullLiteral) - return new EmptyCast (expr, target_type); - return null; } @@ -479,10 +577,10 @@ namespace CIR { return null; } - // - // Handles expressions like this: decimal d; d = 1; - // and changes them into: decimal d; d = new System.Decimal (1); - // + /// + /// 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 (); @@ -495,13 +593,12 @@ namespace CIR { return ne.Resolve (ec); } - // - // Implicit Numeric Conversions. - // - // expr is the expression to convert, returns a new expression of type - // target_type or null if an implicit conversion is not possible. - // - // + /// + /// Implicit Numeric Conversions. + /// + /// expr is the expression to convert, returns a new expression of type + /// target_type or null if an implicit conversion is not possible. + /// static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc) { @@ -510,20 +607,22 @@ namespace CIR { // // Attempt to do the implicit constant expression conversions - if (expr is IntLiteral){ + if (expr is IntConstant){ Expression e; - e = TryImplicitIntConversion (target_type, (IntLiteral) expr); + e = TryImplicitIntConversion (target_type, (IntConstant) expr); + if (e != null) return e; - } else if (expr is LongLiteral){ + } 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 // - if (((LongLiteral) expr).Value > 0) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + long v = ((LongConstant) expr).Value; + if (v > 0) + return new ULongConstant ((ulong) v); } if (expr_type == TypeManager.sbyte_type){ @@ -556,7 +655,6 @@ namespace CIR { return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); if (target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (target_type == TypeManager.double_type) @@ -666,10 +764,10 @@ namespace CIR { return null; } - // - // Determines if a standard implicit conversion exists from - // expr_type to target_type - // + /// + /// Determines if a standard implicit conversion exists from + /// expr_type to target_type + /// public static bool StandardConversionExists (Type expr_type, Type target_type) { if (expr_type == target_type) @@ -838,12 +936,28 @@ namespace CIR { return false; } + + static EmptyExpression MyEmptyExpr; + /// + /// Tells whether an implicit conversion exists from expr_type to + /// target_type + /// + public bool ImplicitConversionExists (EmitContext ec, Type expr_type, Type target_type, + Location l) + { + if (MyEmptyExpr == null) + MyEmptyExpr = new EmptyExpression (expr_type); + else + MyEmptyExpr.SetType (expr_type); + + return ConvertImplicit (ec, MyEmptyExpr, target_type, l) != null; + } - // - // Finds "most encompassed type" according to the spec (13.4.2) - // amongst the methods in the MethodGroupExpr which convert from a - // type encompassing source_type - // + /// + /// Finds "most encompassed type" according to the spec (13.4.2) + /// amongst the methods in the MethodGroupExpr which convert from a + /// type encompassing source_type + /// static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type) { Type best = null; @@ -867,11 +981,11 @@ namespace CIR { return best; } - // - // Finds "most encompassing type" according to the spec (13.4.2) - // amongst the methods in the MethodGroupExpr which convert to a - // type encompassed by target_type - // + /// + /// Finds "most encompassing type" according to the spec (13.4.2) + /// amongst the methods in the MethodGroupExpr which convert to a + /// type encompassed by target_type + /// static Type FindMostEncompassingType (MethodGroupExpr me, Type target) { Type best = null; @@ -897,27 +1011,27 @@ namespace CIR { } - // - // User-defined Implicit conversions - // + /// + /// User-defined Implicit conversions + /// static public Expression ImplicitUserConversion (EmitContext ec, Expression source, Type target, Location loc) { return UserDefinedConversion (ec, source, target, loc, false); } - // - // User-defined Explicit conversions - // + /// + /// User-defined Explicit conversions + /// static public Expression ExplicitUserConversion (EmitContext ec, Expression source, Type target, Location loc) { return UserDefinedConversion (ec, source, target, loc, true); } - // - // User-defined conversions - // + /// + /// User-defined conversions + /// static public Expression UserDefinedConversion (EmitContext ec, Expression source, Type target, Location loc, bool look_for_explicit) @@ -939,15 +1053,15 @@ namespace CIR { else op_name = "op_Implicit"; - mg1 = MemberLookup (ec, source_type, op_name, false, loc); + mg1 = MemberLookup (ec, source_type, op_name, loc); if (source_type.BaseType != null) - mg2 = MemberLookup (ec, source_type.BaseType, op_name, false, loc); + mg2 = MemberLookup (ec, source_type.BaseType, op_name, loc); - mg3 = MemberLookup (ec, target, op_name, false, loc); + mg3 = MemberLookup (ec, target, op_name, loc); if (target.BaseType != null) - mg4 = MemberLookup (ec, target.BaseType, op_name, false, loc); + mg4 = MemberLookup (ec, target.BaseType, op_name, loc); MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2); MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4); @@ -960,15 +1074,15 @@ namespace CIR { op_name = "op_Explicit"; - mg5 = MemberLookup (ec, source_type, op_name, false, loc); + mg5 = MemberLookup (ec, source_type, op_name, loc); if (source_type.BaseType != null) - mg6 = MemberLookup (ec, source_type.BaseType, op_name, false, loc); + mg6 = MemberLookup (ec, source_type.BaseType, op_name, loc); - mg7 = MemberLookup (ec, target, op_name, false, loc); + mg7 = MemberLookup (ec, target, op_name, loc); if (target.BaseType != null) - mg8 = MemberLookup (ec, target.BaseType, op_name, false, loc); + mg8 = MemberLookup (ec, target.BaseType, op_name, loc); MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6); MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8); @@ -1025,7 +1139,7 @@ namespace CIR { if (source == null) return null; - + e = new UserCast ((MethodInfo) method, source); if (e.Type != target){ @@ -1042,11 +1156,11 @@ namespace CIR { return null; } - // - // Converts implicitly the resolved expression `expr' into the - // `target_type'. It returns a new expression that can be used - // in a context that expects a `target_type'. - // + /// + /// Converts implicitly the resolved expression `expr' into the + /// `target_type'. It returns a new expression that can be used + /// in a context that expects a `target_type'. + /// static public Expression ConvertImplicit (EmitContext ec, Expression expr, Type target_type, Location loc) { @@ -1056,6 +1170,9 @@ namespace CIR { if (expr_type == target_type) return expr; + if (target_type == null) + throw new Exception ("Target type is null"); + e = ImplicitNumericConversion (ec, expr, target_type, loc); if (e != null) return e; @@ -1079,16 +1196,16 @@ namespace CIR { } - // - // Attempts to apply the `Standard Implicit - // Conversion' rules to the expression `expr' into - // the `target_type'. It returns a new expression - // that can be used in a context that expects a - // `target_type'. - // - // This is different from `ConvertImplicit' in that the - // user defined implicit conversions are excluded. - // + /// + /// Attempts to apply the `Standard Implicit + /// Conversion' rules to the expression `expr' into + /// the `target_type'. It returns a new expression + /// that can be used in a context that expects a + /// `target_type'. + /// + /// This is different from `ConvertImplicit' in that the + /// user defined implicit conversions are excluded. + /// static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr, Type target_type, Location loc) { @@ -1114,34 +1231,34 @@ namespace CIR { } return null; } - // - // Attemps to perform an implict constant conversion of the IntLiteral - // into a different data type using casts (See Implicit Constant - // Expression Conversions) - // - static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il) + + /// + /// Attemps to perform an implict constant conversion of the IntConstant + /// into a different data type using casts (See Implicit Constant + /// Expression Conversions) + /// + static protected Expression TryImplicitIntConversion (Type target_type, IntConstant ic) { - int value = il.Value; - + int value = ic.Value; + + // + // FIXME: This should really return constants instead of EmptyCasts + // if (target_type == TypeManager.sbyte_type){ if (value >= SByte.MinValue && value <= SByte.MaxValue) - return il; + return new SByteConstant ((sbyte) value); } else if (target_type == TypeManager.byte_type){ if (Byte.MinValue >= 0 && value <= Byte.MaxValue) - return il; + return new ByteConstant ((byte) value); } else if (target_type == TypeManager.short_type){ if (value >= Int16.MinValue && value <= Int16.MaxValue) - return il; + return new ShortConstant ((short) value); } else if (target_type == TypeManager.ushort_type){ if (value >= UInt16.MinValue && value <= UInt16.MaxValue) - return il; + return new UShortConstant ((ushort) value); } else if (target_type == TypeManager.uint32_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint32 - // if (value >= 0) - return il; + return new UIntConstant ((uint) value); } else if (target_type == TypeManager.uint64_type){ // // we can optimize this case: a positive int32 @@ -1149,38 +1266,47 @@ namespace CIR { // to do it. // if (value >= 0) - return new OpcodeCast (il, target_type, OpCodes.Conv_I8); + return new ULongConstant ((ulong) value); } + + if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)) + return new EnumConstant (ic, target_type); return null; } - // - // Attemptes to implicityly convert `target' into `type', using - // ConvertImplicit. If there is no implicit conversion, then - // an error is signaled - // - static public Expression ConvertImplicitRequired (EmitContext ec, Expression target, - Type type, Location loc) + /// + /// Attemptes to implicityly convert `target' into `type', using + /// ConvertImplicit. If there is no implicit conversion, then + /// an error is signaled + /// + static public Expression ConvertImplicitRequired (EmitContext ec, Expression source, + Type target_type, Location loc) { Expression e; - e = ConvertImplicit (ec, target, type, loc); + e = ConvertImplicit (ec, source, target_type, loc); if (e != null) 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"); + } - string msg = "Can not convert implicitly from `"+ - TypeManager.CSharpName (target.Type) + "' to `" + - TypeManager.CSharpName (type) + "'"; + string msg = "Cannot convert implicitly from `"+ + TypeManager.CSharpName (source.Type) + "' to `" + + TypeManager.CSharpName (target_type) + "'"; Error (29, loc, msg); return null; } - // - // Performs the explicit numeric conversions - // + /// + /// Performs the explicit numeric conversions + /// static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type) { @@ -1191,135 +1317,135 @@ namespace CIR { // From sbyte to byte, ushort, uint, ulong, char // if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4); if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH); } else if (expr_type == TypeManager.byte_type){ // // From byte to sbyte and char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH); } else if (expr_type == TypeManager.short_type){ // // From short to sbyte, byte, ushort, uint, ulong, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4); if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH); } else if (expr_type == TypeManager.ushort_type){ // // From ushort to sbyte, byte, short, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH); } else if (expr_type == TypeManager.int32_type){ // // From int to sbyte, byte, short, ushort, uint, ulong, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2); if (target_type == TypeManager.uint32_type) - return new EmptyCast (expr, target_type); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4); if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH); } else if (expr_type == TypeManager.uint32_type){ // // From uint to sbyte, byte, short, ushort, int, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2); if (target_type == TypeManager.int32_type) - return new EmptyCast (expr, target_type); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH); } else if (expr_type == TypeManager.int64_type){ // // From long to sbyte, byte, short, ushort, int, uint, ulong, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2); if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4); if (target_type == TypeManager.uint64_type) - return new EmptyCast (expr, target_type); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH); } else if (expr_type == TypeManager.uint64_type){ // // From ulong to sbyte, byte, short, ushort, int, uint, long, char // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2); if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4); if (target_type == TypeManager.int64_type) - return new EmptyCast (expr, target_type); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH); } else if (expr_type == TypeManager.char_type){ // // From char to sbyte, byte, short // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2); } else if (expr_type == TypeManager.float_type){ // // From float to sbyte, byte, short, @@ -1327,23 +1453,23 @@ namespace CIR { // or decimal // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2); if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4); if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8); if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH); if (target_type == TypeManager.decimal_type) return InternalTypeConstructor (ec, expr, target_type); } else if (expr_type == TypeManager.double_type){ @@ -1353,25 +1479,25 @@ namespace CIR { // char, float or decimal // if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1); if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1); if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2); if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2); if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4); if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4); if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8); if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8); if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH); if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4); if (target_type == TypeManager.decimal_type) return InternalTypeConstructor (ec, expr, target_type); } @@ -1381,10 +1507,10 @@ namespace CIR { return null; } - // - // Returns whether an explicit reference conversion can be performed - // from source_type to target_type - // + /// + /// Returns whether an explicit reference conversion can be performed + /// from source_type to target_type + /// static bool ExplicitReferenceConversionExists (Type source_type, Type target_type) { bool target_is_value_type = target_type.IsValueType; @@ -1473,9 +1599,9 @@ namespace CIR { return false; } - // - // Implements Explicit Reference conversions - // + /// + /// Implements Explicit Reference conversions + /// static Expression ConvertReferenceExplicit (Expression source, Type target_type) { Type source_type = source.Type; @@ -1580,13 +1706,14 @@ namespace CIR { return null; } - // - // Performs an explicit conversion of the expression `expr' whose - // type is expr.Type to `target_type'. - // + /// + /// Performs an explicit conversion of the expression `expr' whose + /// type is expr.Type to `target_type'. + /// static public Expression ConvertExplicit (EmitContext ec, Expression expr, Type target_type, Location loc) { + Type expr_type = expr.Type; Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc); if (ne != null) @@ -1596,6 +1723,36 @@ namespace CIR { 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)); + } + + e = ConvertImplicit (ec, e, target_type, loc); + if (e != null) + return e; + + return ConvertNumericExplicit (ec, e, target_type); + } + ne = ConvertReferenceExplicit (expr, target_type); if (ne != null) return ne; @@ -1604,14 +1761,13 @@ namespace CIR { if (ne != null) return ne; - Report.Error (30, loc, "Cannot convert type '" + TypeManager.CSharpName (expr.Type) + "' to '" - + TypeManager.CSharpName (target_type) + "'"); + error30 (loc, expr_type, target_type); return null; } - // - // Same as ConverExplicit, only it doesn't include user defined conversions - // + /// + /// Same as ConverExplicit, only it doesn't include user defined conversions + /// static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr, Type target_type, Location l) { @@ -1628,9 +1784,7 @@ namespace CIR { if (ne != null) return ne; - Report.Error (30, l, "Cannot convert type '" + - TypeManager.CSharpName (expr.Type) + "' to '" + - TypeManager.CSharpName (target_type) + "'"); + error30 (l, expr.Type, target_type); return null; } @@ -1661,69 +1815,333 @@ namespace CIR { throw new Exception ("Should not happen"); } - // - // Reports that we were expecting `expr' to be of class `expected' - // + /// + /// Reports that we were expecting `expr' to be of class `expected' + /// protected void report118 (Location loc, Expression expr, string expected) { string kind = "Unknown"; if (expr != null) - kind = ExprClassName (expr.ExprClass); + kind = ExprClassName (expr.eclass); - Error (118, loc, "Expression denotes a '" + kind + - "' where an " + expected + " was expected"); + Error (118, loc, "Expression denotes a `" + kind + + "' where a `" + expected + "' was expected"); } - // - // This function tries to reduce the expression performing - // constant folding and common subexpression elimination - // - static public Expression Reduce (EmitContext ec, Expression e) + static void error31 (Location l, string val, Type t) { - //Console.WriteLine ("Calling reduce"); - return e.Reduce (ec); + Report.Error (31, l, "Constant value `" + val + "' cannot be converted to " + + TypeManager.CSharpName (t)); } - } + + /// + /// Converts the IntConstant, UIntConstant, LongConstant or + /// ULongConstant into the integral target_type. Notice + /// that we do not return an `Expression' we do return + /// a boxed integral type. + /// + /// FIXME: Since I added the new constants, we need to + /// also support conversions from CharConstant, ByteConstant, + /// SByteConstant, UShortConstant, ShortConstant + /// + /// This is used by the switch statement, so the domain + /// of work is restricted to the literals above, and the + /// targets are int32, uint32, char, byte, sbyte, ushort, + /// short, uint64 and int64 + /// + public static object ConvertIntLiteral (Constant c, Type target_type, Location loc) + { + string s = ""; + + if (c.Type == target_type) + return ((Constant) c).GetValue (); - // - // This is just a base class for expressions that can - // appear on statements (invocations, object creation, - // assignments, post/pre increment and decrement). The idea - // being that they would support an extra Emition interface that - // does not leave a result on the stack. - // + // + // Make into one of the literals we handle, we dont really care + // about this value as we will just return a few limited types + // + if (c is EnumConstant) + c = ((EnumConstant)c).WidenToCompilerConstant (); + + if (c is IntConstant){ + int v = ((IntConstant) c).Value; + + if (target_type == TypeManager.uint32_type){ + if (v >= 0) + return (uint) v; + } else if (target_type == TypeManager.char_type){ + if (v >= Char.MinValue && v <= Char.MaxValue) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v >= SByte.MinValue && v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type){ + if (v >= Int16.MinValue && v <= UInt16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.ushort_type){ + if (v >= UInt16.MinValue && v <= UInt16.MaxValue) + return (ushort) v; + } else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type){ + if (v > 0) + return (ulong) v; + } + s = v.ToString (); + } else if (c is UIntConstant){ + uint v = ((UIntConstant) c).Value; + + if (target_type == TypeManager.int32_type){ + if (v <= Int32.MaxValue) + return (int) v; + } else if (target_type == TypeManager.char_type){ + if (v >= Char.MinValue && v <= Char.MaxValue) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type){ + if (v <= UInt16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.ushort_type){ + if (v <= UInt16.MaxValue) + return (ushort) v; + } else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type) + return (ulong) v; + s = v.ToString (); + } else if (c is LongConstant){ + long v = ((LongConstant) c).Value; + + if (target_type == TypeManager.int32_type){ + if (v >= UInt32.MinValue && v <= UInt32.MaxValue) + return (int) v; + } else if (target_type == TypeManager.uint32_type){ + if (v >= 0 && v <= UInt32.MaxValue) + return (uint) v; + } else if (target_type == TypeManager.char_type){ + if (v >= Char.MinValue && v <= Char.MaxValue) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v >= SByte.MinValue && v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type){ + if (v >= Int16.MinValue && v <= UInt16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.ushort_type){ + if (v >= UInt16.MinValue && v <= UInt16.MaxValue) + return (ushort) v; + } else if (target_type == TypeManager.uint64_type){ + if (v > 0) + return (ulong) v; + } + s = v.ToString (); + } else if (c is ULongConstant){ + ulong v = ((ULongConstant) c).Value; + + if (target_type == TypeManager.int32_type){ + if (v <= Int32.MaxValue) + return (int) v; + } else if (target_type == TypeManager.uint32_type){ + if (v <= UInt32.MaxValue) + return (uint) v; + } else if (target_type == TypeManager.char_type){ + if (v >= Char.MinValue && v <= Char.MaxValue) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v <= (int) SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type){ + if (v <= UInt16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.ushort_type){ + if (v <= UInt16.MaxValue) + return (ushort) v; + } else if (target_type == TypeManager.int64_type){ + if (v <= Int64.MaxValue) + return (long) v; + } + s = v.ToString (); + } else if (c is ByteConstant){ + byte v = ((ByteConstant) c).Value; + + if (target_type == TypeManager.int32_type) + return (int) v; + else if (target_type == TypeManager.uint32_type) + return (uint) v; + else if (target_type == TypeManager.char_type) + return (char) v; + else if (target_type == TypeManager.sbyte_type){ + if (v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type) + return (short) v; + else if (target_type == TypeManager.ushort_type) + return (ushort) v; + else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type) + return (ulong) v; + s = v.ToString (); + } else if (c is SByteConstant){ + sbyte v = ((SByteConstant) c).Value; + + if (target_type == TypeManager.int32_type) + return (int) v; + else if (target_type == TypeManager.uint32_type){ + if (v >= 0) + return (uint) v; + } else if (target_type == TypeManager.char_type){ + if (v >= 0) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= 0) + return (byte) v; + } else if (target_type == TypeManager.short_type) + return (short) v; + else if (target_type == TypeManager.ushort_type){ + if (v >= 0) + return (ushort) v; + } else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type){ + if (v >= 0) + return (ulong) v; + } + s = v.ToString (); + } else if (c is ShortConstant){ + short v = ((ShortConstant) c).Value; + + if (target_type == TypeManager.int32_type){ + return (int) v; + } else if (target_type == TypeManager.uint32_type){ + if (v >= 0) + return (uint) v; + } else if (target_type == TypeManager.char_type){ + if (v >= 0) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v >= SByte.MinValue && v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.ushort_type){ + if (v >= 0) + return (ushort) v; + } else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type) + return (ulong) v; + + s = v.ToString (); + } else if (c is UShortConstant){ + ushort v = ((UShortConstant) c).Value; + + if (target_type == TypeManager.int32_type) + return (int) v; + else if (target_type == TypeManager.uint32_type) + return (uint) v; + else if (target_type == TypeManager.char_type){ + if (v >= Char.MinValue && v <= Char.MaxValue) + return (char) v; + } else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v <= SByte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.short_type){ + if (v <= Int16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type) + return (ulong) v; + + s = v.ToString (); + } else if (c is CharConstant){ + char v = ((CharConstant) c).Value; + + if (target_type == TypeManager.int32_type) + return (int) v; + else if (target_type == TypeManager.uint32_type) + return (uint) v; + else if (target_type == TypeManager.byte_type){ + if (v >= Byte.MinValue && v <= Byte.MaxValue) + return (byte) v; + } else if (target_type == TypeManager.sbyte_type){ + if (v <= SByte.MaxValue) + return (sbyte) v; + } else if (target_type == TypeManager.short_type){ + if (v <= Int16.MaxValue) + return (short) v; + } else if (target_type == TypeManager.ushort_type) + return (short) v; + else if (target_type == TypeManager.int64_type) + return (long) v; + else if (target_type == TypeManager.uint64_type) + return (ulong) v; + + s = v.ToString (); + } + error31 (loc, s, target_type); + return null; + } + + } + + /// + /// This is just a base class for expressions that can + /// appear on statements (invocations, object creation, + /// assignments, post/pre increment and decrement). The idea + /// being that they would support an extra Emition interface that + /// does not leave a result on the stack. + /// public abstract class ExpressionStatement : Expression { - // - // Requests the expression to be emitted in a `statement' - // context. This means that no new value is left on the - // stack after invoking this method (constrasted with - // Emit that will always leave a value on the stack). - // + /// + /// Requests the expression to be emitted in a `statement' + /// context. This means that no new value is left on the + /// stack after invoking this method (constrasted with + /// Emit that will always leave a value on the stack). + /// public abstract void EmitStatement (EmitContext ec); } - // - // This kind of cast is used to encapsulate the child - // whose type is child.Type into an expression that is - // reported to return "return_type". This is used to encapsulate - // expressions which have compatible types, but need to be dealt - // at higher levels with. - // - // For example, a "byte" expression could be encapsulated in one - // of these as an "unsigned int". The type for the expression - // would be "unsigned int". - // - // - + /// + /// This kind of cast is used to encapsulate the child + /// whose type is child.Type into an expression that is + /// reported to return "return_type". This is used to encapsulate + /// expressions which have compatible types, but need to be dealt + /// at higher levels with. + /// + /// For example, a "byte" expression could be encapsulated in one + /// of these as an "unsigned int". The type for the expression + /// would be "unsigned int". + /// + /// public class EmptyCast : Expression { protected Expression child; public EmptyCast (Expression child, Type return_type) { - ExprClass = child.ExprClass; + eclass = child.eclass; type = return_type; this.child = child; } @@ -1740,20 +2158,18 @@ namespace CIR { { child.Emit (ec); } - } - // - // This class is used to wrap literals which belong inside Enums - // - - public class EnumLiteral : Literal { - Expression child; + /// + /// This class is used to wrap literals which belong inside Enums + /// + public class EnumConstant : Constant { + public Constant Child; - public EnumLiteral (Expression child, Type enum_type) + public EnumConstant (Constant child, Type enum_type) { - ExprClass = child.ExprClass; - this.child = child; + eclass = child.eclass; + this.Child = child; type = enum_type; } @@ -1767,26 +2183,84 @@ namespace CIR { public override void Emit (EmitContext ec) { - child.Emit (ec); + Child.Emit (ec); } public override object GetValue () { - return ((Literal) child).GetValue (); + return Child.GetValue (); + } + + // + // Converts from one of the valid underlying types for an enumeration + // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to + // one of the internal compiler literals: Int/UInt/Long/ULong Literals. + // + public Constant WidenToCompilerConstant () + { + Type t = TypeManager.EnumToUnderlying (Child.Type); + object v = ((Constant) Child).GetValue ();; + + if (t == TypeManager.int32_type) + return new IntConstant ((int) v); + if (t == TypeManager.uint32_type) + return new UIntConstant ((uint) v); + if (t == TypeManager.int64_type) + return new LongConstant ((long) v); + if (t == TypeManager.uint64_type) + return new ULongConstant ((ulong) v); + if (t == TypeManager.short_type) + return new ShortConstant ((short) v); + if (t == TypeManager.ushort_type) + return new UShortConstant ((ushort) v); + if (t == TypeManager.byte_type) + return new ByteConstant ((byte) v); + if (t == TypeManager.sbyte_type) + return new SByteConstant ((sbyte) v); + + throw new Exception ("Invalid enumeration underlying type: " + t); } + // + // Extracts the value in the enumeration on its native representation + // + public object GetPlainValue () + { + Type t = TypeManager.EnumToUnderlying (Child.Type); + object v = ((Constant) Child).GetValue ();; + + if (t == TypeManager.int32_type) + return (int) v; + if (t == TypeManager.uint32_type) + return (uint) v; + if (t == TypeManager.int64_type) + return (long) v; + if (t == TypeManager.uint64_type) + return (ulong) v; + if (t == TypeManager.short_type) + return (short) v; + if (t == TypeManager.ushort_type) + return (ushort) v; + if (t == TypeManager.byte_type) + return (byte) v; + if (t == TypeManager.sbyte_type) + return (sbyte) v; + + return null; + } + public override string AsString () { - return ((Literal) child).AsString (); + return Child.AsString (); } } - // - // This kind of cast is used to encapsulate Value Types in objects. - // - // The effect of it is to box the value type emitted by the previous - // operation. - // + /// + /// This kind of cast is used to encapsulate Value Types in objects. + /// + /// The effect of it is to box the value type emitted by the previous + /// operation. + /// public class BoxedCast : EmptyCast { public BoxedCast (Expression expr) @@ -1809,11 +2283,277 @@ namespace CIR { } } - // - // This kind of cast is used to encapsulate a child expression - // that can be trivially converted to a target type using one or - // two opcodes. The opcodes are passed as arguments. - // + public class UnboxCast : EmptyCast { + public UnboxCast (Expression expr, Type return_type) + : base (expr, return_type) + { + } + + public override Expression DoResolve (EmitContext ec) + { + // This should never be invoked, we are born in fully + // initialized state. + + return this; + } + + public override void Emit (EmitContext ec) + { + Type t = type; + ILGenerator ig = ec.ig; + + base.Emit (ec); + ig.Emit (OpCodes.Unbox, t); + + // + // Load the object from the pointer + // + basic_type: + + if (t == TypeManager.int32_type) + ig.Emit (OpCodes.Ldind_I4); + else if (t == TypeManager.uint32_type) + ig.Emit (OpCodes.Ldind_U4); + else if (t == TypeManager.short_type) + ig.Emit (OpCodes.Ldind_I2); + else if (t == TypeManager.ushort_type) + ig.Emit (OpCodes.Ldind_U2); + else if (t == TypeManager.char_type) + ig.Emit (OpCodes.Ldind_U2); + else if (t == TypeManager.byte_type) + ig.Emit (OpCodes.Ldind_U1); + else if (t == TypeManager.sbyte_type) + ig.Emit (OpCodes.Ldind_I1); + else if (t == TypeManager.uint64_type) + ig.Emit (OpCodes.Ldind_I8); + else if (t == TypeManager.int64_type) + ig.Emit (OpCodes.Ldind_I8); + else if (t == TypeManager.float_type) + ig.Emit (OpCodes.Ldind_R4); + else if (t == TypeManager.double_type) + ig.Emit (OpCodes.Ldind_R8); + else if (t == TypeManager.bool_type) + ig.Emit (OpCodes.Ldind_I1); + else if (t == TypeManager.intptr_type) + ig.Emit (OpCodes.Ldind_I); + else if (TypeManager.IsEnumType (t)){ + t = TypeManager.EnumToUnderlying (t); + goto basic_type; + } else + ig.Emit (OpCodes.Ldobj, t); + } + } + + /// + /// This is used to perform explicit numeric conversions. + /// + /// Explicit numeric conversions might trigger exceptions in a checked + /// context, so they should generate the conv.ovf opcodes instead of + /// conv opcodes. + /// + public class ConvCast : EmptyCast { + public enum Mode : byte { + I1_U1, I1_U2, I1_U4, I1_U8, I1_CH, + U1_I1, U1_CH, + I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH, + U2_I1, U2_U1, U2_I2, U2_CH, + I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH, + U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH, + I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, + U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, + CH_I1, CH_U1, CH_I2, + R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH, + R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4 + } + + Mode mode; + + public ConvCast (Expression child, Type return_type, Mode m) + : base (child, return_type) + { + mode = m; + } + + public override Expression DoResolve (EmitContext ec) + { + // This should never be invoked, we are born in fully + // initialized state. + + return this; + } + + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + base.Emit (ec); + + if (ec.CheckState){ + switch (mode){ + case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + + case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break; + case Mode.U1_CH: /* nothing */ break; + + case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break; + case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + + case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break; + case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break; + case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break; + case Mode.U2_CH: /* nothing */ break; + + case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break; + case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break; + case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + + case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break; + case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break; + case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break; + case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break; + case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break; + case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break; + + case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break; + case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break; + case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break; + case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + + case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break; + case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break; + case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break; + case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break; + case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break; + case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break; + case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break; + case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break; + + case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break; + case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break; + case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break; + + case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break; + case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break; + case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break; + case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break; + case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + + case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break; + case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break; + case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break; + case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break; + case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break; + case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break; + case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break; + case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break; + case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break; + } + } else { + switch (mode){ + case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break; + case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break; + case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.U2_CH: /* nothing */ break; + + case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.I4_U4: /* nothing */ break; + case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break; + case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.U4_I4: /* nothing */ break; + case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break; + case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.I8_U8: /* nothing */ break; + case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break; + case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.U8_I8: /* nothing */ break; + case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break; + + case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break; + case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break; + case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break; + case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break; + + case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break; + case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break; + case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break; + case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break; + case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break; + case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break; + case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break; + case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break; + case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break; + case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break; + } + } + } + } + public class OpcodeCast : EmptyCast { OpCode op, op2; bool second_valid; @@ -1851,13 +2591,12 @@ namespace CIR { if (second_valid) ec.ig.Emit (op2); } - } - // - // This kind of cast is used to encapsulate a child and cast it - // to the class requested - // + /// + /// This kind of cast is used to encapsulate a child and cast it + /// to the class requested + /// public class ClassCast : EmptyCast { public ClassCast (Expression child, Type return_type) : base (child, return_type) @@ -1882,32 +2621,34 @@ namespace CIR { } - // - // SimpleName expressions are initially formed of a single - // word and it only happens at the beginning of the expression. - // - // The expression will try to be bound to a Field, a Method - // group or a Property. If those fail we pass the name to our - // caller and the SimpleName is compounded to perform a type - // lookup. The idea behind this process is that we want to avoid - // creating a namespace map from the assemblies, as that requires - // the GetExportedTypes function to be called and a hashtable to - // be constructed which reduces startup time. If later we find - // that this is slower, we should create a `NamespaceExpr' expression - // that fully participates in the resolution process. - // - // For example `System.Console.WriteLine' is decomposed into - // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine") - // - // The first SimpleName wont produce a match on its own, so it will - // be turned into: - // MemberAccess (SimpleName ("System.Console"), "WriteLine"). - // - // System.Console will produce a TypeExpr match. - // - // The downside of this is that we might be hitting `LookupType' too many - // times with this scheme. - // + /// + /// SimpleName expressions are initially formed of a single + /// word and it only happens at the beginning of the expression. + /// + /// + /// + /// The expression will try to be bound to a Field, a Method + /// group or a Property. If those fail we pass the name to our + /// caller and the SimpleName is compounded to perform a type + /// lookup. The idea behind this process is that we want to avoid + /// creating a namespace map from the assemblies, as that requires + /// the GetExportedTypes function to be called and a hashtable to + /// be constructed which reduces startup time. If later we find + /// that this is slower, we should create a `NamespaceExpr' expression + /// that fully participates in the resolution process. + /// + /// For example `System.Console.WriteLine' is decomposed into + /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine") + /// + /// The first SimpleName wont produce a match on its own, so it will + /// be turned into: + /// MemberAccess (SimpleName ("System.Console"), "WriteLine"). + /// + /// System.Console will produce a TypeExpr match. + /// + /// The downside of this is that we might be hitting `LookupType' too many + /// times with this scheme. + /// public class SimpleName : Expression { public readonly string Name; public readonly Location Location; @@ -1952,70 +2693,182 @@ namespace CIR { Error120 (Location, Name); return null; } + } else if (e is EventExpr) { + if (!((EventExpr) e).IsStatic) { + Error120 (Location, Name); + return null; + } } return e; } - // - // 7.5.2: Simple Names. - // - // Local Variables and Parameters are handled at - // parse time, so they never occur as SimpleNames. - // public override Expression DoResolve (EmitContext ec) + { + return SimpleNameResolve (ec, false); + } + + public Expression DoResolveAllowStatic (EmitContext ec) + { + return SimpleNameResolve (ec, true); + } + + /// + /// 7.5.2: Simple Names. + /// + /// Local Variables and Parameters are handled at + /// parse time, so they never occur as SimpleNames. + /// + /// The `allow_static' flag is used by MemberAccess only + /// and it is used to inform us that it is ok for us to + /// avoid the static check, because MemberAccess might end + /// up resolving the Name as a Type name and the access as + /// a static type access. + /// + /// ie: Type Type; .... { Type.GetType (""); } + /// + /// Type is both an instance variable and a Type; Type.GetType + /// is the static method not an instance method of type. + /// + Expression SimpleNameResolve (EmitContext ec, bool allow_static) { Expression e; // - // Stage 1: Performed by the parser (binding to local or parameters). + // Stage 1: Performed by the parser (binding to locals or parameters). // // - // Stage 2: Lookup members + // Stage 2: Lookup members // - e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true, Location); + e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, Location); if (e == null){ // // Stage 3: Lookup symbol in the various namespaces. - // + // + DeclSpace ds = ec.TypeContainer; Type t; + string alias_value; - if ((t = ec.TypeContainer.LookupType (Name, true)) != null) + if ((t = RootContext.LookupType (ds, Name, true, Location)) != null) return new TypeExpr (t); - + // - // Stage 3 part b: Lookup up if we are an alias to a type + // 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 // - // IMPLEMENT ME. Read mcs/mcs/TODO for ideas, or rewrite - // using NamespaceExprs (dunno how that fixes the alias - // per-file though). + if (Name.IndexOf ('.') == -1 && (alias_value = ec.TypeContainer.LookupAlias (Name)) != null) { + // System.Console.WriteLine (Name + " --> " + alias_value); + if ((t = RootContext.LookupType (ds, alias_value, true, Location)) + != null) + return new TypeExpr (t); + + // we have alias value, but it isn't Type, so try if it's namespace + return new SimpleName (alias_value, Location); + } // No match, maybe our parent can compose us // into something meaningful. - // return this; } - - // Step 2, continues here. + + // + // Stage 2 continues here. + // if (e is TypeExpr) return e; if (e is FieldExpr){ FieldExpr fe = (FieldExpr) e; + FieldInfo fi = fe.FieldInfo; + + if (ec.IsStatic){ + if (!allow_static && !fi.IsStatic){ + Error120 (Location, Name); + return null; + } + } else { + // If we are not in static code and this + // field is not static, set the instance to `this'. + + if (!fi.IsStatic) + fe.InstanceExpression = ec.This; + } + - if (!fe.FieldInfo.IsStatic) - fe.InstanceExpression = new This (Location.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); + } + } + + return e; } - if (ec.IsStatic) + 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.TypeContainer.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 (fi.IsStatic) + instance_expr = null; + else + instance_expr = ec.This; + + instance_expr = instance_expr.Resolve (ec); + + if (instance_expr != null) + instance_expr = instance_expr.Resolve (ec); + + return MemberAccess.ResolveMemberAccess (ec, ml, instance_expr, Location, null); + } + } + + + if (ec.IsStatic){ + if (allow_static) + return e; + return MemberStaticCheck (e); - else + } else return e; } @@ -2032,9 +2885,9 @@ namespace CIR { } } - // - // Fully resolved expression that evaluates to a type - // + /// + /// Fully resolved expression that evaluates to a type + /// public class TypeExpr : Expression { public TypeExpr (Type t) { @@ -2053,11 +2906,11 @@ namespace CIR { } } - // - // MethodGroup Expression. - // - // This is a fully resolved expression that evaluates to a type - // + /// + /// MethodGroup Expression. + /// + /// This is a fully resolved expression that evaluates to a type + /// public class MethodGroupExpr : Expression { public MethodBase [] Methods; Expression instance_expression = null; @@ -2122,29 +2975,29 @@ namespace CIR { return true; } - // - // Removes any instance methods from the MethodGroup, returns - // false if the resulting set is empty. - // + /// + /// Removes any instance methods from the MethodGroup, returns + /// false if the resulting set is empty. + /// public bool RemoveInstanceMethods () { return RemoveMethods (true); } - // - // Removes any static methods from the MethodGroup, returns - // false if the resulting set is empty. - // + /// + /// Removes any static methods from the MethodGroup, returns + /// false if the resulting set is empty. + /// public bool RemoveStaticMethods () { return RemoveMethods (false); } } - // - // Fully resolved expression that evaluates to a Field - // - public class FieldExpr : Expression, IStackStore, IMemoryLocation { + /// + /// Fully resolved expression that evaluates to a Field + /// + public class FieldExpr : Expression, IAssignMethod, IMemoryLocation { public readonly FieldInfo FieldInfo; public Expression InstanceExpression; Location loc; @@ -2171,11 +3024,17 @@ namespace CIR { return null; } + return this; } - public Expression DoResolveLValue (EmitContext ec) + override public Expression DoResolveLValue (EmitContext ec, Expression right_side) { + Expression e = DoResolve (ec); + + if (e == null) + return null; + if (!FieldInfo.IsInitOnly) return this; @@ -2200,20 +3059,56 @@ namespace CIR { if (FieldInfo.IsStatic) ig.Emit (OpCodes.Ldsfld, FieldInfo); else { - InstanceExpression.Emit (ec); - + if (InstanceExpression.Type.IsValueType){ + IMemoryLocation ml; + + if (!(InstanceExpression is IMemoryLocation)){ + LocalTemporary tempo = new LocalTemporary ( + ec, InstanceExpression.Type); + + InstanceExpression.Emit (ec); + tempo.Store (ec); + ml = tempo; + } else + ml = (IMemoryLocation) InstanceExpression; + + ml.AddressOf (ec); + } else + InstanceExpression.Emit (ec); + ig.Emit (OpCodes.Ldfld, FieldInfo); } } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { - if (FieldInfo.IsStatic) + bool is_static = FieldInfo.IsStatic; + + if (!is_static){ + Expression instance = InstanceExpression; + + if (instance.Type.IsValueType){ + if (instance is IMemoryLocation){ + IMemoryLocation ml = (IMemoryLocation) instance; + + ml.AddressOf (ec); + } else + throw new Exception ("The " + instance + " of type " + + instance.Type + + " represents a ValueType and does " + + "not implement IMemoryLocation"); + } else + instance.Emit (ec); + } + source.Emit (ec); + + if (is_static) ec.ig.Emit (OpCodes.Stsfld, FieldInfo); - else + else { ec.ig.Emit (OpCodes.Stfld, FieldInfo); + } } - + public void AddressOf (EmitContext ec) { if (FieldInfo.IsStatic) @@ -2225,16 +3120,17 @@ namespace CIR { } } - // - // Expression that evaluates to a Property. The Assign class - // might set the `Value' expression if we are in an assignment. - // - // This is not an LValue because we need to re-write the expression, we - // can not take data from the stack and store it. - // + /// + /// Expression that evaluates to a Property. The Assign class + /// might set the `Value' expression if we are in an assignment. + /// + /// 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 readonly PropertyInfo PropertyInfo; public readonly bool IsStatic; + public bool IsBase; MethodInfo [] Accessors; Location loc; @@ -2295,12 +3191,14 @@ namespace CIR { return null; } + type = PropertyInfo.PropertyType; + return this; } override public void Emit (EmitContext ec) { - Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null); + Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, Accessors [0], null); } @@ -2313,7 +3211,7 @@ namespace CIR { ArrayList args = new ArrayList (); args.Add (arg); - Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args); + Invocation.EmitCall (ec, false, IsStatic, instance_expr, Accessors [1], args); } override public void EmitStatement (EmitContext ec) @@ -2323,31 +3221,62 @@ namespace CIR { } } - // - // Fully resolved expression that evaluates to a Expression - // + /// + /// Fully resolved expression that evaluates to an Event + /// public class EventExpr : Expression { public readonly EventInfo EventInfo; Location loc; + public Expression InstanceExpression; + + public readonly bool IsStatic; + + MethodInfo add_accessor, remove_accessor; public EventExpr (EventInfo ei, Location loc) { EventInfo = ei; this.loc = loc; eclass = ExprClass.EventAccess; + + add_accessor = TypeManager.GetAddMethod (ei); + remove_accessor = TypeManager.GetRemoveMethod (ei); + + if (add_accessor.IsStatic || remove_accessor.IsStatic) + IsStatic = true; + + if (EventInfo is MyEventBuilder) + type = ((MyEventBuilder) EventInfo).EventType; + else + type = EventInfo.EventHandlerType; } override public Expression DoResolve (EmitContext ec) { - // We are born in resolved state. + // We are born fully resolved return this; } override public void Emit (EmitContext ec) { - throw new Exception ("Implement me"); - // FIXME: Implement. + throw new Exception ("Should not happen I think"); + } + + public void EmitAddOrRemove (EmitContext ec, Expression source) + { + Expression handler = ((Binary) source).Right; + + Argument arg = new Argument (handler, Argument.AType.Expression); + ArrayList args = new ArrayList (); + + args.Add (arg); + + if (((Binary) source).Oper == Binary.Operator.Addition) + Invocation.EmitCall ( + ec, false, IsStatic, InstanceExpression, add_accessor, args); + else + Invocation.EmitCall ( + ec, false, IsStatic, InstanceExpression, remove_accessor, args); } } - }