2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Manjula GHM (mmanjula@novell.com)
8 // (C) 2001 Ximian, Inc.
12 namespace Mono.MonoBASIC {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Allows SimpleNames to be returned.
56 // This is used by MemberAccess to construct long names that can not be
57 // partially resolved (namespace-qualified names for example).
60 // Mask of all the expression class flags.
63 // Disable control flow analysis while resolving the expression.
64 // This is used when resolving the instance expression of a field expression.
65 DisableFlowAnalysis = 16
69 // This is just as a hint to AddressOf of what will be done with the
72 public enum AddressOp {
79 /// This interface is implemented by variables
81 public interface IMemoryLocation {
83 /// The AddressOf method should generate code that loads
84 /// the address of the object and leaves it on the stack.
86 /// The 'mode' argument is used to notify the expression
87 /// of whether this will be used to read from the address or
88 /// write to the address.
90 /// This is just a hint that can be used to provide good error
91 /// reporting, and should have no other side effects.
93 void AddressOf (EmitContext ec, AddressOp mode);
97 /// This interface is implemented by variables
99 public interface IVariable {
101 /// Checks whether the variable has already been assigned at
102 /// the current position of the method's control flow and
103 /// reports an appropriate error message if not.
105 /// If the variable is a struct, then this call checks whether
106 /// all of its fields (including all private ones) have been
109 bool IsAssigned (EmitContext ec, Location loc);
112 /// Checks whether field 'name' in this struct has been assigned.
114 bool IsFieldAssigned (EmitContext ec, string name, Location loc);
117 /// Tells the flow analysis code that the variable has already
118 /// been assigned at the current code position.
120 /// If the variable is a struct, this call marks all its fields
121 /// (including private fields) as being assigned.
123 void SetAssigned (EmitContext ec);
126 /// Tells the flow analysis code that field 'name' in this struct
127 /// has already been assigned atthe current code position.
129 void SetFieldAssigned (EmitContext ec, string name);
133 /// This interface denotes an expression which evaluates to a member
134 /// of a struct or a class.
136 public interface IMemberExpr
139 /// The name of this member.
146 /// Whether this is an instance member.
153 /// Whether this is a static member.
160 /// The type which declares this member.
167 /// The instance expression associated with this member, if it's a
168 /// non-static member.
170 Expression InstanceExpression {
176 /// Expression which resolves to a type.
178 public interface ITypeExpression
181 /// Resolve the expression, but only lookup types.
183 Expression DoResolveType (EmitContext ec);
187 /// Base class for expressions
189 public abstract class Expression {
190 public ExprClass eclass;
192 protected Location loc;
204 public Location Location {
211 /// Utility wrapper routine for Error, just to beautify the code
213 public void Error (int error, string s)
215 if (!Location.IsNull (loc))
216 Report.Error (error, loc, s);
218 Report.Error (error, s);
222 /// Utility wrapper routine for Warning, just to beautify the code
224 public void Warning (int warning, string s)
226 if (!Location.IsNull (loc))
227 Report.Warning (warning, loc, s);
229 Report.Warning (warning, s);
233 /// Utility wrapper routine for Warning, only prints the warning if
234 /// warnings of level 'level' are enabled.
236 public void Warning (int warning, int level, string s)
238 if (level <= RootContext.WarningLevel)
239 Warning (warning, s);
242 static public void Error_CannotConvertType (Location loc, Type source, Type target)
244 Report.Error (30, loc, "Cannot convert type '" +
245 TypeManager.MonoBASIC_Name (source) + "' to '" +
246 TypeManager.MonoBASIC_Name (target) + "'");
250 /// Performs semantic analysis on the Expression
254 /// The Resolve method is invoked to perform the semantic analysis
257 /// The return value is an expression (it can be the
258 /// same expression in some cases) or a new
259 /// expression that better represents this node.
261 /// For example, optimizations of Unary (LiteralInt)
262 /// would return a new LiteralInt with a negated
265 /// If there is an error during semantic analysis,
266 /// then an error should be reported (using Report)
267 /// and a null value should be returned.
269 /// There are two side effects expected from calling
270 /// Resolve(): the the field variable "eclass" should
271 /// be set to any value of the enumeration
272 /// 'ExprClass' and the type variable should be set
273 /// to a valid type (this is the type of the
276 public abstract Expression DoResolve (EmitContext ec);
278 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
280 return DoResolve (ec);
284 /// Resolves an expression and performs semantic analysis on it.
288 /// Currently Resolve wraps DoResolve to perform sanity
289 /// checking and assertion checking on what we expect from Resolve.
291 public Expression Resolve (EmitContext ec, ResolveFlags flags)
293 // Are we doing a types-only search ?
294 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) {
295 ITypeExpression type_expr = this as ITypeExpression;
297 if (type_expr == null)
300 return type_expr.DoResolveType (ec);
303 bool old_do_flow_analysis = ec.DoFlowAnalysis;
304 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
305 ec.DoFlowAnalysis = false;
309 if (this is SimpleName)
310 e = ((SimpleName) this).DoResolveAllowStatic (ec);
314 ec.DoFlowAnalysis = old_do_flow_analysis;
320 if (e is SimpleName){
321 SimpleName s = (SimpleName) e;
323 if ((flags & ResolveFlags.SimpleName) == 0) {
325 object lookup = TypeManager.MemberLookup (
326 ec.ContainerType, ec.ContainerType, AllMemberTypes,
327 AllBindingFlags | BindingFlags.NonPublic, s.Name);
329 Error (30390, "'" + s.Name + "' " +
330 "is inaccessible because of its protection level");
332 Error (30451, "The name '" + s.Name + "' could not be " +
333 "found in '" + ec.DeclSpace.Name + "'");
340 if ((e is TypeExpr) || (e is ComposedCast)) {
341 if ((flags & ResolveFlags.Type) == 0) {
351 if ((flags & ResolveFlags.VariableOrValue) == 0) {
357 case ExprClass.MethodGroup:
358 if ((flags & ResolveFlags.MethodGroup) == 0) {
359 MethodGroupExpr mg = (MethodGroupExpr) e;
360 Invocation i = new Invocation (mg, new ArrayList(), Location.Null);
361 Expression te = i.Resolve(ec);
362 //((MethodGroupExpr) e).ReportUsageError ();
368 case ExprClass.Value:
369 case ExprClass.Variable:
370 case ExprClass.PropertyAccess:
371 case ExprClass.EventAccess:
372 case ExprClass.IndexerAccess:
373 if ((flags & ResolveFlags.VariableOrValue) == 0) {
380 throw new Exception ("Expression " + e.GetType () +
381 " ExprClass is Invalid after resolve");
385 throw new Exception (
386 "Expression " + e.GetType () +
387 " did not set its type after Resolve\n" +
388 "called from: " + this.GetType ());
394 /// Resolves an expression and performs semantic analysis on it.
396 public Expression Resolve (EmitContext ec)
398 return Resolve (ec, ResolveFlags.VariableOrValue);
402 /// Resolves an expression for LValue assignment
406 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
407 /// checking and assertion checking on what we expect from Resolve
409 public Expression ResolveLValue (EmitContext ec, Expression right_side)
411 Expression e = DoResolveLValue (ec, right_side);
414 if (e is SimpleName){
415 SimpleName s = (SimpleName) e;
419 "The name '" + s.Name + "' could not be found in '" +
420 ec.DeclSpace.Name + "'");
424 if (e.eclass == ExprClass.Invalid)
425 throw new Exception ("Expression " + e +
426 " ExprClass is Invalid after resolve");
428 if (e.eclass == ExprClass.MethodGroup) {
429 MethodGroupExpr mg = (MethodGroupExpr) e;
430 Invocation i = new Invocation (mg, new ArrayList(), Location.Null);
431 Expression te = i.Resolve(ec);
433 //((MethodGroupExpr) e).ReportUsageError ();
438 throw new Exception ("Expression " + e +
439 " did not set its type after Resolve");
446 /// Emits the code for the expression
450 /// The Emit method is invoked to generate the code
451 /// for the expression.
453 public abstract void Emit (EmitContext ec);
456 /// Protected constructor. Only derivate types should
457 /// be able to be created
460 protected Expression ()
462 eclass = ExprClass.Invalid;
467 /// Returns a literalized version of a literal FieldInfo
471 /// The possible return values are:
472 /// IntConstant, UIntConstant
473 /// LongLiteral, ULongConstant
474 /// FloatConstant, DoubleConstant
477 /// The value returned is already resolved.
479 public static Constant Constantify (object v, Type t)
481 if (t == TypeManager.int32_type)
482 return new IntConstant ((int) v);
483 else if (t == TypeManager.uint32_type)
484 return new UIntConstant ((uint) v);
485 else if (t == TypeManager.int64_type)
486 return new LongConstant ((long) v);
487 else if (t == TypeManager.uint64_type)
488 return new ULongConstant ((ulong) v);
489 else if (t == TypeManager.float_type)
490 return new FloatConstant ((float) v);
491 else if (t == TypeManager.double_type)
492 return new DoubleConstant ((double) v);
493 else if (t == TypeManager.string_type)
494 return new StringConstant ((string) v);
495 else if (t == TypeManager.short_type)
496 return new ShortConstant ((short)v);
497 else if (t == TypeManager.ushort_type)
498 return new UShortConstant ((ushort)v);
499 else if (t == TypeManager.sbyte_type)
500 return new SByteConstant (((sbyte)v));
501 else if (t == TypeManager.byte_type)
502 return new ByteConstant ((byte)v);
503 else if (t == TypeManager.char_type)
504 return new CharConstant ((char)v);
505 else if (t == TypeManager.bool_type)
506 return new BoolConstant ((bool) v);
507 else if (t == TypeManager.decimal_type)
508 return new DecimalConstant ((decimal)v);
509 else if (TypeManager.IsEnumType (t)){
510 Constant e = Constantify (v, TypeManager.TypeToCoreType (v.GetType ()));
512 return new EnumConstant (e, t);
514 throw new Exception ("Unknown type for constant (" + t +
519 /// Returns a fully formed expression after a MemberLookup
521 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
524 return new EventExpr ((EventInfo) mi, loc);
525 else if (mi is FieldInfo)
526 return new FieldExpr ((FieldInfo) mi, loc);
527 else if (mi is PropertyInfo)
528 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
529 else if (mi is Type){
530 return new TypeExpr ((System.Type) mi, loc);
537 // FIXME: Probably implement a cache for (t,name,current_access_set)?
539 // This code could use some optimizations, but we need to do some
540 // measurements. For example, we could use a delegate to 'flag' when
541 // something can not any longer be a method-group (because it is something
545 // If the return value is an Array, then it is an array of
548 // If the return value is an MemberInfo, it is anything, but a Method
552 // FIXME: When calling MemberLookup inside an 'Invocation', we should pass
553 // the arguments here and have MemberLookup return only the methods that
554 // match the argument count/type, unlike we are doing now (we delay this
557 // This is so we can catch correctly attempts to invoke instance methods
558 // from a static body (scan for error 120 in ResolveSimpleName).
561 // FIXME: Potential optimization, have a static ArrayList
564 public static Expression MemberLookup (EmitContext ec, Type t, string name,
565 MemberTypes mt, BindingFlags bf, Location loc)
567 return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
571 // Lookup type 't' for code in class 'invocation_type'. Note that it's important
572 // to set 'invocation_type' correctly since this method also checks whether the
573 // invoking class is allowed to access the member in class 't'. When you want to
574 // explicitly do a lookup in the base class, you must set both 't' and 'invocation_type'
575 // to the base class (although a derived class can access protected members of its base
576 // class it cannot do so through an instance of the base class (error CS1540)).
579 public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
580 string name, MemberTypes mt, BindingFlags bf,
583 MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
588 int count = mi.Length;
590 if (mi [0] is MethodBase)
591 return new MethodGroupExpr (mi, loc);
593 if (mi [0] is PropertyInfo)
594 return new PropertyGroupExpr (mi, loc);
599 return ExprClassFromMemberInfo (ec, mi [0], loc);
602 public const MemberTypes AllMemberTypes =
603 MemberTypes.Constructor |
607 MemberTypes.NestedType |
608 MemberTypes.Property;
610 public const BindingFlags AllBindingFlags =
611 BindingFlags.Public |
612 BindingFlags.Static |
613 BindingFlags.Instance |
614 BindingFlags.IgnoreCase;
616 public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc)
618 return MemberLookup (ec, ec.ContainerType, t, name, AllMemberTypes, AllBindingFlags, loc);
621 public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
623 return MemberLookup (ec, ec.ContainerType, t, name,
624 MemberTypes.Method, AllBindingFlags, loc);
628 /// This is a wrapper for MemberLookup that is not used to "probe", but
629 /// to find a final definition. If the final definition is not found, we
630 /// look for private members and display a useful debugging message if we
633 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
636 return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
639 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
640 MemberTypes mt, BindingFlags bf, Location loc)
644 int errors = Report.Errors;
646 e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
651 // Error has already been reported.
652 if (errors < Report.Errors)
655 e = MemberLookup (ec, t, name, AllMemberTypes,
656 AllBindingFlags | BindingFlags.NonPublic, loc);
659 30456, loc, "'" + t + "' does not contain a definition " +
660 "for '" + name + "'");
663 30390, loc, "'" + t + "." + name +
664 "' is inaccessible due to its protection level");
670 static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
672 EventInfo ei = event_expr.EventInfo;
674 return TypeManager.GetPrivateFieldOfEvent (ei);
677 static EmptyExpression MyEmptyExpr;
678 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
680 Type expr_type = expr.Type;
682 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
683 // if we are a method group, emit a warning
689 // notice that it is possible to write "ValueType v = 1", the ValueType here
690 // is an abstract class, and not really a value type, so we apply the same rules.
692 if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) {
694 // A pointer type cannot be converted to object
696 if (expr_type.IsPointer)
699 if (expr_type.IsValueType)
700 return new BoxedCast (expr);
701 if (expr_type.IsClass || expr_type.IsInterface)
702 return new EmptyCast (expr, target_type);
703 } else if (expr_type.IsSubclassOf (target_type)) {
705 // Special case: enumeration to System.Enum.
706 // System.Enum is not a value type, it is a class, so we need
707 // a boxing conversion
709 if (expr_type.IsEnum)
710 return new BoxedCast (expr);
712 return new EmptyCast (expr, target_type);
715 // This code is kind of mirrored inside StandardConversionExists
716 // with the small distinction that we only probe there
718 // Always ensure that the code here and there is in sync
720 // from the null type to any reference-type.
721 if (expr is NullLiteral && !target_type.IsValueType)
722 return new EmptyCast (expr, target_type);
724 // from any class-type S to any interface-type T.
725 if (target_type.IsInterface) {
726 if (TypeManager.ImplementsInterface (expr_type, target_type)){
727 if (expr_type.IsClass)
728 return new EmptyCast (expr, target_type);
729 else if (expr_type.IsValueType)
730 return new BoxedCast (expr);
734 // from any interface type S to interface-type T.
735 if (expr_type.IsInterface && target_type.IsInterface) {
736 if (TypeManager.ImplementsInterface (expr_type, target_type))
737 return new EmptyCast (expr, target_type);
742 // from an array-type S to an array-type of type T
743 if (expr_type.IsArray && target_type.IsArray) {
744 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
746 Type expr_element_type = expr_type.GetElementType ();
748 if (MyEmptyExpr == null)
749 MyEmptyExpr = new EmptyExpression ();
751 MyEmptyExpr.SetType (expr_element_type);
752 Type target_element_type = target_type.GetElementType ();
754 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
755 if (StandardConversionExists (MyEmptyExpr,
756 target_element_type))
757 return new EmptyCast (expr, target_type);
762 // from an array-type to System.Array
763 if (expr_type.IsArray && target_type == TypeManager.array_type)
764 return new EmptyCast (expr, target_type);
766 // from any delegate type to System.Delegate
767 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
768 target_type == TypeManager.delegate_type)
769 return new EmptyCast (expr, target_type);
771 // from any array-type or delegate type into System.ICloneable.
772 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
773 if (target_type == TypeManager.icloneable_type)
774 return new EmptyCast (expr, target_type);
784 /// Implicit Numeric Conversions.
786 /// expr is the expression to convert, returns a new expression of type
787 /// target_type or null if an implicit conversion is not possible.
789 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
790 Type target_type, Location loc)
792 Type expr_type = expr.Type;
795 // Attempt to do the implicit constant expression conversions
797 if (expr is BoolConstant || expr is IntConstant || expr is LongConstant || expr is DoubleConstant || expr is FloatConstant){
800 e = TryImplicitNumericConversion (target_type, (Constant) expr);
804 if (target_type == TypeManager.byte_type ||
805 target_type == TypeManager.short_type ||
806 target_type == TypeManager.int32_type ||
807 target_type == TypeManager.int64_type ||
808 target_type == TypeManager.float_type) {
811 if (expr is IntConstant)
812 val = ((IntConstant) expr).Value.ToString();
813 if (expr is LongConstant)
814 val = ((LongConstant) expr).Value.ToString();
815 if (expr is FloatConstant)
816 val = ((FloatConstant) expr).Value.ToString();
817 if (expr is DoubleConstant)
818 val = ((DoubleConstant) expr).Value.ToString();
819 Error_ConstantValueCannotBeConverted(loc, val, target_type);
822 } else if (expr is LongConstant && target_type == TypeManager.uint64_type) {
824 // Try the implicit constant expression conversion
825 // from long to ulong, instead of a nice routine,
828 long v = ((LongConstant) expr).Value;
830 return new ULongConstant ((ulong) v);
833 Type real_target_type = target_type;
835 if (target_type == TypeManager.bool_type) {
837 if (expr_type == TypeManager.decimal_type) {
838 return RTConversionExpression (ec, "System.Convert",".ToBoolean" , expr, loc);
841 if ((expr_type != TypeManager.char_type) &&
842 (expr_type != TypeManager.string_type) &&
843 (expr_type != TypeManager.object_type))
844 return new NumericToBoolCast (expr, expr.Type);
847 if (expr_type == TypeManager.bool_type){
849 if (real_target_type == TypeManager.sbyte_type)
850 return new BoolToNumericCast (expr, target_type);
851 if (real_target_type == TypeManager.byte_type)
852 return new BoolToNumericCast (expr, target_type);
853 if (real_target_type == TypeManager.int32_type)
854 return new BoolToNumericCast (expr, target_type);
855 if (real_target_type == TypeManager.int64_type)
856 return new BoolToNumericCast (expr, target_type);
857 if (real_target_type == TypeManager.double_type)
858 return new BoolToNumericCast (expr, target_type);
859 if (real_target_type == TypeManager.float_type)
860 return new BoolToNumericCast (expr, target_type);
861 if (real_target_type == TypeManager.short_type)
862 return new BoolToNumericCast (expr, target_type);
863 if (real_target_type == TypeManager.decimal_type)
864 return RTConversionExpression(ec, "DecimalType.FromBoolean", expr, loc);
865 } else if (expr_type == TypeManager.sbyte_type){
867 // From sbyte to short, int, long, float, double.
869 if (real_target_type == TypeManager.int32_type)
870 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
871 if (real_target_type == TypeManager.int64_type)
872 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
873 if (real_target_type == TypeManager.double_type)
874 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
875 if (real_target_type == TypeManager.float_type)
876 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
877 if (real_target_type == TypeManager.short_type)
878 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
879 } else if (expr_type == TypeManager.byte_type){
881 // From byte to short, ushort, int, uint, long, ulong, float, double
883 if ((real_target_type == TypeManager.short_type) ||
884 (real_target_type == TypeManager.ushort_type) ||
885 (real_target_type == TypeManager.int32_type) ||
886 (real_target_type == TypeManager.uint32_type))
887 return new EmptyCast (expr, target_type);
889 if (real_target_type == TypeManager.uint64_type)
890 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
891 if (real_target_type == TypeManager.int64_type)
892 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
893 if (real_target_type == TypeManager.float_type)
894 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
895 if (real_target_type == TypeManager.double_type)
896 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
897 } else if (expr_type == TypeManager.short_type){
899 // From short to int, long, float, double
901 if (real_target_type == TypeManager.int32_type)
902 return new EmptyCast (expr, target_type);
903 if (real_target_type == TypeManager.int64_type)
904 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
905 if (real_target_type == TypeManager.double_type)
906 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
907 if (real_target_type == TypeManager.float_type)
908 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
909 } else if (expr_type == TypeManager.ushort_type){
911 // From ushort to int, uint, long, ulong, float, double
913 if (real_target_type == TypeManager.uint32_type)
914 return new EmptyCast (expr, target_type);
916 if (real_target_type == TypeManager.uint64_type)
917 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
918 if (real_target_type == TypeManager.int32_type)
919 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
920 if (real_target_type == TypeManager.int64_type)
921 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
922 if (real_target_type == TypeManager.double_type)
923 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
924 if (real_target_type == TypeManager.float_type)
925 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
926 } else if (expr_type == TypeManager.int32_type){
928 // From int to long, float, double
930 if (real_target_type == TypeManager.int64_type)
931 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
932 if (real_target_type == TypeManager.double_type)
933 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
934 if (real_target_type == TypeManager.float_type)
935 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
936 } else if (expr_type == TypeManager.uint32_type){
938 // From uint to long, ulong, float, double
940 if (real_target_type == TypeManager.int64_type)
941 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
942 if (real_target_type == TypeManager.uint64_type)
943 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
944 if (real_target_type == TypeManager.double_type)
945 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
947 if (real_target_type == TypeManager.float_type)
948 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
950 } else if (expr_type == TypeManager.int64_type){
952 // From long/ulong to float, double
954 if (real_target_type == TypeManager.double_type)
955 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
956 if (real_target_type == TypeManager.float_type)
957 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
958 } else if (expr_type == TypeManager.uint64_type){
960 // From ulong to float, double
962 if (real_target_type == TypeManager.double_type)
963 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
965 if (real_target_type == TypeManager.float_type)
966 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
968 } else if (expr_type == TypeManager.string_type){
970 if (real_target_type == TypeManager.bool_type)
971 return RTConversionExpression (ec, "BooleanType.FromString" , expr, loc);
972 if (real_target_type == TypeManager.decimal_type)
973 return RTConversionExpression (ec, "DecimalType.FromString" , expr, loc);
974 if (real_target_type == TypeManager.float_type)
975 return RTConversionExpression (ec, "SingleType.FromString" , expr, loc);
976 if (real_target_type == TypeManager.short_type)
977 return RTConversionExpression (ec, "ShortType.FromString" , expr, loc);
978 if (real_target_type == TypeManager.int64_type)
979 return RTConversionExpression (ec, "LongType.FromString" , expr, loc);
980 if (real_target_type == TypeManager.int32_type)
981 return RTConversionExpression (ec, "IntegerType.FromString" , expr, loc);
982 if (real_target_type == TypeManager.double_type)
983 return RTConversionExpression (ec, "DoubleType.FromString" , expr, loc);
984 if (real_target_type == TypeManager.byte_type)
985 return RTConversionExpression (ec, "ByteType.FromString" , expr, loc);
986 } else if (expr_type == TypeManager.float_type){
990 if (real_target_type == TypeManager.decimal_type)
991 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
992 if (real_target_type == TypeManager.double_type)
993 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
995 } else if (expr_type == TypeManager.double_type){
997 if (real_target_type == TypeManager.decimal_type)
998 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
999 } else if (expr_type == TypeManager.decimal_type){
1001 if (real_target_type == TypeManager.bool_type)
1002 return RTConversionExpression (ec, "BooleanType.FromDecimal" , expr, loc);
1003 if (real_target_type == TypeManager.short_type)
1004 return RTConversionExpression(ec, "System.Convert", ".ToInt16", expr, loc);
1005 if (real_target_type == TypeManager.byte_type)
1006 return RTConversionExpression(ec, "System.Convert", ".ToByte", expr, loc);
1007 if (real_target_type == TypeManager.int32_type)
1008 return RTConversionExpression(ec, "System.Convert", ".ToInt32", expr, loc);
1009 if (real_target_type == TypeManager.int64_type)
1010 return RTConversionExpression(ec, "System.Convert", ".ToInt64", expr, loc);
1011 if (real_target_type == TypeManager.float_type)
1012 return RTConversionExpression(ec, "System.Convert", ".ToSingle", expr, loc);
1013 if (real_target_type == TypeManager.double_type)
1014 return RTConversionExpression(ec, "System.Convert", ".ToDouble", expr, loc);
1021 // Tests whether an implicit reference conversion exists between expr_type
1024 public static bool ImplicitReferenceConversionExists (Expression expr, Type expr_type, Type target_type)
1027 // This is the boxed case.
1029 if (target_type == TypeManager.object_type) {
1030 if ((expr_type.IsClass) ||
1031 (expr_type.IsValueType) ||
1032 (expr_type.IsInterface))
1035 } else if (expr_type.IsSubclassOf (target_type)) {
1038 // Please remember that all code below actually comes
1039 // from ImplicitReferenceConversion so make sure code remains in sync
1041 // from any class-type S to any interface-type T.
1042 if (target_type.IsInterface) {
1043 if (TypeManager.ImplementsInterface (expr_type, target_type))
1047 // from any interface type S to interface-type T.
1048 if (expr_type.IsInterface && target_type.IsInterface)
1049 if (TypeManager.ImplementsInterface (expr_type, target_type))
1052 // from an array-type S to an array-type of type T
1053 if (expr_type.IsArray && target_type.IsArray) {
1054 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
1056 Type expr_element_type = expr_type.GetElementType ();
1058 if (MyEmptyExpr == null)
1059 MyEmptyExpr = new EmptyExpression ();
1061 MyEmptyExpr.SetType (expr_element_type);
1062 Type target_element_type = target_type.GetElementType ();
1064 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
1065 if (StandardConversionExists (MyEmptyExpr,
1066 target_element_type))
1071 // from an array-type to System.Array
1072 if (expr_type.IsArray && (target_type == TypeManager.array_type))
1075 // from any delegate type to System.Delegate
1076 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
1077 target_type == TypeManager.delegate_type)
1078 if (target_type.IsAssignableFrom (expr_type))
1081 // from any array-type or delegate type into System.ICloneable.
1082 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
1083 if (target_type == TypeManager.icloneable_type)
1086 // from the null type to any reference-type.
1087 if (expr is NullLiteral && !target_type.IsValueType &&
1088 !TypeManager.IsEnumType (target_type))
1097 /// Same as StandardConversionExists except that it also looks at
1098 /// implicit user defined conversions - needed for overload resolution
1100 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
1102 if (StandardConversionExists (expr, target_type) == true)
1106 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
1116 /// Determines if a standard implicit conversion exists from
1117 /// expr_type to target_type
1119 public static bool StandardConversionExists (Expression expr, Type target_type)
1121 return WideningConversionExists (expr, expr.type, target_type);
1124 public static bool WideningConversionExists (Type expr_type, Type target_type)
1126 return WideningConversionExists (null, expr_type, target_type);
1129 public static bool WideningConversionExists (Expression expr, Type target_type)
1131 return WideningConversionExists (expr, expr.Type, target_type);
1134 public static bool WideningConversionExists (Expression expr, Type expr_type, Type target_type)
1137 if (expr_type == null || expr_type == TypeManager.void_type)
1140 if (expr_type == target_type)
1143 // Conversions from enum to underlying type are widening.
1144 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1145 expr_type = TypeManager.EnumToUnderlying (expr_type);
1147 if (expr_type == target_type)
1150 // First numeric conversions
1152 if (expr_type == TypeManager.sbyte_type){
1154 // From sbyte to short, int, long, float, double.
1156 if ((target_type == TypeManager.int32_type) ||
1157 (target_type == TypeManager.int64_type) ||
1158 (target_type == TypeManager.double_type) ||
1159 (target_type == TypeManager.float_type) ||
1160 (target_type == TypeManager.short_type) ||
1161 (target_type == TypeManager.decimal_type))
1164 } else if (expr_type == TypeManager.byte_type){
1166 // From byte to short, ushort, int, uint, long, ulong, float, double
1168 if ((target_type == TypeManager.short_type) ||
1169 (target_type == TypeManager.bool_type) ||
1170 (target_type == TypeManager.ushort_type) ||
1171 (target_type == TypeManager.int32_type) ||
1172 (target_type == TypeManager.uint32_type) ||
1173 (target_type == TypeManager.uint64_type) ||
1174 (target_type == TypeManager.int64_type) ||
1175 (target_type == TypeManager.float_type) ||
1176 (target_type == TypeManager.double_type) ||
1177 (target_type == TypeManager.decimal_type))
1180 } else if (expr_type == TypeManager.short_type){
1182 // From short to int, long, float, double
1184 if ((target_type == TypeManager.int32_type) ||
1185 (target_type == TypeManager.bool_type) ||
1186 (target_type == TypeManager.int64_type) ||
1187 (target_type == TypeManager.double_type) ||
1188 (target_type == TypeManager.float_type) ||
1189 (target_type == TypeManager.decimal_type))
1192 } else if (expr_type == TypeManager.ushort_type){
1194 // From ushort to int, uint, long, ulong, float, double
1196 if ((target_type == TypeManager.uint32_type) ||
1197 (target_type == TypeManager.uint64_type) ||
1198 (target_type == TypeManager.int32_type) ||
1199 (target_type == TypeManager.int64_type) ||
1200 (target_type == TypeManager.double_type) ||
1201 (target_type == TypeManager.float_type) ||
1202 (target_type == TypeManager.decimal_type))
1205 } else if (expr_type == TypeManager.int32_type){
1207 // From int to long, float, double
1209 if ((target_type == TypeManager.int64_type) ||
1210 (target_type == TypeManager.bool_type) ||
1211 (target_type == TypeManager.double_type) ||
1212 (target_type == TypeManager.float_type) ||
1213 (target_type == TypeManager.decimal_type))
1216 } else if (expr_type == TypeManager.uint32_type){
1218 // From uint to long, ulong, float, double
1220 if ((target_type == TypeManager.int64_type) ||
1221 (target_type == TypeManager.bool_type) ||
1222 (target_type == TypeManager.uint64_type) ||
1223 (target_type == TypeManager.double_type) ||
1224 (target_type == TypeManager.float_type) ||
1225 (target_type == TypeManager.decimal_type))
1228 } else if ((expr_type == TypeManager.uint64_type) ||
1229 (expr_type == TypeManager.int64_type)) {
1231 // From long/ulong to float, double
1233 if ((target_type == TypeManager.double_type) ||
1234 (target_type == TypeManager.bool_type) ||
1235 (target_type == TypeManager.float_type) ||
1236 (target_type == TypeManager.decimal_type))
1239 } else if (expr_type == TypeManager.decimal_type) {
1240 if (target_type == TypeManager.float_type ||
1241 target_type == TypeManager.double_type)
1243 } else if (expr_type == TypeManager.float_type){
1245 // float to double, decimal
1247 if (target_type == TypeManager.double_type)
1249 } else if (expr_type == TypeManager.double_type){
1251 if ((target_type == TypeManager.bool_type))
1255 if (ImplicitReferenceConversionExists (expr, expr_type, target_type))
1259 if (expr is IntConstant){
1260 int value = ((IntConstant) expr).Value;
1262 if (target_type == TypeManager.sbyte_type){
1263 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1265 } else if (target_type == TypeManager.byte_type){
1266 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1268 } else if (target_type == TypeManager.short_type){
1269 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1271 } else if (target_type == TypeManager.ushort_type){
1272 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1274 } else if (target_type == TypeManager.uint32_type){
1277 } else if (target_type == TypeManager.uint64_type){
1279 // we can optimize this case: a positive int32
1280 // always fits on a uint64. But we need an opcode
1287 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
1291 if (expr is LongConstant && target_type == TypeManager.uint64_type){
1293 // Try the implicit constant expression conversion
1294 // from long to ulong, instead of a nice routine,
1295 // we just inline it
1297 long v = ((LongConstant) expr).Value;
1303 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1304 IntLiteral i = (IntLiteral) expr;
1310 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
1317 // Used internally by FindMostEncompassedType, this is used
1318 // to avoid creating lots of objects in the tight loop inside
1319 // FindMostEncompassedType
1321 static EmptyExpression priv_fmet_param;
1324 /// Finds "most encompassed type" according to the spec (13.4.2)
1325 /// amongst the methods in the MethodGroupExpr
1327 static Type FindMostEncompassedType (ArrayList types)
1331 if (priv_fmet_param == null)
1332 priv_fmet_param = new EmptyExpression ();
1334 foreach (Type t in types){
1335 priv_fmet_param.SetType (t);
1342 if (StandardConversionExists (priv_fmet_param, best))
1350 // Used internally by FindMostEncompassingType, this is used
1351 // to avoid creating lots of objects in the tight loop inside
1352 // FindMostEncompassingType
1354 static EmptyExpression priv_fmee_ret;
1357 /// Finds "most encompassing type" according to the spec (13.4.2)
1358 /// amongst the types in the given set
1360 static Type FindMostEncompassingType (ArrayList types)
1364 if (priv_fmee_ret == null)
1365 priv_fmee_ret = new EmptyExpression ();
1367 foreach (Type t in types){
1368 priv_fmee_ret.SetType (best);
1375 if (StandardConversionExists (priv_fmee_ret, t))
1383 // Used to avoid creating too many objects
1385 static EmptyExpression priv_fms_expr;
1388 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
1389 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
1390 /// for explicit and implicit conversion operators.
1392 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
1393 bool apply_explicit_conv_rules,
1396 ArrayList src_types_set = new ArrayList ();
1398 if (priv_fms_expr == null)
1399 priv_fms_expr = new EmptyExpression ();
1402 // If any operator converts from S then Sx = S
1404 Type source_type= source.Type;
1405 foreach (MethodBase mb in me.Methods){
1406 ParameterData pd = Invocation.GetParameterData (mb);
1407 Type param_type = pd.ParameterType (0);
1409 if (param_type == source_type)
1412 if (apply_explicit_conv_rules) {
1415 // Find the set of applicable user-defined conversion operators, U. This set
1417 // user-defined implicit or explicit conversion operators declared by
1418 // the classes or structs in D that convert from a type encompassing
1419 // or encompassed by S to a type encompassing or encompassed by T
1421 priv_fms_expr.SetType (param_type);
1422 if (StandardConversionExists (priv_fms_expr, source_type))
1423 src_types_set.Add (param_type);
1425 if (StandardConversionExists (source, param_type))
1426 src_types_set.Add (param_type);
1430 // Only if S is encompassed by param_type
1432 if (StandardConversionExists (source, param_type))
1433 src_types_set.Add (param_type);
1438 // Explicit Conv rules
1440 if (apply_explicit_conv_rules) {
1441 ArrayList candidate_set = new ArrayList ();
1443 foreach (Type param_type in src_types_set){
1444 if (StandardConversionExists (source, param_type))
1445 candidate_set.Add (param_type);
1448 if (candidate_set.Count != 0)
1449 return FindMostEncompassedType (candidate_set);
1455 if (apply_explicit_conv_rules)
1456 return FindMostEncompassingType (src_types_set);
1458 return FindMostEncompassedType (src_types_set);
1462 // Useful in avoiding proliferation of objects
1464 static EmptyExpression priv_fmt_expr;
1467 /// Finds the most specific target Tx according to section 13.4.4
1469 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
1470 bool apply_explicit_conv_rules,
1473 ArrayList tgt_types_set = new ArrayList ();
1475 if (priv_fmt_expr == null)
1476 priv_fmt_expr = new EmptyExpression ();
1479 // If any operator converts to T then Tx = T
1481 foreach (MethodInfo mi in me.Methods){
1482 Type ret_type = mi.ReturnType;
1484 if (ret_type == target)
1487 if (apply_explicit_conv_rules) {
1490 // Find the set of applicable user-defined conversion operators, U.
1492 // This set consists of the
1493 // user-defined implicit or explicit conversion operators declared by
1494 // the classes or structs in D that convert from a type encompassing
1495 // or encompassed by S to a type encompassing or encompassed by T
1497 priv_fms_expr.SetType (ret_type);
1498 if (StandardConversionExists (priv_fms_expr, target))
1499 tgt_types_set.Add (ret_type);
1501 priv_fms_expr.SetType (target);
1502 if (StandardConversionExists (priv_fms_expr, ret_type))
1503 tgt_types_set.Add (ret_type);
1507 // Only if T is encompassed by param_type
1509 priv_fms_expr.SetType (ret_type);
1510 if (StandardConversionExists (priv_fms_expr, target))
1511 tgt_types_set.Add (ret_type);
1516 // Explicit conv rules
1518 if (apply_explicit_conv_rules) {
1519 ArrayList candidate_set = new ArrayList ();
1521 foreach (Type ret_type in tgt_types_set){
1522 priv_fmt_expr.SetType (ret_type);
1524 if (StandardConversionExists (priv_fmt_expr, target))
1525 candidate_set.Add (ret_type);
1528 if (candidate_set.Count != 0)
1529 return FindMostEncompassingType (candidate_set);
1533 // Okay, final case !
1535 if (apply_explicit_conv_rules)
1536 return FindMostEncompassedType (tgt_types_set);
1538 return FindMostEncompassingType (tgt_types_set);
1542 /// User-defined Implicit conversions
1544 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1545 Type target, Location loc)
1547 return UserDefinedConversion (ec, source, target, loc, false);
1551 /// User-defined Explicit conversions
1553 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1554 Type target, Location loc)
1556 return UserDefinedConversion (ec, source, target, loc, true);
1560 /// Computes the MethodGroup for the user-defined conversion
1561 /// operators from source_type to target_type. 'look_for_explicit'
1562 /// controls whether we should also include the list of explicit
1565 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1566 Type source_type, Type target_type,
1567 Location loc, bool look_for_explicit)
1569 Expression mg1 = null, mg2 = null;
1570 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1574 // FIXME : How does the False operator come into the picture ?
1575 // This doesn't look complete and very correct !
1577 if (target_type == TypeManager.bool_type && !look_for_explicit)
1578 op_name = "op_True";
1580 op_name = "op_Implicit";
1582 MethodGroupExpr union3;
1584 mg1 = MethodLookup (ec, source_type, op_name, loc);
1585 if (source_type.BaseType != null)
1586 mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1589 union3 = (MethodGroupExpr) mg2;
1590 else if (mg2 == null)
1591 union3 = (MethodGroupExpr) mg1;
1593 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1595 mg1 = MethodLookup (ec, target_type, op_name, loc);
1598 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1600 union3 = (MethodGroupExpr) mg1;
1603 if (target_type.BaseType != null)
1604 mg1 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1608 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1610 union3 = (MethodGroupExpr) mg1;
1613 MethodGroupExpr union4 = null;
1615 if (look_for_explicit) {
1616 op_name = "op_Explicit";
1618 mg5 = MemberLookup (ec, source_type, op_name, loc);
1619 if (source_type.BaseType != null)
1620 mg6 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1622 mg7 = MemberLookup (ec, target_type, op_name, loc);
1623 if (target_type.BaseType != null)
1624 mg8 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1626 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1627 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1629 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1632 return Invocation.MakeUnionSet (union3, union4, loc);
1636 /// User-defined conversions
1638 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1639 Type target, Location loc,
1640 bool look_for_explicit)
1642 MethodGroupExpr union;
1643 Type source_type = source.Type;
1644 MethodBase method = null;
1646 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1650 Type most_specific_source, most_specific_target;
1653 foreach (MethodBase m in union.Methods){
1654 Console.WriteLine ("Name: " + m.Name);
1655 Console.WriteLine (" : " + ((MethodInfo)m).ReturnType);
1659 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
1660 if (most_specific_source == null)
1663 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
1664 if (most_specific_target == null)
1669 foreach (MethodBase mb in union.Methods){
1670 ParameterData pd = Invocation.GetParameterData (mb);
1671 MethodInfo mi = (MethodInfo) mb;
1673 if (pd.ParameterType (0) == most_specific_source &&
1674 mi.ReturnType == most_specific_target) {
1680 if (method == null || count > 1)
1685 // This will do the conversion to the best match that we
1686 // found. Now we need to perform an implict standard conversion
1687 // if the best match was not the type that we were requested
1690 if (look_for_explicit)
1691 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1693 source = ConvertImplicitStandard (ec, source, most_specific_source, loc);
1699 e = new UserCast ((MethodInfo) method, source, loc);
1700 if (e.Type != target){
1701 if (!look_for_explicit)
1702 e = ConvertImplicitStandard (ec, e, target, loc);
1704 e = ConvertExplicitStandard (ec, e, target, loc);
1710 /// Converts implicitly the resolved expression 'expr' into the
1711 /// 'target_type'. It returns a new expression that can be used
1712 /// in a context that expects a 'target_type'.
1714 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1715 Type target_type, Location loc)
1717 Type expr_type = expr.Type;
1721 if (expr_type == target_type)
1724 if (target_type == null)
1725 throw new Exception ("Target type is null");
1727 e = ConvertImplicitStandard (ec, expr, target_type, loc);
1731 e = ImplicitUserConversion (ec, expr, target_type, loc);
1736 e = NarrowingConversion (ec, expr, target_type, loc);
1744 /// Converts the resolved expression 'expr' into the
1745 /// 'target_type' using the Microsoft.VisualBasic runtime.
1746 /// It returns a new expression that can be used
1747 /// in a context that expects a 'target_type'.
1749 static private Expression RTConversionExpression (EmitContext ec, string s, Expression expr, Location loc)
1755 etmp = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices." + s, loc);
1756 args = new ArrayList();
1757 arg = new Argument (expr, Argument.AType.Expression);
1759 e = (Expression) new Invocation (etmp, args, loc);
1764 static private Expression RTConversionExpression (EmitContext ec, string ns, string method, Expression expr, Location loc)
1770 etmp = Mono.MonoBASIC.Parser.DecomposeQI(ns+method, loc);
1771 args = new ArrayList();
1772 arg = new Argument (expr, Argument.AType.Expression);
1774 e = (Expression) new Invocation (etmp, args, loc);
1780 static public bool NarrowingConversionExists (EmitContext ec, Expression expr, Type target_type)
1782 Type expr_type = expr.Type;
1783 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1784 expr_type = TypeManager.EnumToUnderlying (expr_type);
1786 if (target_type.IsSubclassOf (TypeManager.enum_type))
1787 target_type = TypeManager.EnumToUnderlying (target_type);
1790 if (expr_type == target_type)
1793 if (target_type == TypeManager.sbyte_type){
1795 // To sbyte from short, int, long, float, double.
1797 if ((expr_type == TypeManager.int32_type) ||
1798 (expr_type == TypeManager.int64_type) ||
1799 (expr_type == TypeManager.double_type) ||
1800 (expr_type == TypeManager.float_type) ||
1801 (expr_type == TypeManager.short_type) ||
1802 (expr_type == TypeManager.decimal_type))
1805 } else if (target_type == TypeManager.byte_type){
1807 // To byte from short, ushort, int, uint, long, ulong, float, double
1809 if ((expr_type == TypeManager.short_type) ||
1810 (expr_type == TypeManager.ushort_type) ||
1811 (expr_type == TypeManager.int32_type) ||
1812 (expr_type == TypeManager.uint32_type) ||
1813 (expr_type == TypeManager.uint64_type) ||
1814 (expr_type == TypeManager.int64_type) ||
1815 (expr_type == TypeManager.float_type) ||
1816 (expr_type == TypeManager.double_type) ||
1817 (expr_type == TypeManager.decimal_type))
1820 } else if (target_type == TypeManager.short_type){
1822 // To short from int, long, float, double
1824 if ((expr_type == TypeManager.int32_type) ||
1825 (expr_type == TypeManager.int64_type) ||
1826 (expr_type == TypeManager.double_type) ||
1827 (expr_type == TypeManager.float_type) ||
1828 (expr_type == TypeManager.decimal_type))
1831 } else if (target_type == TypeManager.ushort_type){
1833 // To ushort from int, uint, long, ulong, float, double
1835 if ((expr_type == TypeManager.uint32_type) ||
1836 (expr_type == TypeManager.uint64_type) ||
1837 (expr_type == TypeManager.int32_type) ||
1838 (expr_type == TypeManager.int64_type) ||
1839 (expr_type == TypeManager.double_type) ||
1840 (expr_type == TypeManager.float_type) ||
1841 (expr_type == TypeManager.decimal_type))
1844 } else if (target_type == TypeManager.int32_type){
1846 // To int from long, float, double
1848 if ((expr_type == TypeManager.int64_type) ||
1849 (expr_type == TypeManager.double_type) ||
1850 (expr_type == TypeManager.float_type) ||
1851 (expr_type == TypeManager.decimal_type))
1854 } else if (target_type == TypeManager.uint32_type){
1856 // To uint from long, ulong, float, double
1858 if ((expr_type == TypeManager.int64_type) ||
1859 (expr_type == TypeManager.uint64_type) ||
1860 (expr_type == TypeManager.double_type) ||
1861 (expr_type == TypeManager.float_type) ||
1862 (expr_type == TypeManager.decimal_type))
1865 } else if ((target_type == TypeManager.uint64_type) ||
1866 (target_type == TypeManager.int64_type)) {
1868 // To long/ulong from float, double
1870 if ((expr_type == TypeManager.double_type) ||
1871 (expr_type == TypeManager.float_type) ||
1872 (expr_type == TypeManager.decimal_type))
1875 } else if (target_type == TypeManager.decimal_type){
1876 if (expr_type == TypeManager.float_type ||
1877 expr_type == TypeManager.double_type)
1879 } else if (target_type == TypeManager.float_type){
1881 // To float from double
1883 if (expr_type == TypeManager.double_type)
1887 return (NarrowingConversion (ec, expr, target_type,Location.Null)) != null;
1890 static public Expression NarrowingConversion (EmitContext ec, Expression expr,
1891 Type target_type, Location loc)
1893 Type expr_type = expr.Type;
1895 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1896 expr_type = TypeManager.EnumToUnderlying (expr_type);
1898 if (target_type.IsSubclassOf (TypeManager.enum_type))
1899 target_type = TypeManager.EnumToUnderlying (target_type);
1901 if (expr_type == target_type)
1904 if (target_type == TypeManager.sbyte_type){
1906 // To sbyte from short, int, long, float, double.
1908 if (expr_type == TypeManager.int32_type)
1909 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1910 if (expr_type == TypeManager.int64_type)
1911 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1912 if (expr_type == TypeManager.short_type)
1913 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1915 if (expr_type == TypeManager.float_type) {
1916 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1917 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
1919 if (expr_type == TypeManager.double_type) {
1920 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1921 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
1924 } else if (target_type == TypeManager.byte_type){
1926 // To byte from short, ushort, int, uint, long, ulong, float, double
1928 if (expr_type == TypeManager.short_type)
1929 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1930 if (expr_type == TypeManager.ushort_type)
1931 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1932 if (expr_type == TypeManager.int32_type)
1933 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1934 if (expr_type == TypeManager.uint32_type)
1935 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1936 if (expr_type == TypeManager.uint64_type)
1937 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1938 if (expr_type == TypeManager.int64_type)
1939 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1941 if (expr_type == TypeManager.float_type) {
1942 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1943 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
1945 if (expr_type == TypeManager.double_type) {
1946 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1947 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
1950 } else if (target_type == TypeManager.short_type) {
1952 // To short from int, long, float, double
1954 if (expr_type == TypeManager.int32_type)
1955 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1956 if (expr_type == TypeManager.int64_type)
1957 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1959 if (expr_type == TypeManager.float_type) {
1960 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1961 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
1963 if (expr_type == TypeManager.double_type) {
1964 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1965 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
1968 } else if (target_type == TypeManager.ushort_type) {
1970 // To ushort from int, uint, long, ulong, float, double
1972 if (expr_type == TypeManager.uint32_type)
1973 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1974 if (expr_type == TypeManager.uint64_type)
1975 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1976 if (expr_type == TypeManager.int32_type)
1977 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1978 if (expr_type == TypeManager.int64_type)
1979 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1981 if (expr_type == TypeManager.float_type) {
1982 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1983 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
1986 if (expr_type == TypeManager.double_type) {
1987 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1988 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
1991 } else if (target_type == TypeManager.int32_type){
1993 // To int from long, float, double
1995 if (expr_type == TypeManager.int64_type)
1996 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1998 if (expr_type == TypeManager.float_type) {
1999 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2000 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2002 if (expr_type == TypeManager.double_type) {
2003 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2004 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2007 } else if (target_type == TypeManager.uint32_type){
2009 // To uint from long, ulong, float, double
2011 if (expr_type == TypeManager.int64_type)
2012 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2013 if (expr_type == TypeManager.uint64_type)
2014 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2015 if (expr_type == TypeManager.float_type) {
2016 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2017 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2019 if (expr_type == TypeManager.double_type) {
2020 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2021 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2024 } else if (target_type == TypeManager.uint64_type) {
2026 // To long/ulong from float, double
2028 if (expr_type == TypeManager.float_type) {
2029 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2030 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2032 if (expr_type == TypeManager.double_type) {
2033 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2034 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2037 } else if (target_type == TypeManager.int64_type) {
2039 // To long/ulong from float, double
2041 if (expr_type == TypeManager.float_type) {
2042 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2043 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2045 if (expr_type == TypeManager.double_type) {
2046 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2047 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2050 } else if (target_type == TypeManager.float_type){
2052 // To float from double
2054 if (expr_type == TypeManager.double_type)
2055 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2058 TypeCode dest_type = Type.GetTypeCode (target_type);
2059 TypeCode src_type = Type.GetTypeCode (expr_type);
2060 Expression e = null;
2062 switch (dest_type) {
2063 case TypeCode.String:
2065 case TypeCode.SByte:
2067 e = RTConversionExpression(ec, "StringType.FromByte", expr, loc);
2069 case TypeCode.UInt16:
2070 case TypeCode.Int16:
2071 e = RTConversionExpression(ec, "StringType.FromShort", expr, loc);
2073 case TypeCode.UInt32:
2074 case TypeCode.Int32:
2075 e = RTConversionExpression(ec, "StringType.FromInteger", expr, loc);
2077 case TypeCode.UInt64:
2078 case TypeCode.Int64:
2079 e = RTConversionExpression(ec, "StringType.FromLong", expr, loc);
2082 e = RTConversionExpression(ec, "StringType.FromChar", expr, loc);
2084 case TypeCode.Single:
2085 e = RTConversionExpression(ec, "StringType.FromSingle", expr, loc);
2087 case TypeCode.Double:
2088 e = RTConversionExpression(ec, "StringType.FromDouble", expr, loc);
2090 case TypeCode.Boolean:
2091 e = RTConversionExpression(ec, "StringType.FromBoolean", expr, loc);
2093 case TypeCode.DateTime:
2094 e = RTConversionExpression(ec, "StringType.FromDate", expr, loc);
2096 case TypeCode.Decimal:
2097 e = RTConversionExpression(ec, "StringType.FromDecimal", expr, loc);
2099 case TypeCode.Object:
2100 e = RTConversionExpression(ec, "StringType.FromObject", expr, loc);
2105 case TypeCode.Double:
2107 case TypeCode.String:
2108 e = RTConversionExpression(ec, "DoubleType.FromString", expr, loc);
2110 case TypeCode.Object:
2111 e = RTConversionExpression(ec, "DoubleType.FromObject", expr, loc);
2116 case TypeCode.Single:
2118 case TypeCode.String:
2119 e = RTConversionExpression(ec, "SingleType.FromString", expr, loc);
2121 case TypeCode.Object:
2122 e = RTConversionExpression(ec, "SingleType.FromObject", expr, loc);
2127 case TypeCode.Decimal:
2129 case TypeCode.String:
2130 e = RTConversionExpression(ec, "DecimalType.FromString", expr, loc);
2132 case TypeCode.Object:
2133 e = RTConversionExpression(ec, "DecimalType.FromObject", expr, loc);
2138 case TypeCode.Int64:
2139 case TypeCode.UInt64:
2141 case TypeCode.String:
2142 e = RTConversionExpression(ec, "LongType.FromString", expr, loc);
2144 case TypeCode.Object:
2145 e = RTConversionExpression(ec, "LongType.FromObject", expr, loc);
2149 case TypeCode.Int32:
2150 case TypeCode.UInt32:
2152 case TypeCode.String:
2153 e = RTConversionExpression(ec, "IntegerType.FromString", expr, loc);
2155 case TypeCode.Object:
2156 e = RTConversionExpression(ec, "IntegerType.FromObject", expr, loc);
2161 case TypeCode.Int16:
2162 case TypeCode.UInt16:
2164 case TypeCode.String:
2165 e = RTConversionExpression(ec, "ShortType.FromString", expr, loc);
2167 case TypeCode.Object:
2168 e = RTConversionExpression(ec, "ShortType.FromObject", expr, loc);
2175 case TypeCode.String:
2176 e = RTConversionExpression(ec, "BooleanType.FromString", expr, loc);
2178 case TypeCode.Object:
2179 e = RTConversionExpression(ec, "ByteType.FromObject", expr, loc);
2183 case TypeCode.Boolean:
2185 case TypeCode.String:
2186 e = RTConversionExpression(ec, "BooleanType.FromString", expr, loc);
2188 case TypeCode.Object:
2189 e = RTConversionExpression(ec, "BooleanType.FromObject", expr, loc);
2193 case TypeCode.DateTime:
2195 case TypeCode.String:
2196 e = RTConversionExpression(ec, "DateType.FromString", expr, loc);
2198 case TypeCode.Object:
2199 e = RTConversionExpression(ec, "DateType.FromObject", expr, loc);
2206 case TypeCode.String:
2207 e = RTConversionExpression(ec, "CharType.FromString", expr, loc);
2214 // We must examine separately some types that
2215 // don't have a TypeCode but are supported
2217 if (expr_type == typeof(System.String) && target_type == typeof (System.Char[])) {
2218 e = RTConversionExpression(ec, "CharArrayType.FromString", expr, loc);
2222 // VB.NET Objects can be converted to anything by default
2223 // unless, that is, an exception at runtime blows it all
2224 if (src_type == TypeCode.Object) {
2225 Expression cast_type = Mono.MonoBASIC.Parser.DecomposeQI(target_type.ToString(), loc);
2226 Cast ce = new Cast (cast_type, expr, loc);
2227 ce.IsRuntimeCast = true;
2228 return ce.Resolve (ec);
2233 static public Expression ConvertNothingToDefaultValues (EmitContext ec, Expression expr,
2234 Type target_type, Location loc)
2236 switch (Type.GetTypeCode (target_type)) {
2237 case TypeCode.Boolean :
2238 return new BoolConstant (false);
2239 case TypeCode.Byte :
2240 return new ByteConstant (0);
2241 case TypeCode.Char :
2242 return new CharConstant ((char)0);
2243 case TypeCode.SByte :
2244 return new SByteConstant (0);
2245 case TypeCode.Int16 :
2246 return new ShortConstant (0);
2247 case TypeCode.Int32 :
2248 return new IntConstant (0);
2249 case TypeCode.Int64 :
2250 return new LongConstant (0);
2251 case TypeCode.Decimal :
2252 return new DecimalConstant (System.Decimal.Zero);
2253 case TypeCode.Single :
2254 return new FloatConstant (0.0F);
2255 case TypeCode.Double :
2256 return new DoubleConstant (0.0);
2263 /// Attempts to apply the 'Standard Implicit
2264 /// Conversion' rules to the expression 'expr' into
2265 /// the 'target_type'. It returns a new expression
2266 /// that can be used in a context that expects a
2269 /// This is different from 'ConvertImplicit' in that the
2270 /// user defined implicit conversions are excluded.
2272 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
2273 Type target_type, Location loc)
2275 Type expr_type = expr.Type;
2277 if (expr_type.IsSubclassOf (TypeManager.enum_type))
2278 expr_type = TypeManager.EnumToUnderlying (expr_type);
2282 if (expr is NullLiteral) {
2283 if (target_type == TypeManager.string_type)
2285 e = ConvertNothingToDefaultValues (ec, expr, target_type, loc);
2290 if (expr_type == target_type)
2293 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2298 if (expr is StringConstant && target_type == TypeManager.char_type)
2299 return new CharConstant (((StringConstant) expr).Value [0]);
2301 if (expr is CharConstant && target_type == TypeManager.string_type)
2302 return new StringConstant (((CharConstant) expr).Value.ToString ());
2304 e = ImplicitReferenceConversion (expr, target_type);
2308 if (expr.Type.IsSubclassOf (TypeManager.enum_type)) {
2309 expr_type = TypeManager.EnumToUnderlying (expr.Type);
2310 expr = new EmptyCast (expr, expr_type);
2311 if (expr_type == target_type)
2313 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2319 if (expr_type.IsPointer){
2320 if (target_type == TypeManager.void_ptr_type)
2321 return new EmptyCast (expr, target_type);
2324 // yep, comparing pointer types cant be done with
2325 // t1 == t2, we have to compare their element types.
2327 if (target_type.IsPointer){
2328 if (target_type.GetElementType()==expr_type.GetElementType())
2333 if (target_type.IsPointer){
2334 if (expr is NullLiteral)
2335 return new EmptyCast (expr, target_type);
2343 /// Attemps to perform an implict constant conversion of the any Numeric Constant
2344 /// into a different data type using casts (See Implicit Constant
2345 /// Expression Conversions)
2347 static protected Expression TryImplicitNumericConversion (Type target_type, Constant ic)
2350 if (ic is BoolConstant) {
2351 bool val = (bool) ((BoolConstant)ic).Value;
2353 if (target_type == TypeManager.byte_type)
2354 value = Byte.MaxValue;
2359 if (ic is IntConstant)
2360 value = (double)((IntConstant)ic).Value;
2362 if (ic is LongConstant)
2363 value = (double) ((LongConstant)ic).Value;
2365 if (ic is FloatConstant) {
2366 value = (double) ((FloatConstant)ic).Value;
2369 if (ic is DoubleConstant) {
2370 value = ((DoubleConstant)ic).Value;
2374 // FIXME: This could return constants instead of EmptyCasts
2376 if (target_type == TypeManager.bool_type){
2378 return new BoolConstant (true);
2379 return new BoolConstant (false);
2380 } else if (target_type == TypeManager.sbyte_type){
2381 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2382 return new SByteConstant ((sbyte) System.Math.Round (value));
2383 } else if (target_type == TypeManager.byte_type){
2384 if (value >= Byte.MinValue && value <= Byte.MaxValue)
2385 return new ByteConstant ((byte) System.Math.Round (value));
2386 } else if (target_type == TypeManager.short_type){
2387 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2388 return new ShortConstant ((short) System.Math.Round (value));
2389 } else if (target_type == TypeManager.ushort_type){
2390 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2391 return new UShortConstant ((ushort) System.Math.Round (value));
2392 } else if (target_type == TypeManager.int32_type){
2393 if (value >= Int32.MinValue && value <= Int32.MaxValue)
2394 return new IntConstant ((int) System.Math.Round (value));
2395 } else if (target_type == TypeManager.uint32_type){
2397 return new UIntConstant ((uint) System.Math.Round (value));
2398 } else if (target_type == TypeManager.int64_type){
2399 return new LongConstant ((long) System.Math.Round (value));
2400 } else if (target_type == TypeManager.uint64_type){
2402 // we can optimize this case: a positive int32
2403 // always fits on a uint64. But we need an opcode
2407 return new ULongConstant ((ulong)System.Math.Round ( value));
2408 } else if (target_type == TypeManager.float_type){
2409 return new FloatConstant ((float) value);
2410 } else if (target_type == TypeManager.double_type){
2411 return new DoubleConstant ((double) value);
2414 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
2415 Type underlying = TypeManager.EnumToUnderlying (target_type);
2416 Constant e = (Constant) ic;
2419 // Possibly, we need to create a different 0 literal before passing
2422 if (underlying == TypeManager.int64_type)
2423 e = new LongLiteral (0);
2424 else if (underlying == TypeManager.uint64_type)
2425 e = new ULongLiteral (0);
2427 return new EnumConstant (e, target_type);
2432 static public void Error_CannotConvertImplicit (Location loc, Type source, Type target)
2434 string msg = "Cannot convert implicitly from '"+
2435 TypeManager.MonoBASIC_Name (source) + "' to '" +
2436 TypeManager.MonoBASIC_Name (target) + "'";
2438 throw new Exception (msg);
2440 // Report.Error (30512, loc, msg);
2444 /// Attemptes to implicityly convert 'target' into 'type', using
2445 /// ConvertImplicit. If there is no implicit conversion, then
2446 /// an error is signaled
2448 static public Expression ConvertImplicitRequired (EmitContext ec, Expression source,
2449 Type target_type, Location loc)
2453 e = ConvertImplicit (ec, source, target_type, loc);
2459 if (source is DoubleLiteral && target_type == TypeManager.float_type){
2460 Report.Error (664, loc,
2461 "Double literal cannot be implicitly converted to " +
2462 "float type, use F suffix to create a float literal");
2465 Error_CannotConvertImplicit (loc, source.Type, target_type);
2471 /// Performs the explicit numeric conversions
2473 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc)
2475 Type expr_type = expr.Type;
2478 // If we have an enumeration, extract the underlying type,
2479 // use this during the comparison, but wrap around the original
2482 Type real_target_type = target_type;
2484 if (TypeManager.IsEnumType (real_target_type))
2485 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
2487 if (StandardConversionExists (expr, real_target_type)){
2488 Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc);
2490 if (real_target_type != target_type)
2491 return new EmptyCast (ce, target_type);
2495 if (expr_type == TypeManager.sbyte_type){
2497 // From sbyte to byte, ushort, uint, ulong, char
2499 if (real_target_type == TypeManager.byte_type)
2500 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
2501 if (real_target_type == TypeManager.ushort_type)
2502 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
2503 if (real_target_type == TypeManager.uint32_type)
2504 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
2505 if (real_target_type == TypeManager.uint64_type)
2506 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
2507 } else if (expr_type == TypeManager.byte_type){
2509 // From byte to sbyte and char
2511 if (real_target_type == TypeManager.sbyte_type)
2512 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
2513 } else if (expr_type == TypeManager.short_type){
2515 // From short to sbyte, byte, ushort, uint, ulong, char
2517 if (real_target_type == TypeManager.sbyte_type)
2518 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
2519 if (real_target_type == TypeManager.byte_type)
2520 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
2521 if (real_target_type == TypeManager.ushort_type)
2522 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
2523 if (real_target_type == TypeManager.uint32_type)
2524 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
2525 if (real_target_type == TypeManager.uint64_type)
2526 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
2527 } else if (expr_type == TypeManager.ushort_type){
2529 // From ushort to sbyte, byte, short, char
2531 if (real_target_type == TypeManager.sbyte_type)
2532 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
2533 if (real_target_type == TypeManager.byte_type)
2534 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
2535 if (real_target_type == TypeManager.short_type)
2536 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
2537 } else if (expr_type == TypeManager.int32_type){
2539 // From int to sbyte, byte, short, ushort, uint, ulong, char
2541 if (real_target_type == TypeManager.sbyte_type)
2542 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
2543 if (real_target_type == TypeManager.byte_type)
2544 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
2545 if (real_target_type == TypeManager.short_type)
2546 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
2547 if (real_target_type == TypeManager.ushort_type)
2548 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
2549 if (real_target_type == TypeManager.uint32_type)
2550 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
2551 if (real_target_type == TypeManager.uint64_type)
2552 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
2553 } else if (expr_type == TypeManager.uint32_type){
2555 // From uint to sbyte, byte, short, ushort, int, char
2557 if (real_target_type == TypeManager.sbyte_type)
2558 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
2559 if (real_target_type == TypeManager.byte_type)
2560 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
2561 if (real_target_type == TypeManager.short_type)
2562 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
2563 if (real_target_type == TypeManager.ushort_type)
2564 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
2565 if (real_target_type == TypeManager.int32_type)
2566 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
2567 } else if (expr_type == TypeManager.int64_type){
2569 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
2571 if (real_target_type == TypeManager.sbyte_type)
2572 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
2573 if (real_target_type == TypeManager.byte_type)
2574 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
2575 if (real_target_type == TypeManager.short_type)
2576 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
2577 if (real_target_type == TypeManager.ushort_type)
2578 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2579 if (real_target_type == TypeManager.int32_type)
2580 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2581 if (real_target_type == TypeManager.uint32_type)
2582 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2583 if (real_target_type == TypeManager.uint64_type)
2584 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
2585 } else if (expr_type == TypeManager.uint64_type){
2587 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
2589 if (real_target_type == TypeManager.sbyte_type)
2590 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
2591 if (real_target_type == TypeManager.byte_type)
2592 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
2593 if (real_target_type == TypeManager.short_type)
2594 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
2595 if (real_target_type == TypeManager.ushort_type)
2596 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
2597 if (real_target_type == TypeManager.int32_type)
2598 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2599 if (real_target_type == TypeManager.uint32_type)
2600 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
2601 if (real_target_type == TypeManager.int64_type)
2602 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
2603 } else if (expr_type == TypeManager.float_type){
2605 // From float to sbyte, byte, short,
2606 // ushort, int, uint, long, ulong, char
2609 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2610 if (real_target_type == TypeManager.sbyte_type)
2611 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
2612 if (real_target_type == TypeManager.byte_type)
2613 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
2614 if (real_target_type == TypeManager.short_type)
2615 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
2616 if (real_target_type == TypeManager.ushort_type)
2617 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2618 if (real_target_type == TypeManager.int32_type)
2619 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2620 if (real_target_type == TypeManager.uint32_type)
2621 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2622 if (real_target_type == TypeManager.int64_type)
2623 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2624 if (real_target_type == TypeManager.uint64_type)
2625 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2626 } else if (expr_type == TypeManager.double_type){
2628 // From double to byte, byte, short,
2629 // ushort, int, uint, long, ulong,
2630 // char, float or decimal
2632 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2633 if (real_target_type == TypeManager.sbyte_type)
2634 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
2635 if (real_target_type == TypeManager.byte_type)
2636 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
2637 if (real_target_type == TypeManager.short_type)
2638 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
2639 if (real_target_type == TypeManager.ushort_type)
2640 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
2641 if (real_target_type == TypeManager.int32_type)
2642 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2643 if (real_target_type == TypeManager.uint32_type)
2644 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2645 if (real_target_type == TypeManager.int64_type)
2646 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2647 if (real_target_type == TypeManager.uint64_type)
2648 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2649 if (real_target_type == TypeManager.float_type)
2650 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2653 // decimal is taken care of by the op_Explicit methods.
2659 /// Returns whether an explicit reference conversion can be performed
2660 /// from source_type to target_type
2662 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
2664 bool target_is_value_type = target_type.IsValueType;
2666 if (source_type == target_type)
2670 // From object to any reference type
2672 if (source_type == TypeManager.object_type && !target_is_value_type)
2676 // From any class S to any class-type T, provided S is a base class of T
2678 if (target_type.IsSubclassOf (source_type))
2682 // From any interface type S to any interface T provided S is not derived from T
2684 if (source_type.IsInterface && target_type.IsInterface){
2685 if (!target_type.IsSubclassOf (source_type))
2690 // From any class type S to any interface T, provided S is not sealed
2691 // and provided S does not implement T.
2693 if (target_type.IsInterface && !source_type.IsSealed &&
2694 !TypeManager.ImplementsInterface (source_type, target_type))
2698 // From any interface-type S to to any class type T, provided T is not
2699 // sealed, or provided T implements S.
2701 if (source_type.IsInterface &&
2702 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
2706 // From an array type S with an element type Se to an array type T with an
2707 // element type Te provided all the following are true:
2708 // * S and T differe only in element type, in other words, S and T
2709 // have the same number of dimensions.
2710 // * Both Se and Te are reference types
2711 // * An explicit referenc conversions exist from Se to Te
2713 if (source_type.IsArray && target_type.IsArray) {
2714 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2716 Type source_element_type = source_type.GetElementType ();
2717 Type target_element_type = target_type.GetElementType ();
2719 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2720 if (ExplicitReferenceConversionExists (source_element_type,
2721 target_element_type))
2727 // From System.Array to any array-type
2728 if (source_type == TypeManager.array_type &&
2729 target_type.IsArray){
2734 // From System delegate to any delegate-type
2736 if (source_type == TypeManager.delegate_type &&
2737 target_type.IsSubclassOf (TypeManager.delegate_type))
2741 // From ICloneable to Array or Delegate types
2743 if (source_type == TypeManager.icloneable_type &&
2744 (target_type == TypeManager.array_type ||
2745 target_type == TypeManager.delegate_type))
2752 /// Implements Explicit Reference conversions
2754 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
2756 Type source_type = source.Type;
2757 bool target_is_value_type = target_type.IsValueType;
2760 // From object to any reference type
2762 if (source_type == TypeManager.object_type && !target_is_value_type)
2763 return new ClassCast (source, target_type);
2767 // From any class S to any class-type T, provided S is a base class of T
2769 if (target_type.IsSubclassOf (source_type))
2770 return new ClassCast (source, target_type);
2773 // From any interface type S to any interface T provided S is not derived from T
2775 if (source_type.IsInterface && target_type.IsInterface){
2776 if (TypeManager.ImplementsInterface (source_type, target_type))
2779 return new ClassCast (source, target_type);
2783 // From any class type S to any interface T, provides S is not sealed
2784 // and provided S does not implement T.
2786 if (target_type.IsInterface && !source_type.IsSealed) {
2787 if (TypeManager.ImplementsInterface (source_type, target_type))
2790 return new ClassCast (source, target_type);
2795 // From any interface-type S to to any class type T, provided T is not
2796 // sealed, or provided T implements S.
2798 if (source_type.IsInterface) {
2799 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type))
2800 return new ClassCast (source, target_type);
2805 // From an array type S with an element type Se to an array type T with an
2806 // element type Te provided all the following are true:
2807 // * S and T differe only in element type, in other words, S and T
2808 // have the same number of dimensions.
2809 // * Both Se and Te are reference types
2810 // * An explicit referenc conversions exist from Se to Te
2812 if (source_type.IsArray && target_type.IsArray) {
2813 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2815 Type source_element_type = source_type.GetElementType ();
2816 Type target_element_type = target_type.GetElementType ();
2818 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2819 if (ExplicitReferenceConversionExists (source_element_type,
2820 target_element_type))
2821 return new ClassCast (source, target_type);
2826 // From System.Array to any array-type
2827 if (source_type == TypeManager.array_type &&
2828 target_type.IsArray) {
2829 return new ClassCast (source, target_type);
2833 // From System delegate to any delegate-type
2835 if (source_type == TypeManager.delegate_type &&
2836 target_type.IsSubclassOf (TypeManager.delegate_type))
2837 return new ClassCast (source, target_type);
2840 // From ICloneable to Array or Delegate types
2842 if (source_type == TypeManager.icloneable_type &&
2843 (target_type == TypeManager.array_type ||
2844 target_type == TypeManager.delegate_type))
2845 return new ClassCast (source, target_type);
2851 /// Performs an explicit conversion of the expression 'expr' whose
2852 /// type is expr.Type to 'target_type'.
2854 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
2855 Type target_type, bool runtimeconv, Location loc)
2857 Type expr_type = expr.Type;
2858 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
2863 ne = ConvertNumericExplicit (ec, expr, target_type, loc);
2868 // Unboxing conversion.
2870 if (expr_type == TypeManager.object_type && target_type.IsValueType)
2871 return new UnboxCast (expr, target_type);
2876 if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
2880 // FIXME: Is there any reason we should have EnumConstant
2881 // dealt with here instead of just using always the
2882 // UnderlyingSystemType to wrap the type?
2884 if (expr is EnumConstant)
2885 e = ((EnumConstant) expr).Child;
2887 e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
2890 Expression t = ConvertImplicit (ec, e, target_type, loc);
2894 t = ConvertNumericExplicit (ec, e, target_type, loc);
2898 t = NarrowingConversion (ec, e, target_type, loc);
2902 Error_CannotConvertType (loc, expr_type, target_type);
2906 ne = ConvertReferenceExplicit (expr, target_type);
2911 if (target_type.IsPointer){
2912 if (expr_type.IsPointer)
2913 return new EmptyCast (expr, target_type);
2915 if (expr_type == TypeManager.sbyte_type ||
2916 expr_type == TypeManager.byte_type ||
2917 expr_type == TypeManager.short_type ||
2918 expr_type == TypeManager.ushort_type ||
2919 expr_type == TypeManager.int32_type ||
2920 expr_type == TypeManager.uint32_type ||
2921 expr_type == TypeManager.uint64_type ||
2922 expr_type == TypeManager.int64_type)
2923 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
2925 if (expr_type.IsPointer){
2926 if (target_type == TypeManager.sbyte_type ||
2927 target_type == TypeManager.byte_type ||
2928 target_type == TypeManager.short_type ||
2929 target_type == TypeManager.ushort_type ||
2930 target_type == TypeManager.int32_type ||
2931 target_type == TypeManager.uint32_type ||
2932 target_type == TypeManager.uint64_type ||
2933 target_type == TypeManager.int64_type){
2934 Expression e = new EmptyCast (expr, TypeManager.uint32_type);
2937 ci = ConvertImplicitStandard (ec, e, target_type, loc);
2942 ce = ConvertNumericExplicit (ec, e, target_type, loc);
2946 // We should always be able to go from an uint32
2947 // implicitly or explicitly to the other integral
2950 throw new Exception ("Internal compiler error");
2955 ne = ExplicitUserConversion (ec, expr, target_type, loc);
2959 if (!(runtimeconv)) {
2960 ne = NarrowingConversion (ec, expr, target_type, loc);
2964 Error_CannotConvertType (loc, expr_type, target_type);
2970 /// Same as ConvertExplicit, only it doesn't include user defined conversions
2972 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
2973 Type target_type, Location l)
2975 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
2980 ne = ConvertNumericExplicit (ec, expr, target_type, l);
2984 ne = ConvertReferenceExplicit (expr, target_type);
2988 ne = NarrowingConversion (ec, expr, target_type, l);
2992 Error_CannotConvertType (l, expr.Type, target_type);
2996 static string ExprClassName (ExprClass c)
2999 case ExprClass.Invalid:
3001 case ExprClass.Value:
3003 case ExprClass.Variable:
3005 case ExprClass.Namespace:
3007 case ExprClass.Type:
3009 case ExprClass.MethodGroup:
3010 return "method group";
3011 case ExprClass.PropertyAccess:
3012 return "property access";
3013 case ExprClass.EventAccess:
3014 return "event access";
3015 case ExprClass.IndexerAccess:
3016 return "indexer access";
3017 case ExprClass.Nothing:
3020 throw new Exception ("Should not happen");
3024 /// Reports that we were expecting 'expr' to be of class 'expected'
3026 public void Error118 (string expected)
3028 string kind = "Unknown";
3030 kind = ExprClassName (eclass);
3032 Error (118, "Expression denotes a '" + kind +
3033 "' where a '" + expected + "' was expected");
3036 public void Error118 (ResolveFlags flags)
3038 ArrayList valid = new ArrayList (10);
3040 if ((flags & ResolveFlags.VariableOrValue) != 0) {
3041 valid.Add ("variable");
3042 valid.Add ("value");
3045 if ((flags & ResolveFlags.Type) != 0)
3048 if ((flags & ResolveFlags.MethodGroup) != 0)
3049 valid.Add ("method group");
3051 if ((flags & ResolveFlags.SimpleName) != 0)
3052 valid.Add ("simple name");
3054 if (valid.Count == 0)
3055 valid.Add ("unknown");
3057 StringBuilder sb = new StringBuilder ();
3058 for (int i = 0; i < valid.Count; i++) {
3061 else if (i == valid.Count)
3063 sb.Append (valid [i]);
3066 string kind = ExprClassName (eclass);
3068 Error (119, "Expression denotes a '" + kind + "' where " +
3069 "a '" + sb.ToString () + "' was expected");
3072 static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t)
3074 Report.Error (30439, l, "Constant value '" + val + "' not representable in type " +
3075 TypeManager.MonoBASIC_Name (t));
3078 public static void UnsafeError (Location loc)
3080 Report.Error (214, loc, "Pointers may only be used in an unsafe context");
3084 /// Converts the IntConstant, UIntConstant, LongConstant or
3085 /// ULongConstant,Double into the integral target_type. Notice
3086 /// that we do not return an 'Expression' we do return
3087 /// a boxed integral type.
3089 /// FIXME: Since I added the new constants, we need to
3090 /// also support conversions from CharConstant, ByteConstant,
3091 /// SByteConstant, UShortConstant, ShortConstant
3093 /// This is used by the switch statement, so the domain
3094 /// of work is restricted to the literals above, and the
3095 /// targets are int32, uint32, char, byte, sbyte, ushort,
3096 /// short, uint64 and int64
3098 public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
3102 if (c.Type == target_type)
3103 return ((Constant) c).GetValue ();
3106 // Make into one of the literals we handle, we dont really care
3107 // about this value as we will just return a few limited types
3109 if (c is EnumConstant)
3110 c = ((EnumConstant)c).WidenToCompilerConstant ();
3112 if (c is IntConstant){
3113 int v = ((IntConstant) c).Value;
3115 if (target_type == TypeManager.uint32_type){
3118 } else if (target_type == TypeManager.byte_type){
3119 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3121 } else if (target_type == TypeManager.sbyte_type){
3122 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3124 } else if (target_type == TypeManager.short_type){
3125 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3127 } else if (target_type == TypeManager.ushort_type){
3128 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3130 } else if (target_type == TypeManager.int64_type)
3132 else if (target_type == TypeManager.uint64_type){
3138 } else if (c is UIntConstant){
3139 uint v = ((UIntConstant) c).Value;
3141 if (target_type == TypeManager.int32_type){
3142 if (v <= Int32.MaxValue)
3144 } else if (target_type == TypeManager.byte_type){
3145 if (v <= Byte.MaxValue)
3147 } else if (target_type == TypeManager.sbyte_type){
3148 if (v <= SByte.MaxValue)
3150 } else if (target_type == TypeManager.short_type){
3151 if (v <= UInt16.MaxValue)
3153 } else if (target_type == TypeManager.ushort_type){
3154 if (v <= UInt16.MaxValue)
3156 } else if (target_type == TypeManager.int64_type)
3158 else if (target_type == TypeManager.uint64_type)
3161 } else if (c is LongConstant){
3162 long v = ((LongConstant) c).Value;
3164 if (target_type == TypeManager.int32_type){
3165 if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
3167 } else if (target_type == TypeManager.uint32_type){
3168 if (v >= 0 && v <= UInt32.MaxValue)
3170 } else if (target_type == TypeManager.byte_type){
3171 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3173 } else if (target_type == TypeManager.sbyte_type){
3174 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3176 } else if (target_type == TypeManager.short_type){
3177 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3179 } else if (target_type == TypeManager.ushort_type){
3180 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3182 } else if (target_type == TypeManager.uint64_type){
3187 } else if (c is ULongConstant){
3188 ulong v = ((ULongConstant) c).Value;
3190 if (target_type == TypeManager.int32_type){
3191 if (v <= Int32.MaxValue)
3193 } else if (target_type == TypeManager.uint32_type){
3194 if (v <= UInt32.MaxValue)
3196 } else if (target_type == TypeManager.byte_type){
3197 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3199 } else if (target_type == TypeManager.sbyte_type){
3200 if (v <= (int) SByte.MaxValue)
3202 } else if (target_type == TypeManager.short_type){
3203 if (v <= UInt16.MaxValue)
3205 } else if (target_type == TypeManager.ushort_type){
3206 if (v <= UInt16.MaxValue)
3208 } else if (target_type == TypeManager.int64_type){
3209 if (v <= Int64.MaxValue)
3213 } else if (c is ByteConstant){
3214 byte v = ((ByteConstant) c).Value;
3216 if (target_type == TypeManager.int32_type)
3218 else if (target_type == TypeManager.uint32_type)
3220 else if (target_type == TypeManager.sbyte_type){
3221 if (v <= SByte.MaxValue)
3223 } else if (target_type == TypeManager.short_type)
3225 else if (target_type == TypeManager.ushort_type)
3227 else if (target_type == TypeManager.int64_type)
3229 else if (target_type == TypeManager.uint64_type)
3232 } else if (c is SByteConstant){
3233 sbyte v = ((SByteConstant) c).Value;
3235 if (target_type == TypeManager.int32_type)
3237 else if (target_type == TypeManager.uint32_type){
3240 } else if (target_type == TypeManager.byte_type){
3243 } else if (target_type == TypeManager.short_type)
3245 else if (target_type == TypeManager.ushort_type){
3248 } else if (target_type == TypeManager.int64_type)
3250 else if (target_type == TypeManager.uint64_type){
3255 } else if (c is ShortConstant){
3256 short v = ((ShortConstant) c).Value;
3258 if (target_type == TypeManager.int32_type){
3260 } else if (target_type == TypeManager.uint32_type){
3263 } else if (target_type == TypeManager.byte_type){
3264 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3266 } else if (target_type == TypeManager.sbyte_type){
3267 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3269 } else if (target_type == TypeManager.ushort_type){
3272 } else if (target_type == TypeManager.int64_type)
3274 else if (target_type == TypeManager.uint64_type)
3278 } else if (c is UShortConstant){
3279 ushort v = ((UShortConstant) c).Value;
3281 if (target_type == TypeManager.int32_type)
3283 else if (target_type == TypeManager.uint32_type)
3285 else if (target_type == TypeManager.byte_type){
3286 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3288 } else if (target_type == TypeManager.sbyte_type){
3289 if (v <= SByte.MaxValue)
3291 } else if (target_type == TypeManager.short_type){
3292 if (v <= Int16.MaxValue)
3294 } else if (target_type == TypeManager.int64_type)
3296 else if (target_type == TypeManager.uint64_type)
3300 } else if (c is CharConstant){
3301 char v = ((CharConstant) c).Value;
3303 if (target_type == TypeManager.int32_type)
3305 else if (target_type == TypeManager.uint32_type)
3307 else if (target_type == TypeManager.byte_type){
3308 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3310 } else if (target_type == TypeManager.sbyte_type){
3311 if (v <= SByte.MaxValue)
3313 } else if (target_type == TypeManager.short_type){
3314 if (v <= Int16.MaxValue)
3316 } else if (target_type == TypeManager.ushort_type)
3318 else if (target_type == TypeManager.int64_type)
3320 else if (target_type == TypeManager.uint64_type)
3325 } else if (c is DoubleConstant){
3326 double v = ((DoubleConstant) c).Value;
3328 if (target_type == TypeManager.sbyte_type){
3329 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3330 return new SByteConstant ((sbyte) System.Math.Round (v));
3331 } else if (target_type == TypeManager.byte_type){
3332 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3333 return new ByteConstant ((byte) System.Math.Round (v));
3334 } else if (target_type == TypeManager.short_type){
3335 if (v >= Int16.MinValue && v <= Int16.MaxValue)
3336 return new ShortConstant ((short) System.Math.Round (v));
3337 } else if (target_type == TypeManager.ushort_type){
3338 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3339 return new UShortConstant ((ushort) System.Math.Round (v));
3340 } else if (target_type == TypeManager.int32_type){
3341 if (v >= Int32.MinValue && v <= Int32.MaxValue)
3342 return new IntConstant ((int) System.Math.Round (v));
3343 } else if (target_type == TypeManager.uint32_type){
3344 if (v >= 0 && v <= UInt32.MaxValue)
3345 return new UIntConstant ((uint) System.Math.Round (v));
3346 } else if (target_type == TypeManager.uint64_type){
3348 return new ULongConstant ((ulong) System.Math.Round (v));
3353 Error_ConstantValueCannotBeConverted (loc, s, target_type);
3358 // Load the object from the pointer.
3360 public static void LoadFromPtr (ILGenerator ig, Type t)
3362 if (t == TypeManager.int32_type)
3363 ig.Emit (OpCodes.Ldind_I4);
3364 else if (t == TypeManager.uint32_type)
3365 ig.Emit (OpCodes.Ldind_U4);
3366 else if (t == TypeManager.short_type)
3367 ig.Emit (OpCodes.Ldind_I2);
3368 else if (t == TypeManager.ushort_type)
3369 ig.Emit (OpCodes.Ldind_U2);
3370 else if (t == TypeManager.char_type)
3371 ig.Emit (OpCodes.Ldind_U2);
3372 else if (t == TypeManager.byte_type)
3373 ig.Emit (OpCodes.Ldind_U1);
3374 else if (t == TypeManager.sbyte_type)
3375 ig.Emit (OpCodes.Ldind_I1);
3376 else if (t == TypeManager.uint64_type)
3377 ig.Emit (OpCodes.Ldind_I8);
3378 else if (t == TypeManager.int64_type)
3379 ig.Emit (OpCodes.Ldind_I8);
3380 else if (t == TypeManager.float_type)
3381 ig.Emit (OpCodes.Ldind_R4);
3382 else if (t == TypeManager.double_type)
3383 ig.Emit (OpCodes.Ldind_R8);
3384 else if (t == TypeManager.bool_type)
3385 ig.Emit (OpCodes.Ldind_I1);
3386 else if (t == TypeManager.intptr_type)
3387 ig.Emit (OpCodes.Ldind_I);
3388 else if (TypeManager.IsEnumType (t)) {
3389 if (t == TypeManager.enum_type)
3390 ig.Emit (OpCodes.Ldind_Ref);
3392 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
3393 } else if (t.IsValueType)
3394 ig.Emit (OpCodes.Ldobj, t);
3396 ig.Emit (OpCodes.Ldind_Ref);
3400 // The stack contains the pointer and the value of type 'type'
3402 public static void StoreFromPtr (ILGenerator ig, Type type)
3404 if (TypeManager.IsEnumType (type))
3405 type = TypeManager.EnumToUnderlying (type);
3406 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
3407 ig.Emit (OpCodes.Stind_I4);
3408 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
3409 ig.Emit (OpCodes.Stind_I8);
3410 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
3411 type == TypeManager.ushort_type)
3412 ig.Emit (OpCodes.Stind_I2);
3413 else if (type == TypeManager.float_type)
3414 ig.Emit (OpCodes.Stind_R4);
3415 else if (type == TypeManager.double_type)
3416 ig.Emit (OpCodes.Stind_R8);
3417 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
3418 type == TypeManager.bool_type)
3419 ig.Emit (OpCodes.Stind_I1);
3420 else if (type == TypeManager.intptr_type)
3421 ig.Emit (OpCodes.Stind_I);
3422 else if (type.IsValueType)
3423 ig.Emit (OpCodes.Stobj, type);
3425 ig.Emit (OpCodes.Stind_Ref);
3429 // Returns the size of type 't' if known, otherwise, 0
3431 public static int GetTypeSize (Type t)
3433 t = TypeManager.TypeToCoreType (t);
3434 if (t == TypeManager.int32_type ||
3435 t == TypeManager.uint32_type ||
3436 t == TypeManager.float_type)
3438 else if (t == TypeManager.int64_type ||
3439 t == TypeManager.uint64_type ||
3440 t == TypeManager.double_type)
3442 else if (t == TypeManager.byte_type ||
3443 t == TypeManager.sbyte_type ||
3444 t == TypeManager.bool_type)
3446 else if (t == TypeManager.short_type ||
3447 t == TypeManager.char_type ||
3448 t == TypeManager.ushort_type)
3450 else if (t == TypeManager.decimal_type)
3457 // Default implementation of IAssignMethod.CacheTemporaries
3459 public void CacheTemporaries (EmitContext ec)
3463 static void Error_NegativeArrayIndex (Location loc)
3465 Report.Error (284, loc, "Can not create array with a negative size");
3469 // Converts 'source' to an int, uint, long or ulong.
3471 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
3475 bool old_checked = ec.CheckState;
3476 ec.CheckState = true;
3478 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
3479 if (target == null){
3480 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
3481 if (target == null){
3482 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
3483 if (target == null){
3484 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
3486 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
3490 ec.CheckState = old_checked;
3493 // Only positive constants are allowed at compile time
3495 if (target is Constant){
3496 if (target is IntConstant){
3497 if (((IntConstant) target).Value < 0){
3498 Error_NegativeArrayIndex (loc);
3503 if (target is LongConstant){
3504 if (((LongConstant) target).Value < 0){
3505 Error_NegativeArrayIndex (loc);
3518 /// This is just a base class for expressions that can
3519 /// appear on statements (invocations, object creation,
3520 /// assignments, post/pre increment and decrement). The idea
3521 /// being that they would support an extra Emition interface that
3522 /// does not leave a result on the stack.
3524 public abstract class ExpressionStatement : Expression {
3527 /// Requests the expression to be emitted in a 'statement'
3528 /// context. This means that no new value is left on the
3529 /// stack after invoking this method (constrasted with
3530 /// Emit that will always leave a value on the stack).
3532 public abstract void EmitStatement (EmitContext ec);
3536 /// This kind of cast is used to encapsulate the child
3537 /// whose type is child.Type into an expression that is
3538 /// reported to return "return_type". This is used to encapsulate
3539 /// expressions which have compatible types, but need to be dealt
3540 /// at higher levels with.
3542 /// For example, a "byte" expression could be encapsulated in one
3543 /// of these as an "unsigned int". The type for the expression
3544 /// would be "unsigned int".
3547 public class EmptyCast : Expression {
3548 protected Expression child;
3550 public EmptyCast (Expression child, Type return_type)
3552 eclass = child.eclass;
3557 public override Expression DoResolve (EmitContext ec)
3559 // This should never be invoked, we are born in fully
3560 // initialized state.
3565 public override void Emit (EmitContext ec)
3572 /// This class is used to wrap literals which belong inside Enums
3574 public class EnumConstant : Constant {
3575 public Constant Child;
3577 public EnumConstant (Constant child, Type enum_type)
3579 eclass = child.eclass;
3584 public override Expression DoResolve (EmitContext ec)
3586 // This should never be invoked, we are born in fully
3587 // initialized state.
3592 public override void Emit (EmitContext ec)
3597 public override object GetValue ()
3599 return Child.GetValue ();
3603 // Converts from one of the valid underlying types for an enumeration
3604 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
3605 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
3607 public Constant WidenToCompilerConstant ()
3609 Type t = TypeManager.EnumToUnderlying (Child.Type);
3610 object v = ((Constant) Child).GetValue ();;
3612 if (t == TypeManager.int32_type)
3613 return new IntConstant ((int) v);
3614 if (t == TypeManager.uint32_type)
3615 return new UIntConstant ((uint) v);
3616 if (t == TypeManager.int64_type)
3617 return new LongConstant ((long) v);
3618 if (t == TypeManager.uint64_type)
3619 return new ULongConstant ((ulong) v);
3620 if (t == TypeManager.short_type)
3621 return new ShortConstant ((short) v);
3622 if (t == TypeManager.ushort_type)
3623 return new UShortConstant ((ushort) v);
3624 if (t == TypeManager.byte_type)
3625 return new ByteConstant ((byte) v);
3626 if (t == TypeManager.sbyte_type)
3627 return new SByteConstant ((sbyte) v);
3629 throw new Exception ("Invalid enumeration underlying type: " + t);
3633 // Extracts the value in the enumeration on its native representation
3635 public object GetPlainValue ()
3637 Type t = TypeManager.EnumToUnderlying (Child.Type);
3638 object v = ((Constant) Child).GetValue ();;
3640 if (t == TypeManager.int32_type)
3642 if (t == TypeManager.uint32_type)
3644 if (t == TypeManager.int64_type)
3646 if (t == TypeManager.uint64_type)
3648 if (t == TypeManager.short_type)
3650 if (t == TypeManager.ushort_type)
3652 if (t == TypeManager.byte_type)
3654 if (t == TypeManager.sbyte_type)
3660 public override string AsString ()
3662 return Child.AsString ();
3665 public override DoubleConstant ConvertToDouble ()
3667 return Child.ConvertToDouble ();
3670 public override FloatConstant ConvertToFloat ()
3672 return Child.ConvertToFloat ();
3675 public override ULongConstant ConvertToULong ()
3677 return Child.ConvertToULong ();
3680 public override LongConstant ConvertToLong ()
3682 return Child.ConvertToLong ();
3685 public override UIntConstant ConvertToUInt ()
3687 return Child.ConvertToUInt ();
3690 public override IntConstant ConvertToInt ()
3692 return Child.ConvertToInt ();
3697 /// This kind of cast is used to encapsulate Value Types in objects.
3699 /// The effect of it is to box the value type emitted by the previous
3702 public class BoxedCast : EmptyCast {
3704 public BoxedCast (Expression expr)
3705 : base (expr, TypeManager.object_type)
3709 public override Expression DoResolve (EmitContext ec)
3711 // This should never be invoked, we are born in fully
3712 // initialized state.
3717 public override void Emit (EmitContext ec)
3721 ec.ig.Emit (OpCodes.Box, child.Type);
3725 public class UnboxCast : EmptyCast {
3726 public UnboxCast (Expression expr, Type return_type)
3727 : base (expr, return_type)
3731 public override Expression DoResolve (EmitContext ec)
3733 // This should never be invoked, we are born in fully
3734 // initialized state.
3739 public override void Emit (EmitContext ec)
3742 ILGenerator ig = ec.ig;
3745 ig.Emit (OpCodes.Unbox, t);
3747 LoadFromPtr (ig, t);
3752 /// This is used to perform explicit numeric conversions.
3754 /// Explicit numeric conversions might trigger exceptions in a checked
3755 /// context, so they should generate the conv.ovf opcodes instead of
3758 public class ConvCast : EmptyCast {
3759 public enum Mode : byte {
3760 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
3762 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
3763 U2_I1, U2_U1, U2_I2, U2_CH,
3764 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
3765 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
3766 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
3767 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
3768 CH_I1, CH_U1, CH_I2,
3769 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
3770 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
3776 public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
3777 : base (child, return_type)
3779 checked_state = ec.CheckState;
3783 public override Expression DoResolve (EmitContext ec)
3785 // This should never be invoked, we are born in fully
3786 // initialized state.
3791 public override void Emit (EmitContext ec)
3793 ILGenerator ig = ec.ig;
3799 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3800 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3801 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3802 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3803 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3805 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3806 case Mode.U1_CH: /* nothing */ break;
3808 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3809 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3810 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3811 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3812 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3813 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3815 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3816 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3817 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3818 case Mode.U2_CH: /* nothing */ break;
3820 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3821 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3822 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3823 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3824 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3825 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3826 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3828 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3829 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3830 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3831 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3832 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3833 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3835 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3836 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3837 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3838 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3839 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3840 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3841 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3842 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3844 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3845 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3846 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3847 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3848 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3849 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
3850 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
3851 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3853 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3854 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3855 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3857 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3858 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3859 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3860 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3861 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3862 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3863 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3864 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3865 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3867 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3868 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3869 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3870 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3871 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3872 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3873 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3874 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3875 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3876 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3880 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
3881 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
3882 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
3883 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
3884 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
3886 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
3887 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
3889 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
3890 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
3891 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
3892 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
3893 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
3894 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
3896 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
3897 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
3898 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
3899 case Mode.U2_CH: /* nothing */ break;
3901 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
3902 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
3903 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
3904 case Mode.I4_U4: /* nothing */ break;
3905 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
3906 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
3907 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
3909 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
3910 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
3911 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
3912 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
3913 case Mode.U4_I4: /* nothing */ break;
3914 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
3916 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
3917 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
3918 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
3919 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
3920 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
3921 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
3922 case Mode.I8_U8: /* nothing */ break;
3923 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
3925 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
3926 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
3927 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
3928 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
3929 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
3930 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
3931 case Mode.U8_I8: /* nothing */ break;
3932 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
3934 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
3935 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
3936 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
3938 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
3939 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
3940 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
3941 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
3942 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
3943 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
3944 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
3945 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
3946 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
3948 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
3949 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
3950 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
3951 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
3952 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
3953 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
3954 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
3955 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
3956 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
3957 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3963 public class OpcodeCast : EmptyCast {
3967 public OpcodeCast (Expression child, Type return_type, OpCode op)
3968 : base (child, return_type)
3972 second_valid = false;
3975 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
3976 : base (child, return_type)
3981 second_valid = true;
3984 public override Expression DoResolve (EmitContext ec)
3986 // This should never be invoked, we are born in fully
3987 // initialized state.
3992 public override void Emit (EmitContext ec)
4003 public class NumericToBoolCast : EmptyCast
4007 public NumericToBoolCast (Expression src, Type src_type)
4008 : base (src, TypeManager.bool_type)
4011 this.src_type = src_type;
4014 public override Expression DoResolve (EmitContext ec)
4019 public override void Emit (EmitContext ec)
4023 if (src_type == TypeManager.byte_type ||
4024 src_type == TypeManager.short_type ||
4025 src_type == TypeManager.int32_type) {
4027 ec.ig.Emit (OpCodes.Ldc_I4_0);
4028 ec.ig.Emit (OpCodes.Cgt_Un);
4032 if (src_type == TypeManager.int64_type) {
4033 ec.ig.Emit (OpCodes.Ldc_I8, (long) 0);
4034 ec.ig.Emit (OpCodes.Cgt_Un);
4038 if (src_type == TypeManager.float_type) {
4039 ec.ig.Emit (OpCodes.Ldc_R4, (float) 0);
4040 ec.ig.Emit (OpCodes.Ceq);
4041 ec.ig.Emit (OpCodes.Ldc_I4_0);
4042 ec.ig.Emit (OpCodes.Ceq);
4046 if (src_type == TypeManager.double_type) {
4047 ec.ig.Emit (OpCodes.Ldc_R8, (double) 0);
4048 ec.ig.Emit (OpCodes.Ceq);
4049 ec.ig.Emit (OpCodes.Ldc_I4_0);
4050 ec.ig.Emit (OpCodes.Ceq);
4056 public class BoolToNumericCast : EmptyCast
4061 public BoolToNumericCast (Expression src, Type target_type)
4062 : base (src, target_type)
4065 this.target_type = target_type;
4068 public override Expression DoResolve (EmitContext ec)
4073 public override void Emit (EmitContext ec)
4077 if (target_type == TypeManager.byte_type) {
4078 conv = OpCodes.Conv_U1;
4079 } else if (target_type == TypeManager.short_type) {
4080 conv = OpCodes.Conv_I2;
4081 } else if (target_type == TypeManager.int32_type) {
4082 conv = OpCodes.Conv_I4;
4083 } else if (target_type == TypeManager.int64_type) {
4084 conv = OpCodes.Conv_I8;
4085 } else if (target_type == TypeManager.float_type) {
4086 conv = OpCodes.Conv_R4;
4087 } else if (target_type == TypeManager.double_type) {
4088 conv = OpCodes.Conv_R8;
4091 ec.ig.Emit (OpCodes.Ldc_I4_0);
4092 ec.ig.Emit (OpCodes.Cgt_Un);
4093 ec.ig.Emit (OpCodes.Neg);
4100 /// This kind of cast is used to encapsulate a child and cast it
4101 /// to the class requested
4103 public class ClassCast : EmptyCast {
4104 public ClassCast (Expression child, Type return_type)
4105 : base (child, return_type)
4110 public override Expression DoResolve (EmitContext ec)
4112 // This should never be invoked, we are born in fully
4113 // initialized state.
4118 public override void Emit (EmitContext ec)
4122 ec.ig.Emit (OpCodes.Castclass, type);
4128 /// SimpleName expressions are initially formed of a single
4129 /// word and it only happens at the beginning of the expression.
4133 /// The expression will try to be bound to a Field, a Method
4134 /// group or a Property. If those fail we pass the name to our
4135 /// caller and the SimpleName is compounded to perform a type
4136 /// lookup. The idea behind this process is that we want to avoid
4137 /// creating a namespace map from the assemblies, as that requires
4138 /// the GetExportedTypes function to be called and a hashtable to
4139 /// be constructed which reduces startup time. If later we find
4140 /// that this is slower, we should create a 'NamespaceExpr' expression
4141 /// that fully participates in the resolution process.
4143 /// For example 'System.Console.WriteLine' is decomposed into
4144 /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
4146 /// The first SimpleName wont produce a match on its own, so it will
4148 /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
4150 /// System.Console will produce a TypeExpr match.
4152 /// The downside of this is that we might be hitting 'LookupType' too many
4153 /// times with this scheme.
4155 public class SimpleName : Expression, ITypeExpression {
4156 public readonly string Name;
4157 bool is_invocation = false;
4159 public bool IsInvocation {
4161 is_invocation = value;
4165 public SimpleName (string name, Location l)
4171 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
4173 if (ec.IsFieldInitializer)
4176 "A field initializer cannot reference the non-static field, " +
4177 "method or property '"+name+"'");
4181 "An object reference is required " +
4182 "for the non-static field '"+name+"'");
4186 // Checks whether we are trying to access an instance
4187 // property, method or field from a static body.
4189 Expression MemberStaticCheck (EmitContext ec, Expression e)
4191 if (e is IMemberExpr){
4192 IMemberExpr member = (IMemberExpr) e;
4194 if (!member.IsStatic){
4195 Error_ObjectRefRequired (ec, loc, Name);
4203 public override Expression DoResolve (EmitContext ec)
4205 return SimpleNameResolve (ec, null, false);
4208 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4210 return SimpleNameResolve (ec, right_side, false);
4214 public Expression DoResolveAllowStatic (EmitContext ec)
4216 return SimpleNameResolve (ec, null, true);
4219 public Expression DoResolveType (EmitContext ec)
4222 // Stage 3: Lookup symbol in the various namespaces.
4224 DeclSpace ds = ec.DeclSpace;
4228 if (ec.ResolvingTypeTree){
4229 int errors = Report.Errors;
4230 Type dt = ec.DeclSpace.FindType (loc, Name);
4231 if (Report.Errors != errors)
4235 return new TypeExpr (dt, loc);
4238 if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
4239 return new TypeExpr (t, loc);
4243 // Stage 2 part b: Lookup up if we are an alias to a type
4246 // Since we are cheating: we only do the Alias lookup for
4247 // namespaces if the name does not include any dots in it
4250 alias_value = ec.DeclSpace.LookupAlias (Name);
4252 if (Name.IndexOf ('.') == -1 && alias_value != null) {
4253 if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
4254 return new TypeExpr (t, loc);
4256 // we have alias value, but it isn't Type, so try if it's namespace
4257 return new SimpleName (alias_value, loc);
4260 // No match, maybe our parent can compose us
4261 // into something meaningful.
4266 /// 7.5.2: Simple Names.
4268 /// Local Variables and Parameters are handled at
4269 /// parse time, so they never occur as SimpleNames.
4271 /// The 'allow_static' flag is used by MemberAccess only
4272 /// and it is used to inform us that it is ok for us to
4273 /// avoid the static check, because MemberAccess might end
4274 /// up resolving the Name as a Type name and the access as
4275 /// a static type access.
4277 /// ie: Type Type; .... { Type.GetType (""); }
4279 /// Type is both an instance variable and a Type; Type.GetType
4280 /// is the static method not an instance method of type.
4282 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
4284 Expression e = null;
4287 // Stage 1: Performed by the parser (binding to locals or parameters).
4289 Block current_block = ec.CurrentBlock;
4290 if (ec.InvokingOwnOverload == false && current_block != null && current_block.IsVariableDefined (Name)){
4291 LocalVariableReference var;
4293 var = new LocalVariableReference (current_block, Name, loc);
4295 if (right_side != null)
4296 return var.ResolveLValue (ec, right_side);
4298 return var.Resolve (ec);
4301 if (current_block != null){
4303 Parameter par = null;
4304 Parameters pars = current_block.Parameters;
4306 par = pars.GetParameterByName (Name, out idx);
4309 ParameterReference param;
4311 param = new ParameterReference (pars, idx, Name, loc);
4313 if (right_side != null)
4314 return param.ResolveLValue (ec, right_side);
4316 return param.Resolve (ec);
4321 // Stage 2: Lookup members
4325 // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
4326 // Hence we have two different cases
4329 DeclSpace lookup_ds = ec.DeclSpace;
4331 if (lookup_ds.TypeBuilder == null)
4334 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
4339 // Classes/structs keep looking, enums break
4341 if (lookup_ds is TypeContainer)
4342 lookup_ds = ((TypeContainer) lookup_ds).Parent;
4345 } while (lookup_ds != null);
4347 if (e == null && ec.ContainerType != null)
4348 e = MemberLookup (ec, ec.ContainerType, Name, loc);
4350 // #52067 - Start - Trying to solve
4353 ArrayList lookups = new ArrayList();
4354 ArrayList typelookups = new ArrayList();
4356 int split = Name.LastIndexOf('.');
4358 String nameSpacePart = Name.Substring(0, split);
4359 String memberNamePart = Name.Substring(split + 1);
4360 foreach(Type type in TypeManager.GetPertinentStandardModules(nameSpacePart)) {
4361 e = MemberLookup(ec, type, memberNamePart, loc);
4364 typelookups.Add(type);
4369 string[] NamespacesInScope = RootContext.SourceBeingCompiled.GetNamespacesInScope(ec.DeclSpace.Namespace.Name);
4370 foreach(Type type in TypeManager.GetPertinentStandardModules(NamespacesInScope)) {
4371 e = MemberLookup(ec, type, Name, loc);
4374 typelookups.Add(type);
4377 if (lookups.Count == 1) {
4378 e = (Expression)lookups[0];
4380 if (lookups.Count > 1) {
4381 StringBuilder sb = new StringBuilder();
4382 foreach(Type type in typelookups)
4383 sb.Append("'" + type.FullName + "'");
4384 Error (-1, "The name '" + Name + "' can be resolved to a member of more than one standard module: " + sb.ToString() + ". Please fully qualify it.");
4394 /* preparing to support automatic definition of variables on first usage with Option Explicit Off
4396 Isn't good enough to enable just now (tries to define some internal links and breaks on emit)
4398 if (Name.IndexOf ('.') == -1 && current_block != null && !Mono.MonoBASIC.Parser.OptionExplicit) {
4400 // while looking for a real solution
4401 if (Name != "anything")
4402 return DoResolveType (ec);
4404 Console.WriteLine("Implicitly adding a variable named '{0}'", Name);
4406 // TODO: look at type-suffixes to correct name and type
4407 Expression type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", loc);
4409 current_block.AddVariable(ec, type, Name, loc);
4411 LocalVariableReference var = new LocalVariableReference (current_block, Name, loc);
4412 if (right_side != null)
4413 return var.ResolveLValue (ec, right_side);
4415 return var.Resolve (ec);
4418 return DoResolveType (ec);
4424 if (e is IMemberExpr) {
4425 e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
4429 if (e is PropertyGroupExpr && is_invocation) // We dont know the arguments yet
4432 IMemberExpr me = e as IMemberExpr;
4436 // This fails if ResolveMemberAccess() was unable to decide whether
4437 // it's a field or a type of the same name.
4438 if (!me.IsStatic && (me.InstanceExpression == null))
4441 /* FIXME If this is not commented out, it seems that it's not possible to reach class members in mBas.
4442 Maybe a grammar-related problem?
4445 TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
4446 Error (38, "Cannot access nonstatic member '" + me.Name + "' of " +
4447 "outer type '" + me.DeclaringType + "' via nested type '" +
4448 me.InstanceExpression.Type + "'");
4452 bool isPropertyGroup = (e is PropertyGroupExpr);
4453 if (right_side != null)
4454 e = e.DoResolveLValue (ec, right_side);
4456 e = e.DoResolve (ec);
4458 if (e == null && isPropertyGroup && !is_invocation)
4459 Error (30057, "Property '" + Name + "' cannot be invoked with given arguments");
4464 if (ec.IsStatic || ec.IsFieldInitializer) {
4468 return MemberStaticCheck (ec, e);
4474 public override void Emit (EmitContext ec)
4477 // If this is ever reached, then we failed to
4478 // find the name as a namespace
4481 Error (30451, "The name '" + Name +
4482 "' does not exist in the class '" +
4483 ec.DeclSpace.Name + "'");
4486 public override string ToString ()
4493 /// Fully resolved expression that evaluates to a type
4495 public class TypeExpr : Expression, ITypeExpression {
4496 public TypeExpr (Type t, Location l)
4499 eclass = ExprClass.Type;
4503 public virtual Expression DoResolveType (EmitContext ec)
4508 override public Expression DoResolve (EmitContext ec)
4513 override public void Emit (EmitContext ec)
4515 throw new Exception ("Should never be called");
4518 public override string ToString ()
4520 return Type.ToString ();
4525 /// Used to create types from a fully qualified name. These are just used
4526 /// by the parser to setup the core types. A TypeLookupExpression is always
4527 /// classified as a type.
4529 public class TypeLookupExpression : TypeExpr {
4532 public TypeLookupExpression (string name) : base (null, Location.Null)
4537 public override Expression DoResolveType (EmitContext ec)
4540 type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
4544 public override Expression DoResolve (EmitContext ec)
4546 return DoResolveType (ec);
4549 public override void Emit (EmitContext ec)
4551 throw new Exception ("Should never be called");
4554 public override string ToString ()
4561 /// MethodGroup Expression.
4563 /// This is a fully resolved expression that evaluates to a type
4565 public class MethodGroupExpr : Expression, IMemberExpr {
4566 public MethodBase [] Methods;
4567 Expression instance_expression = null;
4568 bool is_explicit_impl = false;
4570 public MethodGroupExpr (MemberInfo [] mi, Location l)
4572 Methods = new MethodBase [mi.Length];
4573 mi.CopyTo (Methods, 0);
4574 eclass = ExprClass.MethodGroup;
4575 type = TypeManager.object_type;
4579 public MethodGroupExpr (ArrayList list, Location l)
4581 Methods = new MethodBase [list.Count];
4584 list.CopyTo (Methods, 0);
4586 foreach (MemberInfo m in list){
4587 if (!(m is MethodBase)){
4588 Console.WriteLine ("Name " + m.Name);
4589 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4595 eclass = ExprClass.MethodGroup;
4596 type = TypeManager.object_type;
4599 public Type DeclaringType {
4601 return Methods [0].DeclaringType;
4606 // 'A method group may have associated an instance expression'
4608 public Expression InstanceExpression {
4610 return instance_expression;
4614 instance_expression = value;
4618 public bool IsExplicitImpl {
4620 return is_explicit_impl;
4624 is_explicit_impl = value;
4628 public string Name {
4630 return Methods [0].Name;
4634 public bool IsInstance {
4636 foreach (MethodBase mb in Methods)
4644 public bool IsStatic {
4646 foreach (MethodBase mb in Methods)
4654 override public Expression DoResolve (EmitContext ec)
4656 if (instance_expression != null) {
4657 instance_expression = instance_expression.DoResolve (ec);
4658 if (instance_expression == null)
4665 public void ReportUsageError ()
4667 Report.Error (654, loc, "Method '" + Methods [0].DeclaringType + "." +
4668 Methods [0].Name + "()' is referenced without parentheses");
4671 override public void Emit (EmitContext ec)
4673 ReportUsageError ();
4676 bool RemoveMethods (bool keep_static)
4678 ArrayList smethods = new ArrayList ();
4680 foreach (MethodBase mb in Methods){
4681 if (mb.IsStatic == keep_static)
4685 if (smethods.Count == 0)
4688 Methods = new MethodBase [smethods.Count];
4689 smethods.CopyTo (Methods, 0);
4695 /// Removes any instance methods from the MethodGroup, returns
4696 /// false if the resulting set is empty.
4698 public bool RemoveInstanceMethods ()
4700 return RemoveMethods (true);
4704 /// Removes any static methods from the MethodGroup, returns
4705 /// false if the resulting set is empty.
4707 public bool RemoveStaticMethods ()
4709 return RemoveMethods (false);
4714 /// Property Group Expression.
4717 public class PropertyGroupExpr : ExpressionStatement, IMemberExpr {
4718 public PropertyInfo [] Properties;
4719 Expression instance_expression = null;
4720 bool is_explicit_impl = false;
4721 MethodBase method = null;
4722 bool indexer_access_req = false;
4723 ArrayList arguments = null;
4725 public PropertyGroupExpr (MemberInfo [] mi, Location l)
4727 Properties = new PropertyInfo [mi.Length];
4728 mi.CopyTo (Properties, 0);
4729 eclass = ExprClass.PropertyAccess;
4730 type = TypeManager.object_type;
4734 public PropertyGroupExpr (MemberInfo [] mi, ArrayList args, Expression expr, Location l)
4738 instance_expression = expr;
4741 public PropertyGroupExpr (ArrayList list, Location l)
4743 Properties = new PropertyInfo [list.Count];
4746 list.CopyTo (Properties, 0);
4748 foreach (MemberInfo m in list){
4749 if (!(m is PropertyInfo)){
4750 Console.WriteLine ("Name " + m.Name);
4751 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4757 eclass = ExprClass.PropertyAccess;
4758 type = TypeManager.object_type;
4761 public ArrayList Arguments {
4770 public Type DeclaringType {
4772 return Properties [0].DeclaringType;
4776 public bool IndexerAccessRequired {
4778 return indexer_access_req;
4783 // 'A method group may have associated an instance expression'
4785 public Expression InstanceExpression {
4787 return instance_expression;
4791 instance_expression = value;
4795 public bool IsExplicitImpl {
4797 return is_explicit_impl;
4801 is_explicit_impl = value;
4805 public string Name {
4807 return Properties [0].Name;
4811 public bool IsInstance {
4813 foreach (PropertyInfo pi in Properties) {
4814 MethodInfo mi = pi.GetGetMethod ();
4815 if (mi != null && !mi.IsStatic)
4817 mi = pi.GetSetMethod ();
4818 if (mi != null && !mi.IsStatic)
4825 public bool IsStatic {
4827 return (!IsInstance);
4831 public ArrayList GetAccessors () {
4832 ArrayList GetAccessors = new ArrayList ();
4833 foreach (PropertyInfo pi in Properties) {
4834 if (pi.GetGetMethod () != null)
4835 GetAccessors.Add (pi.GetGetMethod ());
4837 return GetAccessors;
4840 public ArrayList SetAccessors () {
4841 ArrayList SetAccessors = new ArrayList ();
4842 foreach (PropertyInfo pi in Properties) {
4843 if (pi.GetSetMethod () != null)
4844 SetAccessors.Add (pi.GetSetMethod ());
4846 return SetAccessors;
4849 override public Expression DoResolve (EmitContext ec)
4851 if (instance_expression != null) {
4852 instance_expression = instance_expression.DoResolve (ec);
4853 if (instance_expression == null)
4857 ArrayList members = GetAccessors ();
4858 if (members == null || members.Count == 0) {
4859 Report.Error (30524, loc, "Property '" + Name + "' lacks a 'get' accesor");
4863 MethodGroupExpr m_expr = new MethodGroupExpr (members, loc);
4864 method = Invocation.OverloadResolve (ec, m_expr, ref arguments, loc);
4865 if ((method as MethodInfo) != null) {
4866 MethodInfo mi = method as MethodInfo;
4867 type = TypeManager.TypeToCoreType (mi.ReturnType);
4868 indexer_access_req = false;
4869 eclass = ExprClass.Value;
4872 // find a get method that doesnt take any arguments. Check the return type of
4873 // that method to find out if indexer access is required. Leave the rest to
4874 // 'Invocation's Resolve'
4875 method = Invocation.OverloadResolve (ec, m_expr, null, loc);
4876 if (method != null) {
4877 MethodInfo mi = method as MethodInfo;
4878 Type ret_type = mi.ReturnType;
4879 if (ret_type.IsArray)
4880 indexer_access_req = true;
4882 Indexers list = Indexers.GetIndexersForType (ec.ContainerType, ret_type, loc);
4883 if (list != null && list.getters.Count > 0)
4884 indexer_access_req = true;
4889 type = mi.ReturnType;
4897 override public Expression DoResolveLValue (EmitContext ec, Expression right_side) {
4898 if (instance_expression != null) {
4899 instance_expression = instance_expression.DoResolve (ec);
4900 if (instance_expression == null)
4904 ArrayList members = SetAccessors ();
4905 if (members == null || members.Count == 0) {
4906 Report.Error (30524, loc, "Property '" + Name + "' lacks a 'set' accesor");
4910 MethodGroupExpr m_expr = new MethodGroupExpr (members, loc);
4911 if (arguments == null)
4912 arguments = new ArrayList ();
4913 arguments.Add (new Argument (right_side, Argument.AType.Expression));
4914 method = Invocation.OverloadResolve (ec, m_expr, ref arguments, loc);
4915 if (method != null) {
4916 //MethodInfo mi = method as MethodInfo;
4917 type = TypeManager.void_type; //TypeManager.TypeToCoreType (mi.ReturnType);
4918 eclass = ExprClass.Value;
4919 indexer_access_req = false;
4922 // Look for properties that do not take any arguments.
4923 // Check if the return type has any indexers
4926 if (method != null) {
4927 MethodInfo mi = method as MethodInfo;
4928 Type ret_type = mi.ReturnType;
4929 if (ret_type.IsArray)
4930 indexer_access_req = true;
4933 Indexers list = Indexers.GetIndexersForType (ec.ContainerType,
4935 if (list != null && list.setters.Count > 0)
4936 indexer_access_req = true;
4940 type = mi.ReturnType;
4948 override public void Emit (EmitContext ec)
4950 if (Arguments == null)
4951 Arguments = new ArrayList ();
4952 Invocation.EmitCall (ec, false, IsStatic, instance_expression, method, null, Arguments, loc);
4955 override public void EmitStatement (EmitContext ec)
4963 /// Fully resolved expression that evaluates to a Field
4965 public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr {
4966 public readonly FieldInfo FieldInfo;
4967 Expression instance_expr;
4969 public FieldExpr (FieldInfo fi, Location l)
4972 eclass = ExprClass.Variable;
4973 type = fi.FieldType;
4977 public string Name {
4979 return FieldInfo.Name;
4983 public bool IsInstance {
4985 return !FieldInfo.IsStatic;
4989 public bool IsStatic {
4991 return FieldInfo.IsStatic;
4995 public Type DeclaringType {
4997 return FieldInfo.DeclaringType;
5001 public Expression InstanceExpression {
5003 return instance_expr;
5007 instance_expr = value;
5011 override public Expression DoResolve (EmitContext ec)
5013 if (!FieldInfo.IsStatic){
5014 if (instance_expr == null){
5015 throw new Exception ("non-static FieldExpr without instance var\n" +
5016 "You have to assign the Instance variable\n" +
5017 "Of the FieldExpr to set this\n");
5020 // Resolve the field's instance expression while flow analysis is turned
5021 // off: when accessing a field "a.b", we must check whether the field
5022 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5023 instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
5024 ResolveFlags.DisableFlowAnalysis);
5025 if (instance_expr == null)
5029 // If the instance expression is a local variable or parameter.
5030 IVariable var = instance_expr as IVariable;
5031 if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc))
5037 void Report_AssignToReadonly (bool is_instance)
5042 msg = "Readonly field can not be assigned outside " +
5043 "of constructor or variable initializer";
5045 msg = "A static readonly field can only be assigned in " +
5046 "a static constructor";
5048 Report.Error (is_instance ? 191 : 198, loc, msg);
5051 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5053 IVariable var = instance_expr as IVariable;
5055 var.SetFieldAssigned (ec, FieldInfo.Name);
5057 Expression e = DoResolve (ec);
5062 if (!FieldInfo.IsInitOnly)
5066 // InitOnly fields can only be assigned in constructors
5069 if (ec.IsConstructor)
5072 Report_AssignToReadonly (true);
5077 override public void Emit (EmitContext ec)
5079 ILGenerator ig = ec.ig;
5080 bool is_volatile = false;
5082 if (FieldInfo is FieldBuilder){
5083 FieldBase f = TypeManager.GetField (FieldInfo);
5085 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5088 f.status |= Field.Status.USED;
5091 if (FieldInfo.IsStatic){
5093 ig.Emit (OpCodes.Volatile);
5095 ig.Emit (OpCodes.Ldsfld, FieldInfo);
5097 if (instance_expr.Type.IsValueType){
5099 LocalTemporary tempo = null;
5101 if (!(instance_expr is IMemoryLocation)){
5102 tempo = new LocalTemporary (
5103 ec, instance_expr.Type);
5105 InstanceExpression.Emit (ec);
5109 ml = (IMemoryLocation) instance_expr;
5111 ml.AddressOf (ec, AddressOp.Load);
5113 instance_expr.Emit (ec);
5116 ig.Emit (OpCodes.Volatile);
5118 ig.Emit (OpCodes.Ldfld, FieldInfo);
5122 public void EmitAssign (EmitContext ec, Expression source)
5124 FieldAttributes fa = FieldInfo.Attributes;
5125 bool is_static = (fa & FieldAttributes.Static) != 0;
5126 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5127 ILGenerator ig = ec.ig;
5129 if (is_readonly && !ec.IsConstructor){
5130 Report_AssignToReadonly (!is_static);
5135 Expression instance = instance_expr;
5137 if (instance.Type.IsValueType){
5138 if (instance is IMemoryLocation){
5139 IMemoryLocation ml = (IMemoryLocation) instance;
5141 ml.AddressOf (ec, AddressOp.Store);
5143 throw new Exception ("The " + instance + " of type " +
5145 " represents a ValueType and does " +
5146 "not implement IMemoryLocation");
5152 if (FieldInfo is FieldBuilder){
5153 FieldBase f = TypeManager.GetField (FieldInfo);
5155 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5156 ig.Emit (OpCodes.Volatile);
5160 ig.Emit (OpCodes.Stsfld, FieldInfo);
5162 ig.Emit (OpCodes.Stfld, FieldInfo);
5164 if (FieldInfo is FieldBuilder){
5165 FieldBase f = TypeManager.GetField (FieldInfo);
5167 f.status |= Field.Status.ASSIGNED;
5171 public void AddressOf (EmitContext ec, AddressOp mode)
5173 ILGenerator ig = ec.ig;
5175 if (FieldInfo is FieldBuilder){
5176 FieldBase f = TypeManager.GetField (FieldInfo);
5177 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5178 ig.Emit (OpCodes.Volatile);
5181 if (FieldInfo is FieldBuilder){
5182 FieldBase f = TypeManager.GetField (FieldInfo);
5184 if ((mode & AddressOp.Store) != 0)
5185 f.status |= Field.Status.ASSIGNED;
5186 if ((mode & AddressOp.Load) != 0)
5187 f.status |= Field.Status.USED;
5191 // Handle initonly fields specially: make a copy and then
5192 // get the address of the copy.
5194 if (FieldInfo.IsInitOnly && !ec.IsConstructor){
5198 local = ig.DeclareLocal (type);
5199 ig.Emit (OpCodes.Stloc, local);
5200 ig.Emit (OpCodes.Ldloca, local);
5204 if (FieldInfo.IsStatic)
5205 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5207 if (instance_expr is IMemoryLocation)
5208 ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
5210 instance_expr.Emit (ec);
5211 ig.Emit (OpCodes.Ldflda, FieldInfo);
5217 /// Expression that evaluates to a Property. The Assign class
5218 /// might set the 'Value' expression if we are in an assignment.
5220 /// This is not an LValue because we need to re-write the expression, we
5221 /// can not take data from the stack and store it.
5223 public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
5224 public readonly PropertyInfo PropertyInfo;
5226 MethodInfo getter, setter;
5228 public ArrayList PropertyArgs;
5230 Expression instance_expr;
5232 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
5235 eclass = ExprClass.PropertyAccess;
5236 PropertyArgs = null;
5240 type = TypeManager.TypeToCoreType (pi.PropertyType);
5242 ResolveAccessors (ec);
5245 public string Name {
5247 return PropertyInfo.Name;
5251 public bool IsInstance {
5257 public bool IsStatic {
5263 public Type DeclaringType {
5265 return PropertyInfo.DeclaringType;
5270 // The instance expression associated with this expression
5272 public Expression InstanceExpression {
5274 instance_expr = value;
5278 return instance_expr;
5282 public bool VerifyAssignable ()
5284 if (!PropertyInfo.CanWrite){
5285 Report.Error (200, loc,
5286 "The property '" + PropertyInfo.Name +
5287 "' can not be assigned to, as it has not set accessor");
5294 void ResolveAccessors (EmitContext ec)
5296 BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
5297 MemberInfo [] group;
5299 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5300 MemberTypes.Method, flags, "get_" + PropertyInfo.Name);
5303 // The first method is the closest to us
5305 if (group != null && group.Length > 0){
5306 getter = (MethodInfo) group [0];
5308 if (getter.IsStatic)
5313 // The first method is the closest to us
5315 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5316 MemberTypes.Method, flags, "set_" + PropertyInfo.Name);
5317 if (group != null && group.Length > 0){
5318 setter = (MethodInfo) group [0];
5319 if (setter.IsStatic)
5324 override public Expression DoResolve (EmitContext ec)
5326 if (getter == null){
5327 Report.Error (30524, loc,
5328 "The property '" + PropertyInfo.Name +
5329 "' can not be used in " +
5330 "this context because it lacks a get accessor");
5334 if ((instance_expr == null) && ec.IsStatic && !is_static) {
5335 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
5339 if (instance_expr != null) {
5340 instance_expr = instance_expr.DoResolve (ec);
5341 if (instance_expr == null)
5348 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5350 if (setter == null){
5351 Report.Error (30526, loc,
5352 "The property '" + PropertyInfo.Name +
5353 "' can not be used in " +
5354 "this context because it lacks a set accessor");
5358 if (instance_expr != null) {
5359 instance_expr = instance_expr.DoResolve (ec);
5360 if (instance_expr == null)
5367 override public void Emit (EmitContext ec)
5370 // Special case: length of single dimension array property is turned into ldlen
5372 if ((getter == TypeManager.system_int_array_get_length) ||
5373 (getter == TypeManager.int_array_get_length)){
5374 Type iet = instance_expr.Type;
5377 // System.Array.Length can be called, but the Type does not
5378 // support invoking GetArrayRank, so test for that case first
5380 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
5381 instance_expr.Emit (ec);
5382 ec.ig.Emit (OpCodes.Ldlen);
5386 if (PropertyArgs == null)
5387 PropertyArgs = new ArrayList ();
5388 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, PropertyArgs, loc);
5392 // Implements the IAssignMethod interface for assignments
5394 public void EmitAssign (EmitContext ec, Expression source)
5396 Argument arg = new Argument (source, Argument.AType.Expression);
5397 ArrayList args = new ArrayList ();
5400 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, PropertyArgs,loc);
5403 override public void EmitStatement (EmitContext ec)
5406 ec.ig.Emit (OpCodes.Pop);
5411 /// Fully resolved expression that evaluates to an Event
5413 public class EventExpr : Expression, IMemberExpr {
5414 public readonly EventInfo EventInfo;
5415 public Expression instance_expr;
5418 MethodInfo add_accessor, remove_accessor;
5420 public EventExpr (EventInfo ei, Location loc)
5424 eclass = ExprClass.EventAccess;
5426 add_accessor = TypeManager.GetAddMethod (ei);
5427 remove_accessor = TypeManager.GetRemoveMethod (ei);
5429 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5432 if (EventInfo is MyEventBuilder)
5433 type = ((MyEventBuilder) EventInfo).EventType;
5435 type = EventInfo.EventHandlerType;
5438 public string Name {
5440 return EventInfo.Name;
5444 public bool IsInstance {
5450 public bool IsStatic {
5456 public Type DeclaringType {
5458 return EventInfo.DeclaringType;
5462 public Expression InstanceExpression {
5464 return instance_expr;
5468 instance_expr = value;
5472 Expression field_expr = null;
5474 public override Expression DoResolve (EmitContext ec)
5476 if (instance_expr != null) {
5477 instance_expr = instance_expr.DoResolve (ec);
5478 if (instance_expr == null)
5482 if (this.DeclaringType == ec.ContainerType) {
5483 MemberInfo mi = GetFieldFromEvent (this);
5486 field_expr = ExprClassFromMemberInfo (ec, mi, loc);
5487 ((FieldExpr) field_expr).InstanceExpression = instance_expr;
5488 field_expr = field_expr.DoResolve (ec);
5489 if (field_expr == null)
5496 public override void Emit (EmitContext ec)
5498 if (field_expr != null)
5499 field_expr.Emit (ec);
5502 public void EmitAddOrRemove (EmitContext ec, Expression source)
5504 Expression handler = ((Binary) source).Right;
5506 Argument arg = new Argument (handler, Argument.AType.Expression);
5507 ArrayList args = new ArrayList ();
5511 if (((Binary) source).Oper == Binary.Operator.Addition)
5512 Invocation.EmitCall (
5513 ec, false, IsStatic, instance_expr, add_accessor, args, loc);
5515 Invocation.EmitCall (
5516 ec, false, IsStatic, instance_expr, remove_accessor, args, loc);