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 (TypeManager.IsEnumType (t)){
508 Constant e = Constantify (v, TypeManager.TypeToCoreType (v.GetType ()));
510 return new EnumConstant (e, t);
512 throw new Exception ("Unknown type for constant (" + t +
517 /// Returns a fully formed expression after a MemberLookup
519 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
522 return new EventExpr ((EventInfo) mi, loc);
523 else if (mi is FieldInfo)
524 return new FieldExpr ((FieldInfo) mi, loc);
525 else if (mi is PropertyInfo)
526 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
527 else if (mi is Type){
528 return new TypeExpr ((System.Type) mi, loc);
535 // FIXME: Probably implement a cache for (t,name,current_access_set)?
537 // This code could use some optimizations, but we need to do some
538 // measurements. For example, we could use a delegate to 'flag' when
539 // something can not any longer be a method-group (because it is something
543 // If the return value is an Array, then it is an array of
546 // If the return value is an MemberInfo, it is anything, but a Method
550 // FIXME: When calling MemberLookup inside an 'Invocation', we should pass
551 // the arguments here and have MemberLookup return only the methods that
552 // match the argument count/type, unlike we are doing now (we delay this
555 // This is so we can catch correctly attempts to invoke instance methods
556 // from a static body (scan for error 120 in ResolveSimpleName).
559 // FIXME: Potential optimization, have a static ArrayList
562 public static Expression MemberLookup (EmitContext ec, Type t, string name,
563 MemberTypes mt, BindingFlags bf, Location loc)
565 return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
569 // Lookup type 't' for code in class 'invocation_type'. Note that it's important
570 // to set 'invocation_type' correctly since this method also checks whether the
571 // invoking class is allowed to access the member in class 't'. When you want to
572 // explicitly do a lookup in the base class, you must set both 't' and 'invocation_type'
573 // to the base class (although a derived class can access protected members of its base
574 // class it cannot do so through an instance of the base class (error CS1540)).
577 public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
578 string name, MemberTypes mt, BindingFlags bf,
581 MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
586 int count = mi.Length;
589 return new MethodGroupExpr (mi, loc);
591 if (mi [0] is MethodBase)
592 return new MethodGroupExpr (mi, loc);
594 return ExprClassFromMemberInfo (ec, mi [0], loc);
597 public const MemberTypes AllMemberTypes =
598 MemberTypes.Constructor |
602 MemberTypes.NestedType |
603 MemberTypes.Property;
605 public const BindingFlags AllBindingFlags =
606 BindingFlags.Public |
607 BindingFlags.Static |
608 BindingFlags.Instance |
609 BindingFlags.IgnoreCase;
611 public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc)
613 return MemberLookup (ec, ec.ContainerType, t, name, AllMemberTypes, AllBindingFlags, loc);
616 public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
618 return MemberLookup (ec, ec.ContainerType, t, name,
619 MemberTypes.Method, AllBindingFlags, loc);
623 /// This is a wrapper for MemberLookup that is not used to "probe", but
624 /// to find a final definition. If the final definition is not found, we
625 /// look for private members and display a useful debugging message if we
628 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
631 return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
634 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
635 MemberTypes mt, BindingFlags bf, Location loc)
639 int errors = Report.Errors;
641 e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
646 // Error has already been reported.
647 if (errors < Report.Errors)
650 e = MemberLookup (ec, t, name, AllMemberTypes,
651 AllBindingFlags | BindingFlags.NonPublic, loc);
654 30456, loc, "'" + t + "' does not contain a definition " +
655 "for '" + name + "'");
658 30390, loc, "'" + t + "." + name +
659 "' is inaccessible due to its protection level");
665 static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
667 EventInfo ei = event_expr.EventInfo;
669 return TypeManager.GetPrivateFieldOfEvent (ei);
672 static EmptyExpression MyEmptyExpr;
673 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
675 Type expr_type = expr.Type;
677 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
678 // if we are a method group, emit a warning
684 // notice that it is possible to write "ValueType v = 1", the ValueType here
685 // is an abstract class, and not really a value type, so we apply the same rules.
687 if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) {
689 // A pointer type cannot be converted to object
691 if (expr_type.IsPointer)
694 if (expr_type.IsValueType)
695 return new BoxedCast (expr);
696 if (expr_type.IsClass || expr_type.IsInterface)
697 return new EmptyCast (expr, target_type);
698 } else if (expr_type.IsSubclassOf (target_type)) {
700 // Special case: enumeration to System.Enum.
701 // System.Enum is not a value type, it is a class, so we need
702 // a boxing conversion
704 if (expr_type.IsEnum)
705 return new BoxedCast (expr);
707 return new EmptyCast (expr, target_type);
710 // This code is kind of mirrored inside StandardConversionExists
711 // with the small distinction that we only probe there
713 // Always ensure that the code here and there is in sync
715 // from the null type to any reference-type.
716 if (expr is NullLiteral && !target_type.IsValueType)
717 return new EmptyCast (expr, target_type);
719 // from any class-type S to any interface-type T.
720 if (target_type.IsInterface) {
721 if (TypeManager.ImplementsInterface (expr_type, target_type)){
722 if (expr_type.IsClass)
723 return new EmptyCast (expr, target_type);
724 else if (expr_type.IsValueType)
725 return new BoxedCast (expr);
729 // from any interface type S to interface-type T.
730 if (expr_type.IsInterface && target_type.IsInterface) {
731 if (TypeManager.ImplementsInterface (expr_type, target_type))
732 return new EmptyCast (expr, target_type);
737 // from an array-type S to an array-type of type T
738 if (expr_type.IsArray && target_type.IsArray) {
739 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
741 Type expr_element_type = expr_type.GetElementType ();
743 if (MyEmptyExpr == null)
744 MyEmptyExpr = new EmptyExpression ();
746 MyEmptyExpr.SetType (expr_element_type);
747 Type target_element_type = target_type.GetElementType ();
749 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
750 if (StandardConversionExists (MyEmptyExpr,
751 target_element_type))
752 return new EmptyCast (expr, target_type);
757 // from an array-type to System.Array
758 if (expr_type.IsArray && target_type == TypeManager.array_type)
759 return new EmptyCast (expr, target_type);
761 // from any delegate type to System.Delegate
762 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
763 target_type == TypeManager.delegate_type)
764 return new EmptyCast (expr, target_type);
766 // from any array-type or delegate type into System.ICloneable.
767 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
768 if (target_type == TypeManager.icloneable_type)
769 return new EmptyCast (expr, target_type);
779 /// Implicit Numeric Conversions.
781 /// expr is the expression to convert, returns a new expression of type
782 /// target_type or null if an implicit conversion is not possible.
784 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
785 Type target_type, Location loc)
787 Type expr_type = expr.Type;
790 // Attempt to do the implicit constant expression conversions
792 if (expr is BoolConstant || expr is IntConstant || expr is LongConstant || expr is DoubleConstant || expr is FloatConstant){
795 e = TryImplicitNumericConversion (target_type, (Constant) expr);
799 if (target_type == TypeManager.byte_type ||
800 target_type == TypeManager.short_type ||
801 target_type == TypeManager.int32_type ||
802 target_type == TypeManager.int64_type ||
803 target_type == TypeManager.float_type) {
806 if (expr is IntConstant)
807 val = ((IntConstant) expr).Value.ToString();
808 if (expr is LongConstant)
809 val = ((LongConstant) expr).Value.ToString();
810 if (expr is FloatConstant)
811 val = ((FloatConstant) expr).Value.ToString();
812 if (expr is DoubleConstant)
813 val = ((DoubleConstant) expr).Value.ToString();
814 Error_ConstantValueCannotBeConverted(loc, val, target_type);
817 } else if (expr is LongConstant && target_type == TypeManager.uint64_type) {
819 // Try the implicit constant expression conversion
820 // from long to ulong, instead of a nice routine,
823 long v = ((LongConstant) expr).Value;
825 return new ULongConstant ((ulong) v);
828 Type real_target_type = target_type;
830 if (target_type == TypeManager.bool_type) {
832 if (expr_type == TypeManager.decimal_type) {
833 return RTConversionExpression (ec, "System.Convert",".ToBoolean" , expr, loc);
836 if ((expr_type != TypeManager.char_type) &&
837 (expr_type != TypeManager.string_type))
838 return new NumericToBoolCast (expr, expr.Type);
841 if (expr_type == TypeManager.bool_type){
843 if (real_target_type == TypeManager.sbyte_type)
844 return new BoolToNumericCast (expr, target_type);
845 if (real_target_type == TypeManager.byte_type)
846 return new BoolToNumericCast (expr, target_type);
847 if (real_target_type == TypeManager.int32_type)
848 return new BoolToNumericCast (expr, target_type);
849 if (real_target_type == TypeManager.int64_type)
850 return new BoolToNumericCast (expr, target_type);
851 if (real_target_type == TypeManager.double_type)
852 return new BoolToNumericCast (expr, target_type);
853 if (real_target_type == TypeManager.float_type)
854 return new BoolToNumericCast (expr, target_type);
855 if (real_target_type == TypeManager.short_type)
856 return new BoolToNumericCast (expr, target_type);
857 if (real_target_type == TypeManager.decimal_type)
858 return RTConversionExpression(ec, "DecimalType.FromBoolean", expr, loc);
859 } else if (expr_type == TypeManager.sbyte_type){
861 // From sbyte to short, int, long, float, double.
863 if (real_target_type == TypeManager.int32_type)
864 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
865 if (real_target_type == TypeManager.int64_type)
866 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
867 if (real_target_type == TypeManager.double_type)
868 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
869 if (real_target_type == TypeManager.float_type)
870 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
871 if (real_target_type == TypeManager.short_type)
872 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
873 } else if (expr_type == TypeManager.byte_type){
875 // From byte to short, ushort, int, uint, long, ulong, float, double
877 if ((real_target_type == TypeManager.short_type) ||
878 (real_target_type == TypeManager.ushort_type) ||
879 (real_target_type == TypeManager.int32_type) ||
880 (real_target_type == TypeManager.uint32_type))
881 return new EmptyCast (expr, target_type);
883 if (real_target_type == TypeManager.uint64_type)
884 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
885 if (real_target_type == TypeManager.int64_type)
886 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
887 if (real_target_type == TypeManager.float_type)
888 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
889 if (real_target_type == TypeManager.double_type)
890 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
891 } else if (expr_type == TypeManager.short_type){
893 // From short to int, long, float, double
895 if (real_target_type == TypeManager.int32_type)
896 return new EmptyCast (expr, target_type);
897 if (real_target_type == TypeManager.int64_type)
898 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
899 if (real_target_type == TypeManager.double_type)
900 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
901 if (real_target_type == TypeManager.float_type)
902 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
903 } else if (expr_type == TypeManager.ushort_type){
905 // From ushort to int, uint, long, ulong, float, double
907 if (real_target_type == TypeManager.uint32_type)
908 return new EmptyCast (expr, target_type);
910 if (real_target_type == TypeManager.uint64_type)
911 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
912 if (real_target_type == TypeManager.int32_type)
913 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
914 if (real_target_type == TypeManager.int64_type)
915 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
916 if (real_target_type == TypeManager.double_type)
917 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
918 if (real_target_type == TypeManager.float_type)
919 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
920 } else if (expr_type == TypeManager.int32_type){
922 // From int to long, float, double
924 if (real_target_type == TypeManager.int64_type)
925 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
926 if (real_target_type == TypeManager.double_type)
927 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
928 if (real_target_type == TypeManager.float_type)
929 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
930 } else if (expr_type == TypeManager.uint32_type){
932 // From uint to long, ulong, float, double
934 if (real_target_type == TypeManager.int64_type)
935 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
936 if (real_target_type == TypeManager.uint64_type)
937 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
938 if (real_target_type == TypeManager.double_type)
939 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
941 if (real_target_type == TypeManager.float_type)
942 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
944 } else if (expr_type == TypeManager.int64_type){
946 // From long/ulong to float, double
948 if (real_target_type == TypeManager.double_type)
949 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
950 if (real_target_type == TypeManager.float_type)
951 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
952 } else if (expr_type == TypeManager.uint64_type){
954 // From ulong to float, double
956 if (real_target_type == TypeManager.double_type)
957 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
959 if (real_target_type == TypeManager.float_type)
960 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
962 } else if (expr_type == TypeManager.char_type){
964 // From char to ushort, int, uint, long, ulong, float, double
966 if ((real_target_type == TypeManager.ushort_type) ||
967 (real_target_type == TypeManager.int32_type) ||
968 (real_target_type == TypeManager.uint32_type))
969 return new EmptyCast (expr, target_type);
970 if (real_target_type == TypeManager.uint64_type)
971 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
972 if (real_target_type == TypeManager.int64_type)
973 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
974 if (real_target_type == TypeManager.float_type)
975 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
976 if (real_target_type == TypeManager.double_type)
977 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
978 } else if (expr_type == TypeManager.string_type){
980 if (real_target_type == TypeManager.bool_type)
981 return RTConversionExpression (ec, "BooleanType.FromString" , expr, loc);
982 if (real_target_type == TypeManager.decimal_type)
983 return RTConversionExpression (ec, "DecimalType.FromString" , expr, loc);
984 if (real_target_type == TypeManager.float_type)
985 return RTConversionExpression (ec, "SingleType.FromString" , expr, loc);
986 if (real_target_type == TypeManager.short_type)
987 return RTConversionExpression (ec, "ShortType.FromString" , expr, loc);
988 if (real_target_type == TypeManager.int64_type)
989 return RTConversionExpression (ec, "LongType.FromString" , expr, loc);
990 if (real_target_type == TypeManager.int32_type)
991 return RTConversionExpression (ec, "IntegerType.FromString" , expr, loc);
992 if (real_target_type == TypeManager.double_type)
993 return RTConversionExpression (ec, "DoubleType.FromString" , expr, loc);
994 if (real_target_type == TypeManager.byte_type)
995 return RTConversionExpression (ec, "ByteType.FromString" , expr, loc);
996 } else if (expr_type == TypeManager.float_type){
1000 if (real_target_type == TypeManager.decimal_type)
1001 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
1002 if (real_target_type == TypeManager.double_type)
1003 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
1005 } else if (expr_type == TypeManager.double_type){
1007 if (real_target_type == TypeManager.decimal_type)
1008 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
1009 } else if (expr_type == TypeManager.decimal_type){
1011 if (real_target_type == TypeManager.bool_type)
1012 return RTConversionExpression (ec, "BooleanType.FromDecimal" , expr, loc);
1013 if (real_target_type == TypeManager.short_type)
1014 return RTConversionExpression(ec, "System.Convert", ".ToInt16", expr, loc);
1015 if (real_target_type == TypeManager.byte_type)
1016 return RTConversionExpression(ec, "System.Convert", ".ToByte", expr, loc);
1017 if (real_target_type == TypeManager.int32_type)
1018 return RTConversionExpression(ec, "System.Convert", ".ToInt32", expr, loc);
1019 if (real_target_type == TypeManager.int64_type)
1020 return RTConversionExpression(ec, "System.Convert", ".ToInt64", expr, loc);
1021 if (real_target_type == TypeManager.float_type)
1022 return RTConversionExpression(ec, "System.Convert", ".ToSingle", expr, loc);
1023 if (real_target_type == TypeManager.double_type)
1024 return RTConversionExpression(ec, "System.Convert", ".ToDouble", expr, loc);
1025 if (real_target_type == TypeManager.char_type)
1026 return RTConversionExpression(ec, "System.Convert", ".ToChar", expr, loc);
1033 // Tests whether an implicit reference conversion exists between expr_type
1036 public static bool ImplicitReferenceConversionExists (Expression expr, Type expr_type, Type target_type)
1039 // This is the boxed case.
1041 if (target_type == TypeManager.object_type) {
1042 if ((expr_type.IsClass) ||
1043 (expr_type.IsValueType) ||
1044 (expr_type.IsInterface))
1047 } else if (expr_type.IsSubclassOf (target_type)) {
1050 // Please remember that all code below actually comes
1051 // from ImplicitReferenceConversion so make sure code remains in sync
1053 // from any class-type S to any interface-type T.
1054 if (target_type.IsInterface) {
1055 if (TypeManager.ImplementsInterface (expr_type, target_type))
1059 // from any interface type S to interface-type T.
1060 if (expr_type.IsInterface && target_type.IsInterface)
1061 if (TypeManager.ImplementsInterface (expr_type, target_type))
1064 // from an array-type S to an array-type of type T
1065 if (expr_type.IsArray && target_type.IsArray) {
1066 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
1068 Type expr_element_type = expr_type.GetElementType ();
1070 if (MyEmptyExpr == null)
1071 MyEmptyExpr = new EmptyExpression ();
1073 MyEmptyExpr.SetType (expr_element_type);
1074 Type target_element_type = target_type.GetElementType ();
1076 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
1077 if (StandardConversionExists (MyEmptyExpr,
1078 target_element_type))
1083 // from an array-type to System.Array
1084 if (expr_type.IsArray && (target_type == TypeManager.array_type))
1087 // from any delegate type to System.Delegate
1088 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
1089 target_type == TypeManager.delegate_type)
1090 if (target_type.IsAssignableFrom (expr_type))
1093 // from any array-type or delegate type into System.ICloneable.
1094 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
1095 if (target_type == TypeManager.icloneable_type)
1098 // from the null type to any reference-type.
1099 if (expr is NullLiteral && !target_type.IsValueType &&
1100 !TypeManager.IsEnumType (target_type))
1109 /// Same as StandardConversionExists except that it also looks at
1110 /// implicit user defined conversions - needed for overload resolution
1112 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
1114 if (StandardConversionExists (expr, target_type) == true)
1118 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
1128 /// Determines if a standard implicit conversion exists from
1129 /// expr_type to target_type
1131 public static bool StandardConversionExists (Expression expr, Type target_type)
1133 return WideningConversionExists (expr, expr.type, target_type);
1136 public static bool WideningConversionExists (Type expr_type, Type target_type)
1138 return WideningConversionExists (null, expr_type, target_type);
1141 public static bool WideningConversionExists (Expression expr, Type target_type)
1143 return WideningConversionExists (expr, expr.Type, target_type);
1146 public static bool WideningConversionExists (Expression expr, Type expr_type, Type target_type)
1149 if (expr_type == null || expr_type == TypeManager.void_type)
1152 if (expr_type == target_type)
1155 // Conversions from enum to underlying type are widening.
1156 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1157 expr_type = TypeManager.EnumToUnderlying (expr_type);
1159 if (expr_type == target_type)
1162 // First numeric conversions
1164 if (expr_type == TypeManager.sbyte_type){
1166 // From sbyte to short, int, long, float, double.
1168 if ((target_type == TypeManager.int32_type) ||
1169 (target_type == TypeManager.int64_type) ||
1170 (target_type == TypeManager.double_type) ||
1171 (target_type == TypeManager.float_type) ||
1172 (target_type == TypeManager.short_type) ||
1173 (target_type == TypeManager.decimal_type))
1176 } else if (expr_type == TypeManager.byte_type){
1178 // From byte to short, ushort, int, uint, long, ulong, float, double
1180 if ((target_type == TypeManager.short_type) ||
1181 (target_type == TypeManager.bool_type) ||
1182 (target_type == TypeManager.ushort_type) ||
1183 (target_type == TypeManager.int32_type) ||
1184 (target_type == TypeManager.uint32_type) ||
1185 (target_type == TypeManager.uint64_type) ||
1186 (target_type == TypeManager.int64_type) ||
1187 (target_type == TypeManager.float_type) ||
1188 (target_type == TypeManager.double_type) ||
1189 (target_type == TypeManager.decimal_type))
1192 } else if (expr_type == TypeManager.short_type){
1194 // From short to int, long, float, double
1196 if ((target_type == TypeManager.int32_type) ||
1197 (target_type == TypeManager.bool_type) ||
1198 (target_type == TypeManager.int64_type) ||
1199 (target_type == TypeManager.double_type) ||
1200 (target_type == TypeManager.float_type) ||
1201 (target_type == TypeManager.decimal_type))
1204 } else if (expr_type == TypeManager.ushort_type){
1206 // From ushort to int, uint, long, ulong, float, double
1208 if ((target_type == TypeManager.uint32_type) ||
1209 (target_type == TypeManager.uint64_type) ||
1210 (target_type == TypeManager.int32_type) ||
1211 (target_type == TypeManager.int64_type) ||
1212 (target_type == TypeManager.double_type) ||
1213 (target_type == TypeManager.float_type) ||
1214 (target_type == TypeManager.decimal_type))
1217 } else if (expr_type == TypeManager.int32_type){
1219 // From int to long, float, double
1221 if ((target_type == TypeManager.int64_type) ||
1222 (target_type == TypeManager.bool_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.uint32_type){
1230 // From uint to long, ulong, float, double
1232 if ((target_type == TypeManager.int64_type) ||
1233 (target_type == TypeManager.bool_type) ||
1234 (target_type == TypeManager.uint64_type) ||
1235 (target_type == TypeManager.double_type) ||
1236 (target_type == TypeManager.float_type) ||
1237 (target_type == TypeManager.decimal_type))
1240 } else if ((expr_type == TypeManager.uint64_type) ||
1241 (expr_type == TypeManager.int64_type)) {
1243 // From long/ulong to float, double
1245 if ((target_type == TypeManager.double_type) ||
1246 (target_type == TypeManager.bool_type) ||
1247 (target_type == TypeManager.float_type) ||
1248 (target_type == TypeManager.decimal_type))
1251 } else if (expr_type == TypeManager.char_type){
1253 // From char to ushort, int, uint, long, ulong, float, double
1255 if ((target_type == TypeManager.ushort_type) ||
1256 (target_type == TypeManager.int32_type) ||
1257 (target_type == TypeManager.uint32_type) ||
1258 (target_type == TypeManager.uint64_type) ||
1259 (target_type == TypeManager.int64_type) ||
1260 (target_type == TypeManager.float_type) ||
1261 (target_type == TypeManager.double_type) ||
1262 (target_type == TypeManager.string_type) ||
1263 (target_type == TypeManager.decimal_type))
1266 } else if (expr_type == TypeManager.decimal_type) {
1267 if (target_type == TypeManager.float_type ||
1268 target_type == TypeManager.double_type)
1270 } else if (expr_type == TypeManager.float_type){
1272 // float to double, decimal
1274 if (target_type == TypeManager.double_type)
1276 } else if (expr_type == TypeManager.double_type){
1278 if ((target_type == TypeManager.bool_type))
1282 if (ImplicitReferenceConversionExists (expr, expr_type, target_type))
1285 if (expr is IntConstant){
1286 int value = ((IntConstant) expr).Value;
1288 if (target_type == TypeManager.sbyte_type){
1289 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1291 } else if (target_type == TypeManager.byte_type){
1292 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1294 } else if (target_type == TypeManager.short_type){
1295 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1297 } else if (target_type == TypeManager.ushort_type){
1298 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1300 } else if (target_type == TypeManager.uint32_type){
1303 } else if (target_type == TypeManager.uint64_type){
1305 // we can optimize this case: a positive int32
1306 // always fits on a uint64. But we need an opcode
1313 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
1317 if (expr is LongConstant && target_type == TypeManager.uint64_type){
1319 // Try the implicit constant expression conversion
1320 // from long to ulong, instead of a nice routine,
1321 // we just inline it
1323 long v = ((LongConstant) expr).Value;
1328 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1329 IntLiteral i = (IntLiteral) expr;
1335 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
1342 // Used internally by FindMostEncompassedType, this is used
1343 // to avoid creating lots of objects in the tight loop inside
1344 // FindMostEncompassedType
1346 static EmptyExpression priv_fmet_param;
1349 /// Finds "most encompassed type" according to the spec (13.4.2)
1350 /// amongst the methods in the MethodGroupExpr
1352 static Type FindMostEncompassedType (ArrayList types)
1356 if (priv_fmet_param == null)
1357 priv_fmet_param = new EmptyExpression ();
1359 foreach (Type t in types){
1360 priv_fmet_param.SetType (t);
1367 if (StandardConversionExists (priv_fmet_param, best))
1375 // Used internally by FindMostEncompassingType, this is used
1376 // to avoid creating lots of objects in the tight loop inside
1377 // FindMostEncompassingType
1379 static EmptyExpression priv_fmee_ret;
1382 /// Finds "most encompassing type" according to the spec (13.4.2)
1383 /// amongst the types in the given set
1385 static Type FindMostEncompassingType (ArrayList types)
1389 if (priv_fmee_ret == null)
1390 priv_fmee_ret = new EmptyExpression ();
1392 foreach (Type t in types){
1393 priv_fmee_ret.SetType (best);
1400 if (StandardConversionExists (priv_fmee_ret, t))
1408 // Used to avoid creating too many objects
1410 static EmptyExpression priv_fms_expr;
1413 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
1414 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
1415 /// for explicit and implicit conversion operators.
1417 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
1418 bool apply_explicit_conv_rules,
1421 ArrayList src_types_set = new ArrayList ();
1423 if (priv_fms_expr == null)
1424 priv_fms_expr = new EmptyExpression ();
1427 // If any operator converts from S then Sx = S
1429 Type source_type= source.Type;
1430 foreach (MethodBase mb in me.Methods){
1431 ParameterData pd = Invocation.GetParameterData (mb);
1432 Type param_type = pd.ParameterType (0);
1434 if (param_type == source_type)
1437 if (apply_explicit_conv_rules) {
1440 // Find the set of applicable user-defined conversion operators, U. This set
1442 // user-defined implicit or explicit conversion operators declared by
1443 // the classes or structs in D that convert from a type encompassing
1444 // or encompassed by S to a type encompassing or encompassed by T
1446 priv_fms_expr.SetType (param_type);
1447 if (StandardConversionExists (priv_fms_expr, source_type))
1448 src_types_set.Add (param_type);
1450 if (StandardConversionExists (source, param_type))
1451 src_types_set.Add (param_type);
1455 // Only if S is encompassed by param_type
1457 if (StandardConversionExists (source, param_type))
1458 src_types_set.Add (param_type);
1463 // Explicit Conv rules
1465 if (apply_explicit_conv_rules) {
1466 ArrayList candidate_set = new ArrayList ();
1468 foreach (Type param_type in src_types_set){
1469 if (StandardConversionExists (source, param_type))
1470 candidate_set.Add (param_type);
1473 if (candidate_set.Count != 0)
1474 return FindMostEncompassedType (candidate_set);
1480 if (apply_explicit_conv_rules)
1481 return FindMostEncompassingType (src_types_set);
1483 return FindMostEncompassedType (src_types_set);
1487 // Useful in avoiding proliferation of objects
1489 static EmptyExpression priv_fmt_expr;
1492 /// Finds the most specific target Tx according to section 13.4.4
1494 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
1495 bool apply_explicit_conv_rules,
1498 ArrayList tgt_types_set = new ArrayList ();
1500 if (priv_fmt_expr == null)
1501 priv_fmt_expr = new EmptyExpression ();
1504 // If any operator converts to T then Tx = T
1506 foreach (MethodInfo mi in me.Methods){
1507 Type ret_type = mi.ReturnType;
1509 if (ret_type == target)
1512 if (apply_explicit_conv_rules) {
1515 // Find the set of applicable user-defined conversion operators, U.
1517 // This set consists of the
1518 // user-defined implicit or explicit conversion operators declared by
1519 // the classes or structs in D that convert from a type encompassing
1520 // or encompassed by S to a type encompassing or encompassed by T
1522 priv_fms_expr.SetType (ret_type);
1523 if (StandardConversionExists (priv_fms_expr, target))
1524 tgt_types_set.Add (ret_type);
1526 priv_fms_expr.SetType (target);
1527 if (StandardConversionExists (priv_fms_expr, ret_type))
1528 tgt_types_set.Add (ret_type);
1532 // Only if T is encompassed by param_type
1534 priv_fms_expr.SetType (ret_type);
1535 if (StandardConversionExists (priv_fms_expr, target))
1536 tgt_types_set.Add (ret_type);
1541 // Explicit conv rules
1543 if (apply_explicit_conv_rules) {
1544 ArrayList candidate_set = new ArrayList ();
1546 foreach (Type ret_type in tgt_types_set){
1547 priv_fmt_expr.SetType (ret_type);
1549 if (StandardConversionExists (priv_fmt_expr, target))
1550 candidate_set.Add (ret_type);
1553 if (candidate_set.Count != 0)
1554 return FindMostEncompassingType (candidate_set);
1558 // Okay, final case !
1560 if (apply_explicit_conv_rules)
1561 return FindMostEncompassedType (tgt_types_set);
1563 return FindMostEncompassingType (tgt_types_set);
1567 /// User-defined Implicit conversions
1569 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1570 Type target, Location loc)
1572 return UserDefinedConversion (ec, source, target, loc, false);
1576 /// User-defined Explicit conversions
1578 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1579 Type target, Location loc)
1581 return UserDefinedConversion (ec, source, target, loc, true);
1585 /// Computes the MethodGroup for the user-defined conversion
1586 /// operators from source_type to target_type. 'look_for_explicit'
1587 /// controls whether we should also include the list of explicit
1590 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1591 Type source_type, Type target_type,
1592 Location loc, bool look_for_explicit)
1594 Expression mg1 = null, mg2 = null;
1595 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1599 // FIXME : How does the False operator come into the picture ?
1600 // This doesn't look complete and very correct !
1602 if (target_type == TypeManager.bool_type && !look_for_explicit)
1603 op_name = "op_True";
1605 op_name = "op_Implicit";
1607 MethodGroupExpr union3;
1609 mg1 = MethodLookup (ec, source_type, op_name, loc);
1610 if (source_type.BaseType != null)
1611 mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1614 union3 = (MethodGroupExpr) mg2;
1615 else if (mg2 == null)
1616 union3 = (MethodGroupExpr) mg1;
1618 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1620 mg1 = MethodLookup (ec, target_type, op_name, loc);
1623 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1625 union3 = (MethodGroupExpr) mg1;
1628 if (target_type.BaseType != null)
1629 mg1 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1633 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1635 union3 = (MethodGroupExpr) mg1;
1638 MethodGroupExpr union4 = null;
1640 if (look_for_explicit) {
1641 op_name = "op_Explicit";
1643 mg5 = MemberLookup (ec, source_type, op_name, loc);
1644 if (source_type.BaseType != null)
1645 mg6 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1647 mg7 = MemberLookup (ec, target_type, op_name, loc);
1648 if (target_type.BaseType != null)
1649 mg8 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1651 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1652 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1654 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1657 return Invocation.MakeUnionSet (union3, union4, loc);
1661 /// User-defined conversions
1663 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1664 Type target, Location loc,
1665 bool look_for_explicit)
1667 MethodGroupExpr union;
1668 Type source_type = source.Type;
1669 MethodBase method = null;
1671 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1675 Type most_specific_source, most_specific_target;
1678 foreach (MethodBase m in union.Methods){
1679 Console.WriteLine ("Name: " + m.Name);
1680 Console.WriteLine (" : " + ((MethodInfo)m).ReturnType);
1684 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
1685 if (most_specific_source == null)
1688 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
1689 if (most_specific_target == null)
1694 foreach (MethodBase mb in union.Methods){
1695 ParameterData pd = Invocation.GetParameterData (mb);
1696 MethodInfo mi = (MethodInfo) mb;
1698 if (pd.ParameterType (0) == most_specific_source &&
1699 mi.ReturnType == most_specific_target) {
1705 if (method == null || count > 1)
1710 // This will do the conversion to the best match that we
1711 // found. Now we need to perform an implict standard conversion
1712 // if the best match was not the type that we were requested
1715 if (look_for_explicit)
1716 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1718 source = ConvertImplicitStandard (ec, source, most_specific_source, loc);
1724 e = new UserCast ((MethodInfo) method, source, loc);
1725 if (e.Type != target){
1726 if (!look_for_explicit)
1727 e = ConvertImplicitStandard (ec, e, target, loc);
1729 e = ConvertExplicitStandard (ec, e, target, loc);
1735 /// Converts implicitly the resolved expression 'expr' into the
1736 /// 'target_type'. It returns a new expression that can be used
1737 /// in a context that expects a 'target_type'.
1739 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1740 Type target_type, Location loc)
1742 Type expr_type = expr.Type;
1746 if (expr_type == target_type)
1749 if (target_type == null)
1750 throw new Exception ("Target type is null");
1752 e = ConvertImplicitStandard (ec, expr, target_type, loc);
1756 e = ImplicitUserConversion (ec, expr, target_type, loc);
1761 e = NarrowingConversion (ec, expr, target_type, loc);
1769 /// Converts the resolved expression 'expr' into the
1770 /// 'target_type' using the Microsoft.VisualBasic runtime.
1771 /// It returns a new expression that can be used
1772 /// in a context that expects a 'target_type'.
1774 static private Expression RTConversionExpression (EmitContext ec, string s, Expression expr, Location loc)
1780 etmp = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices." + s, loc);
1781 args = new ArrayList();
1782 arg = new Argument (expr, Argument.AType.Expression);
1784 e = (Expression) new Invocation (etmp, args, loc);
1789 static private Expression RTConversionExpression (EmitContext ec, string ns, string method, Expression expr, Location loc)
1795 etmp = Mono.MonoBASIC.Parser.DecomposeQI(ns+method, loc);
1796 args = new ArrayList();
1797 arg = new Argument (expr, Argument.AType.Expression);
1799 e = (Expression) new Invocation (etmp, args, loc);
1805 static public bool NarrowingConversionExists (EmitContext ec, Expression expr, Type target_type)
1807 Type expr_type = expr.Type;
1809 if (target_type == TypeManager.sbyte_type){
1811 // To sbyte from short, int, long, float, double.
1813 if ((expr_type == TypeManager.int32_type) ||
1814 (expr_type == TypeManager.int64_type) ||
1815 (expr_type == TypeManager.double_type) ||
1816 (expr_type == TypeManager.float_type) ||
1817 (expr_type == TypeManager.short_type) ||
1818 (expr_type == TypeManager.decimal_type))
1821 } else if (target_type == TypeManager.byte_type){
1823 // To byte from short, ushort, int, uint, long, ulong, float, double
1825 if ((expr_type == TypeManager.short_type) ||
1826 (expr_type == TypeManager.ushort_type) ||
1827 (expr_type == TypeManager.int32_type) ||
1828 (expr_type == TypeManager.uint32_type) ||
1829 (expr_type == TypeManager.uint64_type) ||
1830 (expr_type == TypeManager.int64_type) ||
1831 (expr_type == TypeManager.float_type) ||
1832 (expr_type == TypeManager.double_type) ||
1833 (expr_type == TypeManager.decimal_type))
1836 } else if (target_type == TypeManager.short_type){
1838 // To short from int, long, float, double
1840 if ((expr_type == TypeManager.int32_type) ||
1841 (expr_type == TypeManager.int64_type) ||
1842 (expr_type == TypeManager.double_type) ||
1843 (expr_type == TypeManager.float_type) ||
1844 (expr_type == TypeManager.decimal_type))
1847 } else if (target_type == TypeManager.ushort_type){
1849 // To ushort from int, uint, long, ulong, float, double
1851 if ((expr_type == TypeManager.uint32_type) ||
1852 (expr_type == TypeManager.uint64_type) ||
1853 (expr_type == TypeManager.int32_type) ||
1854 (expr_type == TypeManager.int64_type) ||
1855 (expr_type == TypeManager.double_type) ||
1856 (expr_type == TypeManager.float_type) ||
1857 (expr_type == TypeManager.decimal_type))
1860 } else if (target_type == TypeManager.int32_type){
1862 // To int from long, float, double
1864 if ((expr_type == TypeManager.int64_type) ||
1865 (expr_type == TypeManager.double_type) ||
1866 (expr_type == TypeManager.float_type) ||
1867 (expr_type == TypeManager.decimal_type))
1870 } else if (target_type == TypeManager.uint32_type){
1872 // To uint from long, ulong, float, double
1874 if ((expr_type == TypeManager.int64_type) ||
1875 (expr_type == TypeManager.uint64_type) ||
1876 (expr_type == TypeManager.double_type) ||
1877 (expr_type == TypeManager.float_type) ||
1878 (expr_type == TypeManager.decimal_type))
1881 } else if ((target_type == TypeManager.uint64_type) ||
1882 (target_type == TypeManager.int64_type)) {
1884 // To long/ulong from float, double
1886 if ((expr_type == TypeManager.double_type) ||
1887 (expr_type == TypeManager.float_type) ||
1888 (expr_type == TypeManager.decimal_type))
1891 } else if (target_type == TypeManager.char_type){
1893 // To char from ushort, int, uint, long, ulong, float, double, decimal,string
1895 if ((expr_type == TypeManager.ushort_type) ||
1896 (expr_type == TypeManager.int32_type) ||
1897 (expr_type == TypeManager.uint32_type) ||
1898 (expr_type == TypeManager.uint64_type) ||
1899 (expr_type == TypeManager.int64_type) ||
1900 (expr_type == TypeManager.float_type) ||
1901 (expr_type == TypeManager.double_type) ||
1902 (expr_type == TypeManager.decimal_type) ||
1903 (expr_type == TypeManager.string_type))
1907 } else if (target_type == TypeManager.float_type){
1909 // To float from double
1911 if (expr_type == TypeManager.double_type)
1915 return (NarrowingConversion (ec, expr, target_type,Location.Null)) != null;
1918 static public Expression NarrowingConversion (EmitContext ec, Expression expr,
1919 Type target_type, Location loc)
1921 Type expr_type = expr.Type;
1923 if (target_type == TypeManager.sbyte_type){
1925 // To sbyte from short, int, long, float, double.
1927 if (expr_type == TypeManager.int32_type)
1928 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1929 if (expr_type == TypeManager.int64_type)
1930 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1931 if (expr_type == TypeManager.short_type)
1932 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1934 if (expr_type == TypeManager.float_type) {
1935 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1936 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
1938 if (expr_type == TypeManager.double_type) {
1939 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1940 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
1943 } else if (target_type == TypeManager.byte_type){
1945 // To byte from short, ushort, int, uint, long, ulong, float, double
1947 if (expr_type == TypeManager.short_type)
1948 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1949 if (expr_type == TypeManager.ushort_type)
1950 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1951 if (expr_type == TypeManager.int32_type)
1952 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1953 if (expr_type == TypeManager.uint32_type)
1954 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1955 if (expr_type == TypeManager.uint64_type)
1956 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1957 if (expr_type == TypeManager.int64_type)
1958 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1960 if (expr_type == TypeManager.float_type) {
1961 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1962 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
1964 if (expr_type == TypeManager.double_type) {
1965 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1966 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
1969 } else if (target_type == TypeManager.short_type) {
1971 // To short from int, long, float, double
1973 if (expr_type == TypeManager.int32_type)
1974 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1975 if (expr_type == TypeManager.int64_type)
1976 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1978 if (expr_type == TypeManager.float_type) {
1979 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1980 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
1982 if (expr_type == TypeManager.double_type) {
1983 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1984 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
1987 } else if (target_type == TypeManager.ushort_type) {
1989 // To ushort from int, uint, long, ulong, float, double
1991 if (expr_type == TypeManager.uint32_type)
1992 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1993 if (expr_type == TypeManager.uint64_type)
1994 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1995 if (expr_type == TypeManager.int32_type)
1996 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1997 if (expr_type == TypeManager.int64_type)
1998 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2000 if (expr_type == TypeManager.float_type) {
2001 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2002 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2005 if (expr_type == TypeManager.double_type) {
2006 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2007 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
2010 } else if (target_type == TypeManager.int32_type){
2012 // To int from long, float, double
2014 if (expr_type == TypeManager.int64_type)
2015 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2017 if (expr_type == TypeManager.float_type) {
2018 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2019 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2021 if (expr_type == TypeManager.double_type) {
2022 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2023 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2026 } else if (target_type == TypeManager.uint32_type){
2028 // To uint from long, ulong, float, double
2030 if (expr_type == TypeManager.int64_type)
2031 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2032 if (expr_type == TypeManager.uint64_type)
2033 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2034 if (expr_type == TypeManager.float_type) {
2035 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2036 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2038 if (expr_type == TypeManager.double_type) {
2039 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2040 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2043 } else if (target_type == TypeManager.uint64_type) {
2045 // To long/ulong from float, double
2047 if (expr_type == TypeManager.float_type) {
2048 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2049 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2051 if (expr_type == TypeManager.double_type) {
2052 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2053 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2056 } else if (target_type == TypeManager.int64_type) {
2058 // To long/ulong from float, double
2060 if (expr_type == TypeManager.float_type) {
2061 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2062 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2064 if (expr_type == TypeManager.double_type) {
2065 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2066 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2069 } else if (target_type == TypeManager.char_type){
2071 // To char from ushort, int, uint, long, ulong, float, double
2073 if (expr_type == TypeManager.ushort_type)
2074 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
2075 if (expr_type == TypeManager.int32_type)
2076 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
2077 if (expr_type == TypeManager.uint32_type)
2078 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
2079 if (expr_type == TypeManager.uint64_type)
2080 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
2081 if (expr_type == TypeManager.int64_type)
2082 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
2084 if (expr_type == TypeManager.float_type) {
2085 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2086 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_CH);
2088 if (expr_type == TypeManager.double_type) {
2089 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2090 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_CH);
2093 } else if (target_type == TypeManager.float_type){
2095 // To float from double
2097 if (expr_type == TypeManager.double_type)
2098 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2101 TypeCode dest_type = Type.GetTypeCode (target_type);
2102 TypeCode src_type = Type.GetTypeCode (expr_type);
2103 Expression e = null;
2105 switch (dest_type) {
2106 case TypeCode.String:
2108 case TypeCode.SByte:
2110 e = RTConversionExpression(ec, "StringType.FromByte", expr, loc);
2112 case TypeCode.UInt16:
2113 case TypeCode.Int16:
2114 e = RTConversionExpression(ec, "StringType.FromShort", expr, loc);
2116 case TypeCode.UInt32:
2117 case TypeCode.Int32:
2118 e = RTConversionExpression(ec, "StringType.FromInteger", expr, loc);
2120 case TypeCode.UInt64:
2121 case TypeCode.Int64:
2122 e = RTConversionExpression(ec, "StringType.FromLong", expr, loc);
2125 e = RTConversionExpression(ec, "StringType.FromChar", expr, loc);
2127 case TypeCode.Single:
2128 e = RTConversionExpression(ec, "StringType.FromSingle", expr, loc);
2130 case TypeCode.Double:
2131 e = RTConversionExpression(ec, "StringType.FromDouble", expr, loc);
2133 case TypeCode.Boolean:
2134 e = RTConversionExpression(ec, "StringType.FromBoolean", expr, loc);
2136 case TypeCode.DateTime:
2137 e = RTConversionExpression(ec, "StringType.FromDate", expr, loc);
2139 case TypeCode.Decimal:
2140 e = RTConversionExpression(ec, "StringType.FromDecimal", expr, loc);
2142 case TypeCode.Object:
2143 e = RTConversionExpression(ec, "StringType.FromObject", expr, loc);
2148 case TypeCode.Int32:
2149 case TypeCode.UInt32:
2151 case TypeCode.String:
2152 e = RTConversionExpression(ec, "IntegerType.FromString", expr, loc);
2154 case TypeCode.Object:
2155 e = RTConversionExpression(ec, "IntegerType.FromObject", expr, loc);
2160 case TypeCode.Int16:
2161 case TypeCode.UInt16:
2163 case TypeCode.String:
2164 e = RTConversionExpression(ec, "ShortType.FromString", expr, loc);
2166 case TypeCode.Object:
2167 e = RTConversionExpression(ec, "ShortType.FromObject", expr, loc);
2172 // Ok, this *is* broken
2173 e = RTConversionExpression(ec, "ByteType.FromObject", expr, loc);
2175 case TypeCode.DateTime:
2177 case TypeCode.String:
2178 e = RTConversionExpression(ec, "DateType.FromString", expr, loc);
2180 case TypeCode.Object:
2181 e = RTConversionExpression(ec, "DateType.FromObject", expr, loc);
2188 case TypeCode.String:
2189 e = RTConversionExpression(ec, "CharType.FromString", expr, loc);
2196 // We must examine separately some types that
2197 // don't have a TypeCode but are supported
2199 if (expr_type == typeof(System.String) && target_type == typeof (System.Char[])) {
2200 e = RTConversionExpression(ec, "CharArrayType.FromString", expr, loc);
2204 // VB.NET Objects can be converted to anything by default
2205 // unless, that is, an exception at runtime blows it all
2206 if (src_type == TypeCode.Object) {
2207 Expression cast_type = Mono.MonoBASIC.Parser.DecomposeQI(target_type.ToString(), loc);
2208 Cast ce = new Cast (cast_type, expr, loc);
2209 ce.IsRuntimeCast = true;
2210 return ce.Resolve (ec);
2215 static public Expression ConvertNothingToDefaultValues (EmitContext ec, Expression expr,
2216 Type target_type, Location loc)
2218 switch (Type.GetTypeCode (target_type)) {
2219 case TypeCode.Boolean :
2220 return new BoolConstant (false);
2221 case TypeCode.Byte :
2222 return new ByteConstant (0);
2223 case TypeCode.Char :
2224 return new CharConstant ((char)0);
2225 case TypeCode.SByte :
2226 return new SByteConstant (0);
2227 case TypeCode.Int16 :
2228 return new ShortConstant (0);
2229 case TypeCode.Int32 :
2230 return new IntConstant (0);
2231 case TypeCode.Int64 :
2232 return new LongConstant (0);
2233 case TypeCode.Decimal :
2234 return new DecimalConstant (System.Decimal.Zero);
2235 case TypeCode.Single :
2236 return new FloatConstant (0.0F);
2237 case TypeCode.Double :
2238 return new DoubleConstant (0.0);
2245 /// Attempts to apply the 'Standard Implicit
2246 /// Conversion' rules to the expression 'expr' into
2247 /// the 'target_type'. It returns a new expression
2248 /// that can be used in a context that expects a
2251 /// This is different from 'ConvertImplicit' in that the
2252 /// user defined implicit conversions are excluded.
2254 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
2255 Type target_type, Location loc)
2257 Type expr_type = expr.Type;
2260 if (expr is NullLiteral) {
2261 if (target_type == TypeManager.string_type)
2263 e = ConvertNothingToDefaultValues (ec, expr, target_type, loc);
2268 if (expr_type == target_type)
2271 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2276 e = ImplicitReferenceConversion (expr, target_type);
2280 if (expr.Type.IsSubclassOf (TypeManager.enum_type)) {
2281 expr_type = TypeManager.EnumToUnderlying (expr.Type);
2282 expr = new EmptyCast (expr, expr_type);
2283 if (expr_type == target_type)
2285 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2291 if (expr_type.IsPointer){
2292 if (target_type == TypeManager.void_ptr_type)
2293 return new EmptyCast (expr, target_type);
2296 // yep, comparing pointer types cant be done with
2297 // t1 == t2, we have to compare their element types.
2299 if (target_type.IsPointer){
2300 if (target_type.GetElementType()==expr_type.GetElementType())
2305 if (target_type.IsPointer){
2306 if (expr is NullLiteral)
2307 return new EmptyCast (expr, target_type);
2315 /// Attemps to perform an implict constant conversion of the any Numeric Constant
2316 /// into a different data type using casts (See Implicit Constant
2317 /// Expression Conversions)
2319 static protected Expression TryImplicitNumericConversion (Type target_type, Constant ic)
2322 if (ic is BoolConstant) {
2323 bool val = (bool) ((BoolConstant)ic).Value;
2325 if (target_type == TypeManager.byte_type)
2326 value = Byte.MaxValue;
2331 if (ic is IntConstant)
2332 value = (double)((IntConstant)ic).Value;
2334 if (ic is LongConstant)
2335 value = (double) ((LongConstant)ic).Value;
2337 if (ic is FloatConstant) {
2338 value = (double) ((FloatConstant)ic).Value;
2341 if (ic is DoubleConstant) {
2342 value = ((DoubleConstant)ic).Value;
2346 // FIXME: This could return constants instead of EmptyCasts
2348 if (target_type == TypeManager.bool_type){
2350 return new BoolConstant (true);
2351 return new BoolConstant (false);
2352 } else if (target_type == TypeManager.sbyte_type){
2353 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2354 return new SByteConstant ((sbyte) System.Math.Round (value));
2355 } else if (target_type == TypeManager.byte_type){
2356 if (value >= Byte.MinValue && value <= Byte.MaxValue)
2357 return new ByteConstant ((byte) System.Math.Round (value));
2358 } else if (target_type == TypeManager.short_type){
2359 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2360 return new ShortConstant ((short) System.Math.Round (value));
2361 } else if (target_type == TypeManager.ushort_type){
2362 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2363 return new UShortConstant ((ushort) System.Math.Round (value));
2364 } else if (target_type == TypeManager.int32_type){
2365 if (value >= Int32.MinValue && value <= Int32.MaxValue)
2366 return new IntConstant ((int) System.Math.Round (value));
2367 } else if (target_type == TypeManager.uint32_type){
2369 return new UIntConstant ((uint) System.Math.Round (value));
2370 } else if (target_type == TypeManager.int64_type){
2371 return new LongConstant ((long) System.Math.Round (value));
2372 } else if (target_type == TypeManager.uint64_type){
2374 // we can optimize this case: a positive int32
2375 // always fits on a uint64. But we need an opcode
2379 return new ULongConstant ((ulong)System.Math.Round ( value));
2380 } else if (target_type == TypeManager.float_type){
2381 return new FloatConstant ((float) value);
2382 } else if (target_type == TypeManager.double_type){
2383 return new DoubleConstant ((double) value);
2386 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
2387 Type underlying = TypeManager.EnumToUnderlying (target_type);
2388 Constant e = (Constant) ic;
2391 // Possibly, we need to create a different 0 literal before passing
2394 if (underlying == TypeManager.int64_type)
2395 e = new LongLiteral (0);
2396 else if (underlying == TypeManager.uint64_type)
2397 e = new ULongLiteral (0);
2399 return new EnumConstant (e, target_type);
2404 static public void Error_CannotConvertImplicit (Location loc, Type source, Type target)
2406 string msg = "Cannot convert implicitly from '"+
2407 TypeManager.MonoBASIC_Name (source) + "' to '" +
2408 TypeManager.MonoBASIC_Name (target) + "'";
2410 throw new Exception (msg);
2412 // Report.Error (30512, loc, msg);
2416 /// Attemptes to implicityly convert 'target' into 'type', using
2417 /// ConvertImplicit. If there is no implicit conversion, then
2418 /// an error is signaled
2420 static public Expression ConvertImplicitRequired (EmitContext ec, Expression source,
2421 Type target_type, Location loc)
2425 e = ConvertImplicit (ec, source, target_type, loc);
2431 if (source is DoubleLiteral && target_type == TypeManager.float_type){
2432 Report.Error (664, loc,
2433 "Double literal cannot be implicitly converted to " +
2434 "float type, use F suffix to create a float literal");
2437 Error_CannotConvertImplicit (loc, source.Type, target_type);
2443 /// Performs the explicit numeric conversions
2445 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc)
2447 Type expr_type = expr.Type;
2450 // If we have an enumeration, extract the underlying type,
2451 // use this during the comparison, but wrap around the original
2454 Type real_target_type = target_type;
2456 if (TypeManager.IsEnumType (real_target_type))
2457 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
2459 if (StandardConversionExists (expr, real_target_type)){
2460 Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc);
2462 if (real_target_type != target_type)
2463 return new EmptyCast (ce, target_type);
2467 if (expr_type == TypeManager.sbyte_type){
2469 // From sbyte to byte, ushort, uint, ulong, char
2471 if (real_target_type == TypeManager.byte_type)
2472 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
2473 if (real_target_type == TypeManager.ushort_type)
2474 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
2475 if (real_target_type == TypeManager.uint32_type)
2476 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
2477 if (real_target_type == TypeManager.uint64_type)
2478 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
2479 if (real_target_type == TypeManager.char_type)
2480 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
2481 } else if (expr_type == TypeManager.byte_type){
2483 // From byte to sbyte and char
2485 if (real_target_type == TypeManager.sbyte_type)
2486 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
2487 if (real_target_type == TypeManager.char_type)
2488 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
2489 } else if (expr_type == TypeManager.short_type){
2491 // From short to sbyte, byte, ushort, uint, ulong, char
2493 if (real_target_type == TypeManager.sbyte_type)
2494 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
2495 if (real_target_type == TypeManager.byte_type)
2496 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
2497 if (real_target_type == TypeManager.ushort_type)
2498 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
2499 if (real_target_type == TypeManager.uint32_type)
2500 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
2501 if (real_target_type == TypeManager.uint64_type)
2502 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
2503 if (real_target_type == TypeManager.char_type)
2504 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
2505 } else if (expr_type == TypeManager.ushort_type){
2507 // From ushort to sbyte, byte, short, char
2509 if (real_target_type == TypeManager.sbyte_type)
2510 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
2511 if (real_target_type == TypeManager.byte_type)
2512 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
2513 if (real_target_type == TypeManager.short_type)
2514 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
2515 if (real_target_type == TypeManager.char_type)
2516 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
2517 } else if (expr_type == TypeManager.int32_type){
2519 // From int to sbyte, byte, short, ushort, uint, ulong, char
2521 if (real_target_type == TypeManager.sbyte_type)
2522 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
2523 if (real_target_type == TypeManager.byte_type)
2524 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
2525 if (real_target_type == TypeManager.short_type)
2526 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
2527 if (real_target_type == TypeManager.ushort_type)
2528 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
2529 if (real_target_type == TypeManager.uint32_type)
2530 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
2531 if (real_target_type == TypeManager.uint64_type)
2532 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
2533 if (real_target_type == TypeManager.char_type)
2534 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
2535 } else if (expr_type == TypeManager.uint32_type){
2537 // From uint to sbyte, byte, short, ushort, int, char
2539 if (real_target_type == TypeManager.sbyte_type)
2540 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
2541 if (real_target_type == TypeManager.byte_type)
2542 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
2543 if (real_target_type == TypeManager.short_type)
2544 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
2545 if (real_target_type == TypeManager.ushort_type)
2546 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
2547 if (real_target_type == TypeManager.int32_type)
2548 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
2549 if (real_target_type == TypeManager.char_type)
2550 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
2551 } else if (expr_type == TypeManager.int64_type){
2553 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
2555 if (real_target_type == TypeManager.sbyte_type)
2556 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
2557 if (real_target_type == TypeManager.byte_type)
2558 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
2559 if (real_target_type == TypeManager.short_type)
2560 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
2561 if (real_target_type == TypeManager.ushort_type)
2562 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2563 if (real_target_type == TypeManager.int32_type)
2564 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2565 if (real_target_type == TypeManager.uint32_type)
2566 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2567 if (real_target_type == TypeManager.uint64_type)
2568 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
2569 if (real_target_type == TypeManager.char_type)
2570 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
2571 } else if (expr_type == TypeManager.uint64_type){
2573 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
2575 if (real_target_type == TypeManager.sbyte_type)
2576 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
2577 if (real_target_type == TypeManager.byte_type)
2578 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
2579 if (real_target_type == TypeManager.short_type)
2580 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
2581 if (real_target_type == TypeManager.ushort_type)
2582 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
2583 if (real_target_type == TypeManager.int32_type)
2584 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2585 if (real_target_type == TypeManager.uint32_type)
2586 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
2587 if (real_target_type == TypeManager.int64_type)
2588 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
2589 if (real_target_type == TypeManager.char_type)
2590 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
2591 } else if (expr_type == TypeManager.char_type){
2593 // From char to sbyte, byte, short
2595 if (real_target_type == TypeManager.sbyte_type)
2596 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
2597 if (real_target_type == TypeManager.byte_type)
2598 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
2599 if (real_target_type == TypeManager.short_type)
2600 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
2601 } else if (expr_type == TypeManager.float_type){
2603 // From float to sbyte, byte, short,
2604 // ushort, int, uint, long, ulong, char
2607 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2608 if (real_target_type == TypeManager.sbyte_type)
2609 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
2610 if (real_target_type == TypeManager.byte_type)
2611 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
2612 if (real_target_type == TypeManager.short_type)
2613 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
2614 if (real_target_type == TypeManager.ushort_type)
2615 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2616 if (real_target_type == TypeManager.int32_type)
2617 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2618 if (real_target_type == TypeManager.uint32_type)
2619 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2620 if (real_target_type == TypeManager.int64_type)
2621 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2622 if (real_target_type == TypeManager.uint64_type)
2623 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2624 if (real_target_type == TypeManager.char_type)
2625 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_CH);
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.char_type)
2650 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_CH);
2651 if (real_target_type == TypeManager.float_type)
2652 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_R4);
2655 // decimal is taken care of by the op_Explicit methods.
2661 /// Returns whether an explicit reference conversion can be performed
2662 /// from source_type to target_type
2664 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
2666 bool target_is_value_type = target_type.IsValueType;
2668 if (source_type == target_type)
2672 // From object to any reference type
2674 if (source_type == TypeManager.object_type && !target_is_value_type)
2678 // From any class S to any class-type T, provided S is a base class of T
2680 if (target_type.IsSubclassOf (source_type))
2684 // From any interface type S to any interface T provided S is not derived from T
2686 if (source_type.IsInterface && target_type.IsInterface){
2687 if (!target_type.IsSubclassOf (source_type))
2692 // From any class type S to any interface T, provided S is not sealed
2693 // and provided S does not implement T.
2695 if (target_type.IsInterface && !source_type.IsSealed &&
2696 !TypeManager.ImplementsInterface (source_type, target_type))
2700 // From any interface-type S to to any class type T, provided T is not
2701 // sealed, or provided T implements S.
2703 if (source_type.IsInterface &&
2704 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
2708 // From an array type S with an element type Se to an array type T with an
2709 // element type Te provided all the following are true:
2710 // * S and T differe only in element type, in other words, S and T
2711 // have the same number of dimensions.
2712 // * Both Se and Te are reference types
2713 // * An explicit referenc conversions exist from Se to Te
2715 if (source_type.IsArray && target_type.IsArray) {
2716 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2718 Type source_element_type = source_type.GetElementType ();
2719 Type target_element_type = target_type.GetElementType ();
2721 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2722 if (ExplicitReferenceConversionExists (source_element_type,
2723 target_element_type))
2729 // From System.Array to any array-type
2730 if (source_type == TypeManager.array_type &&
2731 target_type.IsArray){
2736 // From System delegate to any delegate-type
2738 if (source_type == TypeManager.delegate_type &&
2739 target_type.IsSubclassOf (TypeManager.delegate_type))
2743 // From ICloneable to Array or Delegate types
2745 if (source_type == TypeManager.icloneable_type &&
2746 (target_type == TypeManager.array_type ||
2747 target_type == TypeManager.delegate_type))
2754 /// Implements Explicit Reference conversions
2756 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
2758 Type source_type = source.Type;
2759 bool target_is_value_type = target_type.IsValueType;
2762 // From object to any reference type
2764 if (source_type == TypeManager.object_type && !target_is_value_type)
2765 return new ClassCast (source, target_type);
2769 // From any class S to any class-type T, provided S is a base class of T
2771 if (target_type.IsSubclassOf (source_type))
2772 return new ClassCast (source, target_type);
2775 // From any interface type S to any interface T provided S is not derived from T
2777 if (source_type.IsInterface && target_type.IsInterface){
2778 if (TypeManager.ImplementsInterface (source_type, target_type))
2781 return new ClassCast (source, target_type);
2785 // From any class type S to any interface T, provides S is not sealed
2786 // and provided S does not implement T.
2788 if (target_type.IsInterface && !source_type.IsSealed) {
2789 if (TypeManager.ImplementsInterface (source_type, target_type))
2792 return new ClassCast (source, target_type);
2797 // From any interface-type S to to any class type T, provided T is not
2798 // sealed, or provided T implements S.
2800 if (source_type.IsInterface) {
2801 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type))
2802 return new ClassCast (source, target_type);
2807 // From an array type S with an element type Se to an array type T with an
2808 // element type Te provided all the following are true:
2809 // * S and T differe only in element type, in other words, S and T
2810 // have the same number of dimensions.
2811 // * Both Se and Te are reference types
2812 // * An explicit referenc conversions exist from Se to Te
2814 if (source_type.IsArray && target_type.IsArray) {
2815 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2817 Type source_element_type = source_type.GetElementType ();
2818 Type target_element_type = target_type.GetElementType ();
2820 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2821 if (ExplicitReferenceConversionExists (source_element_type,
2822 target_element_type))
2823 return new ClassCast (source, target_type);
2828 // From System.Array to any array-type
2829 if (source_type == TypeManager.array_type &&
2830 target_type.IsArray) {
2831 return new ClassCast (source, target_type);
2835 // From System delegate to any delegate-type
2837 if (source_type == TypeManager.delegate_type &&
2838 target_type.IsSubclassOf (TypeManager.delegate_type))
2839 return new ClassCast (source, target_type);
2842 // From ICloneable to Array or Delegate types
2844 if (source_type == TypeManager.icloneable_type &&
2845 (target_type == TypeManager.array_type ||
2846 target_type == TypeManager.delegate_type))
2847 return new ClassCast (source, target_type);
2853 /// Performs an explicit conversion of the expression 'expr' whose
2854 /// type is expr.Type to 'target_type'.
2856 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
2857 Type target_type, bool runtimeconv, Location loc)
2859 Type expr_type = expr.Type;
2860 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
2865 ne = ConvertNumericExplicit (ec, expr, target_type, loc);
2870 // Unboxing conversion.
2872 if (expr_type == TypeManager.object_type && target_type.IsValueType)
2873 return new UnboxCast (expr, target_type);
2878 if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
2882 // FIXME: Is there any reason we should have EnumConstant
2883 // dealt with here instead of just using always the
2884 // UnderlyingSystemType to wrap the type?
2886 if (expr is EnumConstant)
2887 e = ((EnumConstant) expr).Child;
2889 e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
2892 Expression t = ConvertImplicit (ec, e, target_type, loc);
2896 t = ConvertNumericExplicit (ec, e, target_type, loc);
2900 t = NarrowingConversion (ec, e, target_type, loc);
2904 Error_CannotConvertType (loc, expr_type, target_type);
2908 ne = ConvertReferenceExplicit (expr, target_type);
2913 if (target_type.IsPointer){
2914 if (expr_type.IsPointer)
2915 return new EmptyCast (expr, target_type);
2917 if (expr_type == TypeManager.sbyte_type ||
2918 expr_type == TypeManager.byte_type ||
2919 expr_type == TypeManager.short_type ||
2920 expr_type == TypeManager.ushort_type ||
2921 expr_type == TypeManager.int32_type ||
2922 expr_type == TypeManager.uint32_type ||
2923 expr_type == TypeManager.uint64_type ||
2924 expr_type == TypeManager.int64_type)
2925 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
2927 if (expr_type.IsPointer){
2928 if (target_type == TypeManager.sbyte_type ||
2929 target_type == TypeManager.byte_type ||
2930 target_type == TypeManager.short_type ||
2931 target_type == TypeManager.ushort_type ||
2932 target_type == TypeManager.int32_type ||
2933 target_type == TypeManager.uint32_type ||
2934 target_type == TypeManager.uint64_type ||
2935 target_type == TypeManager.int64_type){
2936 Expression e = new EmptyCast (expr, TypeManager.uint32_type);
2939 ci = ConvertImplicitStandard (ec, e, target_type, loc);
2944 ce = ConvertNumericExplicit (ec, e, target_type, loc);
2948 // We should always be able to go from an uint32
2949 // implicitly or explicitly to the other integral
2952 throw new Exception ("Internal compiler error");
2957 ne = ExplicitUserConversion (ec, expr, target_type, loc);
2961 if (!(runtimeconv)) {
2962 ne = NarrowingConversion (ec, expr, target_type, loc);
2966 Error_CannotConvertType (loc, expr_type, target_type);
2972 /// Same as ConvertExplicit, only it doesn't include user defined conversions
2974 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
2975 Type target_type, Location l)
2977 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
2982 ne = ConvertNumericExplicit (ec, expr, target_type, l);
2986 ne = ConvertReferenceExplicit (expr, target_type);
2990 ne = NarrowingConversion (ec, expr, target_type, l);
2994 Error_CannotConvertType (l, expr.Type, target_type);
2998 static string ExprClassName (ExprClass c)
3001 case ExprClass.Invalid:
3003 case ExprClass.Value:
3005 case ExprClass.Variable:
3007 case ExprClass.Namespace:
3009 case ExprClass.Type:
3011 case ExprClass.MethodGroup:
3012 return "method group";
3013 case ExprClass.PropertyAccess:
3014 return "property access";
3015 case ExprClass.EventAccess:
3016 return "event access";
3017 case ExprClass.IndexerAccess:
3018 return "indexer access";
3019 case ExprClass.Nothing:
3022 throw new Exception ("Should not happen");
3026 /// Reports that we were expecting 'expr' to be of class 'expected'
3028 public void Error118 (string expected)
3030 string kind = "Unknown";
3032 kind = ExprClassName (eclass);
3034 Error (118, "Expression denotes a '" + kind +
3035 "' where a '" + expected + "' was expected");
3038 public void Error118 (ResolveFlags flags)
3040 ArrayList valid = new ArrayList (10);
3042 if ((flags & ResolveFlags.VariableOrValue) != 0) {
3043 valid.Add ("variable");
3044 valid.Add ("value");
3047 if ((flags & ResolveFlags.Type) != 0)
3050 if ((flags & ResolveFlags.MethodGroup) != 0)
3051 valid.Add ("method group");
3053 if ((flags & ResolveFlags.SimpleName) != 0)
3054 valid.Add ("simple name");
3056 if (valid.Count == 0)
3057 valid.Add ("unknown");
3059 StringBuilder sb = new StringBuilder ();
3060 for (int i = 0; i < valid.Count; i++) {
3063 else if (i == valid.Count)
3065 sb.Append (valid [i]);
3068 string kind = ExprClassName (eclass);
3070 Error (119, "Expression denotes a '" + kind + "' where " +
3071 "a '" + sb.ToString () + "' was expected");
3074 static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t)
3076 Report.Error (31, l, "Constant value '" + val + "' cannot be converted to " +
3077 TypeManager.MonoBASIC_Name (t));
3080 public static void UnsafeError (Location loc)
3082 Report.Error (214, loc, "Pointers may only be used in an unsafe context");
3086 /// Converts the IntConstant, UIntConstant, LongConstant or
3087 /// ULongConstant,Double into the integral target_type. Notice
3088 /// that we do not return an 'Expression' we do return
3089 /// a boxed integral type.
3091 /// FIXME: Since I added the new constants, we need to
3092 /// also support conversions from CharConstant, ByteConstant,
3093 /// SByteConstant, UShortConstant, ShortConstant
3095 /// This is used by the switch statement, so the domain
3096 /// of work is restricted to the literals above, and the
3097 /// targets are int32, uint32, char, byte, sbyte, ushort,
3098 /// short, uint64 and int64
3100 public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
3104 if (c.Type == target_type)
3105 return ((Constant) c).GetValue ();
3108 // Make into one of the literals we handle, we dont really care
3109 // about this value as we will just return a few limited types
3111 if (c is EnumConstant)
3112 c = ((EnumConstant)c).WidenToCompilerConstant ();
3114 if (c is IntConstant){
3115 int v = ((IntConstant) c).Value;
3117 if (target_type == TypeManager.uint32_type){
3120 } else if (target_type == TypeManager.char_type){
3121 if (v >= Char.MinValue && v <= Char.MaxValue)
3123 } else if (target_type == TypeManager.byte_type){
3124 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3126 } else if (target_type == TypeManager.sbyte_type){
3127 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3129 } else if (target_type == TypeManager.short_type){
3130 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3132 } else if (target_type == TypeManager.ushort_type){
3133 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3135 } else if (target_type == TypeManager.int64_type)
3137 else if (target_type == TypeManager.uint64_type){
3143 } else if (c is UIntConstant){
3144 uint v = ((UIntConstant) c).Value;
3146 if (target_type == TypeManager.int32_type){
3147 if (v <= Int32.MaxValue)
3149 } else if (target_type == TypeManager.char_type){
3150 if (v >= Char.MinValue && v <= Char.MaxValue)
3152 } else if (target_type == TypeManager.byte_type){
3153 if (v <= Byte.MaxValue)
3155 } else if (target_type == TypeManager.sbyte_type){
3156 if (v <= SByte.MaxValue)
3158 } else if (target_type == TypeManager.short_type){
3159 if (v <= UInt16.MaxValue)
3161 } else if (target_type == TypeManager.ushort_type){
3162 if (v <= UInt16.MaxValue)
3164 } else if (target_type == TypeManager.int64_type)
3166 else if (target_type == TypeManager.uint64_type)
3169 } else if (c is LongConstant){
3170 long v = ((LongConstant) c).Value;
3172 if (target_type == TypeManager.int32_type){
3173 if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
3175 } else if (target_type == TypeManager.uint32_type){
3176 if (v >= 0 && v <= UInt32.MaxValue)
3178 } else if (target_type == TypeManager.char_type){
3179 if (v >= Char.MinValue && v <= Char.MaxValue)
3181 } else if (target_type == TypeManager.byte_type){
3182 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3184 } else if (target_type == TypeManager.sbyte_type){
3185 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3187 } else if (target_type == TypeManager.short_type){
3188 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3190 } else if (target_type == TypeManager.ushort_type){
3191 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3193 } else if (target_type == TypeManager.uint64_type){
3198 } else if (c is ULongConstant){
3199 ulong v = ((ULongConstant) c).Value;
3201 if (target_type == TypeManager.int32_type){
3202 if (v <= Int32.MaxValue)
3204 } else if (target_type == TypeManager.uint32_type){
3205 if (v <= UInt32.MaxValue)
3207 } else if (target_type == TypeManager.char_type){
3208 if (v >= Char.MinValue && v <= Char.MaxValue)
3210 } else if (target_type == TypeManager.byte_type){
3211 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3213 } else if (target_type == TypeManager.sbyte_type){
3214 if (v <= (int) SByte.MaxValue)
3216 } else if (target_type == TypeManager.short_type){
3217 if (v <= UInt16.MaxValue)
3219 } else if (target_type == TypeManager.ushort_type){
3220 if (v <= UInt16.MaxValue)
3222 } else if (target_type == TypeManager.int64_type){
3223 if (v <= Int64.MaxValue)
3227 } else if (c is ByteConstant){
3228 byte v = ((ByteConstant) c).Value;
3230 if (target_type == TypeManager.int32_type)
3232 else if (target_type == TypeManager.uint32_type)
3234 else if (target_type == TypeManager.char_type)
3236 else if (target_type == TypeManager.sbyte_type){
3237 if (v <= SByte.MaxValue)
3239 } else if (target_type == TypeManager.short_type)
3241 else if (target_type == TypeManager.ushort_type)
3243 else if (target_type == TypeManager.int64_type)
3245 else if (target_type == TypeManager.uint64_type)
3248 } else if (c is SByteConstant){
3249 sbyte v = ((SByteConstant) c).Value;
3251 if (target_type == TypeManager.int32_type)
3253 else if (target_type == TypeManager.uint32_type){
3256 } else if (target_type == TypeManager.char_type){
3259 } else if (target_type == TypeManager.byte_type){
3262 } else if (target_type == TypeManager.short_type)
3264 else if (target_type == TypeManager.ushort_type){
3267 } else if (target_type == TypeManager.int64_type)
3269 else if (target_type == TypeManager.uint64_type){
3274 } else if (c is ShortConstant){
3275 short v = ((ShortConstant) c).Value;
3277 if (target_type == TypeManager.int32_type){
3279 } else if (target_type == TypeManager.uint32_type){
3282 } else if (target_type == TypeManager.char_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.MinValue && v <= SByte.MaxValue)
3291 } else if (target_type == TypeManager.ushort_type){
3294 } else if (target_type == TypeManager.int64_type)
3296 else if (target_type == TypeManager.uint64_type)
3300 } else if (c is UShortConstant){
3301 ushort v = ((UShortConstant) c).Value;
3303 if (target_type == TypeManager.int32_type)
3305 else if (target_type == TypeManager.uint32_type)
3307 else if (target_type == TypeManager.char_type){
3308 if (v >= Char.MinValue && v <= Char.MaxValue)
3310 } else if (target_type == TypeManager.byte_type){
3311 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3313 } else if (target_type == TypeManager.sbyte_type){
3314 if (v <= SByte.MaxValue)
3316 } else if (target_type == TypeManager.short_type){
3317 if (v <= Int16.MaxValue)
3319 } else if (target_type == TypeManager.int64_type)
3321 else if (target_type == TypeManager.uint64_type)
3325 } else if (c is CharConstant){
3326 char v = ((CharConstant) c).Value;
3328 if (target_type == TypeManager.int32_type)
3330 else if (target_type == TypeManager.uint32_type)
3332 else if (target_type == TypeManager.byte_type){
3333 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3335 } else if (target_type == TypeManager.sbyte_type){
3336 if (v <= SByte.MaxValue)
3338 } else if (target_type == TypeManager.short_type){
3339 if (v <= Int16.MaxValue)
3341 } else if (target_type == TypeManager.ushort_type)
3343 else if (target_type == TypeManager.int64_type)
3345 else if (target_type == TypeManager.uint64_type)
3350 } else if (c is DoubleConstant){
3351 double v = ((DoubleConstant) c).Value;
3353 if (target_type == TypeManager.sbyte_type){
3354 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3355 return new SByteConstant ((sbyte) System.Math.Round (v));
3356 } else if (target_type == TypeManager.byte_type){
3357 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3358 return new ByteConstant ((byte) System.Math.Round (v));
3359 } else if (target_type == TypeManager.char_type){
3360 if (v >= Char.MinValue && v <= Char.MaxValue)
3362 } else if (target_type == TypeManager.short_type){
3363 if (v >= Int16.MinValue && v <= Int16.MaxValue)
3364 return new ShortConstant ((short) System.Math.Round (v));
3365 } else if (target_type == TypeManager.ushort_type){
3366 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3367 return new UShortConstant ((ushort) System.Math.Round (v));
3368 } else if (target_type == TypeManager.int32_type){
3369 if (v >= Int32.MinValue && v <= Int32.MaxValue)
3370 return new IntConstant ((int) System.Math.Round (v));
3371 } else if (target_type == TypeManager.uint32_type){
3372 if (v >= 0 && v <= UInt32.MaxValue)
3373 return new UIntConstant ((uint) System.Math.Round (v));
3374 } else if (target_type == TypeManager.uint64_type){
3376 return new ULongConstant ((ulong) System.Math.Round (v));
3381 Error_ConstantValueCannotBeConverted (loc, s, target_type);
3386 // Load the object from the pointer.
3388 public static void LoadFromPtr (ILGenerator ig, Type t)
3390 if (t == TypeManager.int32_type)
3391 ig.Emit (OpCodes.Ldind_I4);
3392 else if (t == TypeManager.uint32_type)
3393 ig.Emit (OpCodes.Ldind_U4);
3394 else if (t == TypeManager.short_type)
3395 ig.Emit (OpCodes.Ldind_I2);
3396 else if (t == TypeManager.ushort_type)
3397 ig.Emit (OpCodes.Ldind_U2);
3398 else if (t == TypeManager.char_type)
3399 ig.Emit (OpCodes.Ldind_U2);
3400 else if (t == TypeManager.byte_type)
3401 ig.Emit (OpCodes.Ldind_U1);
3402 else if (t == TypeManager.sbyte_type)
3403 ig.Emit (OpCodes.Ldind_I1);
3404 else if (t == TypeManager.uint64_type)
3405 ig.Emit (OpCodes.Ldind_I8);
3406 else if (t == TypeManager.int64_type)
3407 ig.Emit (OpCodes.Ldind_I8);
3408 else if (t == TypeManager.float_type)
3409 ig.Emit (OpCodes.Ldind_R4);
3410 else if (t == TypeManager.double_type)
3411 ig.Emit (OpCodes.Ldind_R8);
3412 else if (t == TypeManager.bool_type)
3413 ig.Emit (OpCodes.Ldind_I1);
3414 else if (t == TypeManager.intptr_type)
3415 ig.Emit (OpCodes.Ldind_I);
3416 else if (TypeManager.IsEnumType (t)) {
3417 if (t == TypeManager.enum_type)
3418 ig.Emit (OpCodes.Ldind_Ref);
3420 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
3421 } else if (t.IsValueType)
3422 ig.Emit (OpCodes.Ldobj, t);
3424 ig.Emit (OpCodes.Ldind_Ref);
3428 // The stack contains the pointer and the value of type 'type'
3430 public static void StoreFromPtr (ILGenerator ig, Type type)
3432 if (TypeManager.IsEnumType (type))
3433 type = TypeManager.EnumToUnderlying (type);
3434 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
3435 ig.Emit (OpCodes.Stind_I4);
3436 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
3437 ig.Emit (OpCodes.Stind_I8);
3438 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
3439 type == TypeManager.ushort_type)
3440 ig.Emit (OpCodes.Stind_I2);
3441 else if (type == TypeManager.float_type)
3442 ig.Emit (OpCodes.Stind_R4);
3443 else if (type == TypeManager.double_type)
3444 ig.Emit (OpCodes.Stind_R8);
3445 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
3446 type == TypeManager.bool_type)
3447 ig.Emit (OpCodes.Stind_I1);
3448 else if (type == TypeManager.intptr_type)
3449 ig.Emit (OpCodes.Stind_I);
3450 else if (type.IsValueType)
3451 ig.Emit (OpCodes.Stobj, type);
3453 ig.Emit (OpCodes.Stind_Ref);
3457 // Returns the size of type 't' if known, otherwise, 0
3459 public static int GetTypeSize (Type t)
3461 t = TypeManager.TypeToCoreType (t);
3462 if (t == TypeManager.int32_type ||
3463 t == TypeManager.uint32_type ||
3464 t == TypeManager.float_type)
3466 else if (t == TypeManager.int64_type ||
3467 t == TypeManager.uint64_type ||
3468 t == TypeManager.double_type)
3470 else if (t == TypeManager.byte_type ||
3471 t == TypeManager.sbyte_type ||
3472 t == TypeManager.bool_type)
3474 else if (t == TypeManager.short_type ||
3475 t == TypeManager.char_type ||
3476 t == TypeManager.ushort_type)
3478 else if (t == TypeManager.decimal_type)
3485 // Default implementation of IAssignMethod.CacheTemporaries
3487 public void CacheTemporaries (EmitContext ec)
3491 static void Error_NegativeArrayIndex (Location loc)
3493 Report.Error (284, loc, "Can not create array with a negative size");
3497 // Converts 'source' to an int, uint, long or ulong.
3499 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
3503 bool old_checked = ec.CheckState;
3504 ec.CheckState = true;
3506 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
3507 if (target == null){
3508 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
3509 if (target == null){
3510 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
3511 if (target == null){
3512 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
3514 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
3518 ec.CheckState = old_checked;
3521 // Only positive constants are allowed at compile time
3523 if (target is Constant){
3524 if (target is IntConstant){
3525 if (((IntConstant) target).Value < 0){
3526 Error_NegativeArrayIndex (loc);
3531 if (target is LongConstant){
3532 if (((LongConstant) target).Value < 0){
3533 Error_NegativeArrayIndex (loc);
3546 /// This is just a base class for expressions that can
3547 /// appear on statements (invocations, object creation,
3548 /// assignments, post/pre increment and decrement). The idea
3549 /// being that they would support an extra Emition interface that
3550 /// does not leave a result on the stack.
3552 public abstract class ExpressionStatement : Expression {
3555 /// Requests the expression to be emitted in a 'statement'
3556 /// context. This means that no new value is left on the
3557 /// stack after invoking this method (constrasted with
3558 /// Emit that will always leave a value on the stack).
3560 public abstract void EmitStatement (EmitContext ec);
3564 /// This kind of cast is used to encapsulate the child
3565 /// whose type is child.Type into an expression that is
3566 /// reported to return "return_type". This is used to encapsulate
3567 /// expressions which have compatible types, but need to be dealt
3568 /// at higher levels with.
3570 /// For example, a "byte" expression could be encapsulated in one
3571 /// of these as an "unsigned int". The type for the expression
3572 /// would be "unsigned int".
3575 public class EmptyCast : Expression {
3576 protected Expression child;
3578 public EmptyCast (Expression child, Type return_type)
3580 eclass = child.eclass;
3585 public override Expression DoResolve (EmitContext ec)
3587 // This should never be invoked, we are born in fully
3588 // initialized state.
3593 public override void Emit (EmitContext ec)
3600 /// This class is used to wrap literals which belong inside Enums
3602 public class EnumConstant : Constant {
3603 public Constant Child;
3605 public EnumConstant (Constant child, Type enum_type)
3607 eclass = child.eclass;
3612 public override Expression DoResolve (EmitContext ec)
3614 // This should never be invoked, we are born in fully
3615 // initialized state.
3620 public override void Emit (EmitContext ec)
3625 public override object GetValue ()
3627 return Child.GetValue ();
3631 // Converts from one of the valid underlying types for an enumeration
3632 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
3633 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
3635 public Constant WidenToCompilerConstant ()
3637 Type t = TypeManager.EnumToUnderlying (Child.Type);
3638 object v = ((Constant) Child).GetValue ();;
3640 if (t == TypeManager.int32_type)
3641 return new IntConstant ((int) v);
3642 if (t == TypeManager.uint32_type)
3643 return new UIntConstant ((uint) v);
3644 if (t == TypeManager.int64_type)
3645 return new LongConstant ((long) v);
3646 if (t == TypeManager.uint64_type)
3647 return new ULongConstant ((ulong) v);
3648 if (t == TypeManager.short_type)
3649 return new ShortConstant ((short) v);
3650 if (t == TypeManager.ushort_type)
3651 return new UShortConstant ((ushort) v);
3652 if (t == TypeManager.byte_type)
3653 return new ByteConstant ((byte) v);
3654 if (t == TypeManager.sbyte_type)
3655 return new SByteConstant ((sbyte) v);
3657 throw new Exception ("Invalid enumeration underlying type: " + t);
3661 // Extracts the value in the enumeration on its native representation
3663 public object GetPlainValue ()
3665 Type t = TypeManager.EnumToUnderlying (Child.Type);
3666 object v = ((Constant) Child).GetValue ();;
3668 if (t == TypeManager.int32_type)
3670 if (t == TypeManager.uint32_type)
3672 if (t == TypeManager.int64_type)
3674 if (t == TypeManager.uint64_type)
3676 if (t == TypeManager.short_type)
3678 if (t == TypeManager.ushort_type)
3680 if (t == TypeManager.byte_type)
3682 if (t == TypeManager.sbyte_type)
3688 public override string AsString ()
3690 return Child.AsString ();
3693 public override DoubleConstant ConvertToDouble ()
3695 return Child.ConvertToDouble ();
3698 public override FloatConstant ConvertToFloat ()
3700 return Child.ConvertToFloat ();
3703 public override ULongConstant ConvertToULong ()
3705 return Child.ConvertToULong ();
3708 public override LongConstant ConvertToLong ()
3710 return Child.ConvertToLong ();
3713 public override UIntConstant ConvertToUInt ()
3715 return Child.ConvertToUInt ();
3718 public override IntConstant ConvertToInt ()
3720 return Child.ConvertToInt ();
3725 /// This kind of cast is used to encapsulate Value Types in objects.
3727 /// The effect of it is to box the value type emitted by the previous
3730 public class BoxedCast : EmptyCast {
3732 public BoxedCast (Expression expr)
3733 : base (expr, TypeManager.object_type)
3737 public override Expression DoResolve (EmitContext ec)
3739 // This should never be invoked, we are born in fully
3740 // initialized state.
3745 public override void Emit (EmitContext ec)
3749 ec.ig.Emit (OpCodes.Box, child.Type);
3753 public class UnboxCast : EmptyCast {
3754 public UnboxCast (Expression expr, Type return_type)
3755 : base (expr, return_type)
3759 public override Expression DoResolve (EmitContext ec)
3761 // This should never be invoked, we are born in fully
3762 // initialized state.
3767 public override void Emit (EmitContext ec)
3770 ILGenerator ig = ec.ig;
3773 ig.Emit (OpCodes.Unbox, t);
3775 LoadFromPtr (ig, t);
3780 /// This is used to perform explicit numeric conversions.
3782 /// Explicit numeric conversions might trigger exceptions in a checked
3783 /// context, so they should generate the conv.ovf opcodes instead of
3786 public class ConvCast : EmptyCast {
3787 public enum Mode : byte {
3788 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
3790 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
3791 U2_I1, U2_U1, U2_I2, U2_CH,
3792 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
3793 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
3794 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
3795 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
3796 CH_I1, CH_U1, CH_I2,
3797 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
3798 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
3804 public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
3805 : base (child, return_type)
3807 checked_state = ec.CheckState;
3811 public override Expression DoResolve (EmitContext ec)
3813 // This should never be invoked, we are born in fully
3814 // initialized state.
3819 public override void Emit (EmitContext ec)
3821 ILGenerator ig = ec.ig;
3827 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3828 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3829 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3830 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3831 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3833 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3834 case Mode.U1_CH: /* nothing */ break;
3836 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3837 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3838 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3839 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3840 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3841 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3843 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3844 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3845 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3846 case Mode.U2_CH: /* nothing */ break;
3848 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3849 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3850 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3851 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3852 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3853 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3854 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3856 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3857 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3858 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3859 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3860 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3861 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3863 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3864 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3865 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3866 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3867 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3868 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3869 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3870 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3872 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3873 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3874 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3875 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3876 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3877 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
3878 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
3879 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3881 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3882 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3883 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3885 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3886 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3887 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3888 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3889 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3890 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3891 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3892 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3893 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3895 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3896 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3897 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3898 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3899 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3900 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3901 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3902 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3903 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3904 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3908 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
3909 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
3910 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
3911 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
3912 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
3914 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
3915 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
3917 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
3918 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
3919 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
3920 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
3921 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
3922 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
3924 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
3925 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
3926 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
3927 case Mode.U2_CH: /* nothing */ break;
3929 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
3930 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
3931 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
3932 case Mode.I4_U4: /* nothing */ break;
3933 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
3934 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
3935 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
3937 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
3938 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
3939 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
3940 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
3941 case Mode.U4_I4: /* nothing */ break;
3942 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
3944 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
3945 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
3946 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
3947 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
3948 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
3949 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
3950 case Mode.I8_U8: /* nothing */ break;
3951 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
3953 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
3954 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
3955 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
3956 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
3957 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
3958 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
3959 case Mode.U8_I8: /* nothing */ break;
3960 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
3962 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
3963 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
3964 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
3966 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
3967 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
3968 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
3969 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
3970 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
3971 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
3972 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
3973 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
3974 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
3976 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
3977 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
3978 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
3979 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
3980 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
3981 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
3982 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
3983 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
3984 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
3985 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3991 public class OpcodeCast : EmptyCast {
3995 public OpcodeCast (Expression child, Type return_type, OpCode op)
3996 : base (child, return_type)
4000 second_valid = false;
4003 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
4004 : base (child, return_type)
4009 second_valid = true;
4012 public override Expression DoResolve (EmitContext ec)
4014 // This should never be invoked, we are born in fully
4015 // initialized state.
4020 public override void Emit (EmitContext ec)
4031 public class NumericToBoolCast : EmptyCast
4035 public NumericToBoolCast (Expression src, Type src_type)
4036 : base (src, TypeManager.bool_type)
4039 this.src_type = src_type;
4042 public override Expression DoResolve (EmitContext ec)
4047 public override void Emit (EmitContext ec)
4051 if (src_type == TypeManager.byte_type ||
4052 src_type == TypeManager.short_type ||
4053 src_type == TypeManager.int32_type) {
4055 ec.ig.Emit (OpCodes.Ldc_I4_0);
4056 ec.ig.Emit (OpCodes.Cgt_Un);
4060 if (src_type == TypeManager.int64_type) {
4061 ec.ig.Emit (OpCodes.Ldc_I8, (long) 0);
4062 ec.ig.Emit (OpCodes.Cgt_Un);
4066 if (src_type == TypeManager.float_type) {
4067 ec.ig.Emit (OpCodes.Ldc_R4, (float) 0);
4068 ec.ig.Emit (OpCodes.Ceq);
4069 ec.ig.Emit (OpCodes.Ldc_I4_0);
4070 ec.ig.Emit (OpCodes.Ceq);
4074 if (src_type == TypeManager.double_type) {
4075 ec.ig.Emit (OpCodes.Ldc_R8, (double) 0);
4076 ec.ig.Emit (OpCodes.Ceq);
4077 ec.ig.Emit (OpCodes.Ldc_I4_0);
4078 ec.ig.Emit (OpCodes.Ceq);
4084 public class BoolToNumericCast : EmptyCast
4090 public BoolToNumericCast (Expression src, Type target_type)
4091 : base (src, target_type)
4094 this.target_type = target_type;
4097 public override Expression DoResolve (EmitContext ec)
4102 public override void Emit (EmitContext ec)
4106 if (target_type == TypeManager.byte_type) {
4107 conv = OpCodes.Conv_U1;
4108 } else if (target_type == TypeManager.short_type) {
4109 conv = OpCodes.Conv_I2;
4110 } else if (target_type == TypeManager.int32_type) {
4111 conv = OpCodes.Conv_I4;
4112 } else if (target_type == TypeManager.int64_type) {
4113 conv = OpCodes.Conv_I8;
4114 } else if (target_type == TypeManager.float_type) {
4115 conv = OpCodes.Conv_R4;
4116 } else if (target_type == TypeManager.double_type) {
4117 conv = OpCodes.Conv_R8;
4120 ec.ig.Emit (OpCodes.Ldc_I4_0);
4121 ec.ig.Emit (OpCodes.Cgt_Un);
4122 ec.ig.Emit (OpCodes.Neg);
4129 /// This kind of cast is used to encapsulate a child and cast it
4130 /// to the class requested
4132 public class ClassCast : EmptyCast {
4133 public ClassCast (Expression child, Type return_type)
4134 : base (child, return_type)
4139 public override Expression DoResolve (EmitContext ec)
4141 // This should never be invoked, we are born in fully
4142 // initialized state.
4147 public override void Emit (EmitContext ec)
4151 ec.ig.Emit (OpCodes.Castclass, type);
4157 /// SimpleName expressions are initially formed of a single
4158 /// word and it only happens at the beginning of the expression.
4162 /// The expression will try to be bound to a Field, a Method
4163 /// group or a Property. If those fail we pass the name to our
4164 /// caller and the SimpleName is compounded to perform a type
4165 /// lookup. The idea behind this process is that we want to avoid
4166 /// creating a namespace map from the assemblies, as that requires
4167 /// the GetExportedTypes function to be called and a hashtable to
4168 /// be constructed which reduces startup time. If later we find
4169 /// that this is slower, we should create a 'NamespaceExpr' expression
4170 /// that fully participates in the resolution process.
4172 /// For example 'System.Console.WriteLine' is decomposed into
4173 /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
4175 /// The first SimpleName wont produce a match on its own, so it will
4177 /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
4179 /// System.Console will produce a TypeExpr match.
4181 /// The downside of this is that we might be hitting 'LookupType' too many
4182 /// times with this scheme.
4184 public class SimpleName : Expression, ITypeExpression {
4185 public readonly string Name;
4187 public SimpleName (string name, Location l)
4193 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
4195 if (ec.IsFieldInitializer)
4198 "A field initializer cannot reference the non-static field, " +
4199 "method or property '"+name+"'");
4203 "An object reference is required " +
4204 "for the non-static field '"+name+"'");
4208 // Checks whether we are trying to access an instance
4209 // property, method or field from a static body.
4211 Expression MemberStaticCheck (EmitContext ec, Expression e)
4213 if (e is IMemberExpr){
4214 IMemberExpr member = (IMemberExpr) e;
4216 if (!member.IsStatic){
4217 Error_ObjectRefRequired (ec, loc, Name);
4225 public override Expression DoResolve (EmitContext ec)
4227 return SimpleNameResolve (ec, null, false);
4230 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4232 return SimpleNameResolve (ec, right_side, false);
4236 public Expression DoResolveAllowStatic (EmitContext ec)
4238 return SimpleNameResolve (ec, null, true);
4241 public Expression DoResolveType (EmitContext ec)
4244 // Stage 3: Lookup symbol in the various namespaces.
4246 DeclSpace ds = ec.DeclSpace;
4250 if (ec.ResolvingTypeTree){
4251 int errors = Report.Errors;
4252 Type dt = ec.DeclSpace.FindType (loc, Name);
4253 if (Report.Errors != errors)
4257 return new TypeExpr (dt, loc);
4260 if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
4261 return new TypeExpr (t, loc);
4265 // Stage 2 part b: Lookup up if we are an alias to a type
4268 // Since we are cheating: we only do the Alias lookup for
4269 // namespaces if the name does not include any dots in it
4272 alias_value = ec.DeclSpace.LookupAlias (Name);
4274 if (Name.IndexOf ('.') == -1 && alias_value != null) {
4275 if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
4276 return new TypeExpr (t, loc);
4278 // we have alias value, but it isn't Type, so try if it's namespace
4279 return new SimpleName (alias_value, loc);
4282 // No match, maybe our parent can compose us
4283 // into something meaningful.
4288 /// 7.5.2: Simple Names.
4290 /// Local Variables and Parameters are handled at
4291 /// parse time, so they never occur as SimpleNames.
4293 /// The 'allow_static' flag is used by MemberAccess only
4294 /// and it is used to inform us that it is ok for us to
4295 /// avoid the static check, because MemberAccess might end
4296 /// up resolving the Name as a Type name and the access as
4297 /// a static type access.
4299 /// ie: Type Type; .... { Type.GetType (""); }
4301 /// Type is both an instance variable and a Type; Type.GetType
4302 /// is the static method not an instance method of type.
4304 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
4306 Expression e = null;
4309 // Stage 1: Performed by the parser (binding to locals or parameters).
4311 Block current_block = ec.CurrentBlock;
4312 if (ec.InvokingOwnOverload == false && current_block != null && current_block.IsVariableDefined (Name)){
4313 LocalVariableReference var;
4315 var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
4317 if (right_side != null)
4318 return var.ResolveLValue (ec, right_side);
4320 return var.Resolve (ec);
4323 if (current_block != null){
4325 Parameter par = null;
4326 Parameters pars = current_block.Parameters;
4328 par = pars.GetParameterByName (Name, out idx);
4331 ParameterReference param;
4333 param = new ParameterReference (pars, idx, Name, loc);
4335 if (right_side != null)
4336 return param.ResolveLValue (ec, right_side);
4338 return param.Resolve (ec);
4343 // Stage 2: Lookup members
4347 // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
4348 // Hence we have two different cases
4351 DeclSpace lookup_ds = ec.DeclSpace;
4353 if (lookup_ds.TypeBuilder == null)
4356 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
4361 // Classes/structs keep looking, enums break
4363 if (lookup_ds is TypeContainer)
4364 lookup_ds = ((TypeContainer) lookup_ds).Parent;
4367 } while (lookup_ds != null);
4369 if (e == null && ec.ContainerType != null)
4370 e = MemberLookup (ec, ec.ContainerType, Name, loc);
4372 // #52067 - Start - Trying to solve
4376 ArrayList lookups = new ArrayList();
4377 ArrayList typelookups = new ArrayList();
4379 int split = Name.LastIndexOf('.');
4381 String nameSpacePart = Name.Substring(0, split);
4382 String memberNamePart = Name.Substring(split + 1);
4383 foreach(Type type in TypeManager.GetPertinentStandardModules(nameSpacePart)) {
4384 e = MemberLookup(ec, type, memberNamePart, loc);
4387 typelookups.Add(type);
4392 string[] NamespacesInScope = RootContext.SourceBeingCompiled.GetNamespacesInScope(ec.DeclSpace.Namespace.Name);
4393 foreach(Type type in TypeManager.GetPertinentStandardModules(NamespacesInScope)) {
4394 e = MemberLookup(ec, type, Name, loc);
4397 typelookups.Add(type);
4400 if (lookups.Count == 1) {
4401 e = (Expression)lookups[0];
4403 if (lookups.Count > 1) {
4404 StringBuilder sb = new StringBuilder();
4405 foreach(Type type in typelookups)
4406 sb.Append("'" + type.FullName + "'");
4407 Error (-1, "The name '" + Name + "' can be resolved to a member of more than one standard module: " + sb.ToString() + ". Please fully qualify it.");
4416 return DoResolveType (ec);
4421 if (e is IMemberExpr) {
4422 e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
4426 IMemberExpr me = e as IMemberExpr;
4430 // This fails if ResolveMemberAccess() was unable to decide whether
4431 // it's a field or a type of the same name.
4432 if (!me.IsStatic && (me.InstanceExpression == null))
4435 /* FIXME If this is not commented out, it seems that it's not possible to reach class members in mBas.
4436 Maybe a grammar-related problem?
4439 TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
4440 Error (38, "Cannot access nonstatic member '" + me.Name + "' of " +
4441 "outer type '" + me.DeclaringType + "' via nested type '" +
4442 me.InstanceExpression.Type + "'");
4446 if (right_side != null)
4447 e = e.DoResolveLValue (ec, right_side);
4449 e = e.DoResolve (ec);
4454 if (ec.IsStatic || ec.IsFieldInitializer){
4458 return MemberStaticCheck (ec, e);
4463 public override void Emit (EmitContext ec)
4466 // If this is ever reached, then we failed to
4467 // find the name as a namespace
4470 Error (30451, "The name '" + Name +
4471 "' does not exist in the class '" +
4472 ec.DeclSpace.Name + "'");
4475 public override string ToString ()
4482 /// Fully resolved expression that evaluates to a type
4484 public class TypeExpr : Expression, ITypeExpression {
4485 public TypeExpr (Type t, Location l)
4488 eclass = ExprClass.Type;
4492 public virtual Expression DoResolveType (EmitContext ec)
4497 override public Expression DoResolve (EmitContext ec)
4502 override public void Emit (EmitContext ec)
4504 throw new Exception ("Should never be called");
4507 public override string ToString ()
4509 return Type.ToString ();
4514 /// Used to create types from a fully qualified name. These are just used
4515 /// by the parser to setup the core types. A TypeLookupExpression is always
4516 /// classified as a type.
4518 public class TypeLookupExpression : TypeExpr {
4521 public TypeLookupExpression (string name) : base (null, Location.Null)
4526 public override Expression DoResolveType (EmitContext ec)
4529 type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
4533 public override Expression DoResolve (EmitContext ec)
4535 return DoResolveType (ec);
4538 public override void Emit (EmitContext ec)
4540 throw new Exception ("Should never be called");
4543 public override string ToString ()
4550 /// MethodGroup Expression.
4552 /// This is a fully resolved expression that evaluates to a type
4554 public class MethodGroupExpr : Expression, IMemberExpr {
4555 public MethodBase [] Methods;
4556 Expression instance_expression = null;
4557 bool is_explicit_impl = false;
4559 public MethodGroupExpr (MemberInfo [] mi, Location l)
4561 Methods = new MethodBase [mi.Length];
4562 mi.CopyTo (Methods, 0);
4563 eclass = ExprClass.MethodGroup;
4564 type = TypeManager.object_type;
4568 public MethodGroupExpr (ArrayList list, Location l)
4570 Methods = new MethodBase [list.Count];
4573 list.CopyTo (Methods, 0);
4575 foreach (MemberInfo m in list){
4576 if (!(m is MethodBase)){
4577 Console.WriteLine ("Name " + m.Name);
4578 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4584 eclass = ExprClass.MethodGroup;
4585 type = TypeManager.object_type;
4588 public Type DeclaringType {
4590 return Methods [0].DeclaringType;
4595 // 'A method group may have associated an instance expression'
4597 public Expression InstanceExpression {
4599 return instance_expression;
4603 instance_expression = value;
4607 public bool IsExplicitImpl {
4609 return is_explicit_impl;
4613 is_explicit_impl = value;
4617 public string Name {
4619 return Methods [0].Name;
4623 public bool IsInstance {
4625 foreach (MethodBase mb in Methods)
4633 public bool IsStatic {
4635 foreach (MethodBase mb in Methods)
4643 override public Expression DoResolve (EmitContext ec)
4645 if (instance_expression != null) {
4646 instance_expression = instance_expression.DoResolve (ec);
4647 if (instance_expression == null)
4654 public void ReportUsageError ()
4656 Report.Error (654, loc, "Method '" + Methods [0].DeclaringType + "." +
4657 Methods [0].Name + "()' is referenced without parentheses");
4660 override public void Emit (EmitContext ec)
4662 ReportUsageError ();
4665 bool RemoveMethods (bool keep_static)
4667 ArrayList smethods = new ArrayList ();
4669 foreach (MethodBase mb in Methods){
4670 if (mb.IsStatic == keep_static)
4674 if (smethods.Count == 0)
4677 Methods = new MethodBase [smethods.Count];
4678 smethods.CopyTo (Methods, 0);
4684 /// Removes any instance methods from the MethodGroup, returns
4685 /// false if the resulting set is empty.
4687 public bool RemoveInstanceMethods ()
4689 return RemoveMethods (true);
4693 /// Removes any static methods from the MethodGroup, returns
4694 /// false if the resulting set is empty.
4696 public bool RemoveStaticMethods ()
4698 return RemoveMethods (false);
4703 /// Fully resolved expression that evaluates to a Field
4705 public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr {
4706 public readonly FieldInfo FieldInfo;
4707 Expression instance_expr;
4709 public FieldExpr (FieldInfo fi, Location l)
4712 eclass = ExprClass.Variable;
4713 type = fi.FieldType;
4717 public string Name {
4719 return FieldInfo.Name;
4723 public bool IsInstance {
4725 return !FieldInfo.IsStatic;
4729 public bool IsStatic {
4731 return FieldInfo.IsStatic;
4735 public Type DeclaringType {
4737 return FieldInfo.DeclaringType;
4741 public Expression InstanceExpression {
4743 return instance_expr;
4747 instance_expr = value;
4751 override public Expression DoResolve (EmitContext ec)
4753 if (!FieldInfo.IsStatic){
4754 if (instance_expr == null){
4755 throw new Exception ("non-static FieldExpr without instance var\n" +
4756 "You have to assign the Instance variable\n" +
4757 "Of the FieldExpr to set this\n");
4760 // Resolve the field's instance expression while flow analysis is turned
4761 // off: when accessing a field "a.b", we must check whether the field
4762 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4763 instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
4764 ResolveFlags.DisableFlowAnalysis);
4765 if (instance_expr == null)
4769 // If the instance expression is a local variable or parameter.
4770 IVariable var = instance_expr as IVariable;
4771 if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc))
4777 void Report_AssignToReadonly (bool is_instance)
4782 msg = "Readonly field can not be assigned outside " +
4783 "of constructor or variable initializer";
4785 msg = "A static readonly field can only be assigned in " +
4786 "a static constructor";
4788 Report.Error (is_instance ? 191 : 198, loc, msg);
4791 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4793 IVariable var = instance_expr as IVariable;
4795 var.SetFieldAssigned (ec, FieldInfo.Name);
4797 Expression e = DoResolve (ec);
4802 if (!FieldInfo.IsInitOnly)
4806 // InitOnly fields can only be assigned in constructors
4809 if (ec.IsConstructor)
4812 Report_AssignToReadonly (true);
4817 override public void Emit (EmitContext ec)
4819 ILGenerator ig = ec.ig;
4820 bool is_volatile = false;
4822 if (FieldInfo is FieldBuilder){
4823 FieldBase f = TypeManager.GetField (FieldInfo);
4825 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4828 f.status |= Field.Status.USED;
4831 if (FieldInfo.IsStatic){
4833 ig.Emit (OpCodes.Volatile);
4835 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4837 if (instance_expr.Type.IsValueType){
4839 LocalTemporary tempo = null;
4841 if (!(instance_expr is IMemoryLocation)){
4842 tempo = new LocalTemporary (
4843 ec, instance_expr.Type);
4845 InstanceExpression.Emit (ec);
4849 ml = (IMemoryLocation) instance_expr;
4851 ml.AddressOf (ec, AddressOp.Load);
4853 instance_expr.Emit (ec);
4856 ig.Emit (OpCodes.Volatile);
4858 ig.Emit (OpCodes.Ldfld, FieldInfo);
4862 public void EmitAssign (EmitContext ec, Expression source)
4864 FieldAttributes fa = FieldInfo.Attributes;
4865 bool is_static = (fa & FieldAttributes.Static) != 0;
4866 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4867 ILGenerator ig = ec.ig;
4869 if (is_readonly && !ec.IsConstructor){
4870 Report_AssignToReadonly (!is_static);
4875 Expression instance = instance_expr;
4877 if (instance.Type.IsValueType){
4878 if (instance is IMemoryLocation){
4879 IMemoryLocation ml = (IMemoryLocation) instance;
4881 ml.AddressOf (ec, AddressOp.Store);
4883 throw new Exception ("The " + instance + " of type " +
4885 " represents a ValueType and does " +
4886 "not implement IMemoryLocation");
4892 if (FieldInfo is FieldBuilder){
4893 FieldBase f = TypeManager.GetField (FieldInfo);
4895 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4896 ig.Emit (OpCodes.Volatile);
4900 ig.Emit (OpCodes.Stsfld, FieldInfo);
4902 ig.Emit (OpCodes.Stfld, FieldInfo);
4904 if (FieldInfo is FieldBuilder){
4905 FieldBase f = TypeManager.GetField (FieldInfo);
4907 f.status |= Field.Status.ASSIGNED;
4911 public void AddressOf (EmitContext ec, AddressOp mode)
4913 ILGenerator ig = ec.ig;
4915 if (FieldInfo is FieldBuilder){
4916 FieldBase f = TypeManager.GetField (FieldInfo);
4917 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4918 ig.Emit (OpCodes.Volatile);
4921 if (FieldInfo is FieldBuilder){
4922 FieldBase f = TypeManager.GetField (FieldInfo);
4924 if ((mode & AddressOp.Store) != 0)
4925 f.status |= Field.Status.ASSIGNED;
4926 if ((mode & AddressOp.Load) != 0)
4927 f.status |= Field.Status.USED;
4931 // Handle initonly fields specially: make a copy and then
4932 // get the address of the copy.
4934 if (FieldInfo.IsInitOnly && !ec.IsConstructor){
4938 local = ig.DeclareLocal (type);
4939 ig.Emit (OpCodes.Stloc, local);
4940 ig.Emit (OpCodes.Ldloca, local);
4944 if (FieldInfo.IsStatic)
4945 ig.Emit (OpCodes.Ldsflda, FieldInfo);
4947 if (instance_expr is IMemoryLocation)
4948 ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
4950 instance_expr.Emit (ec);
4951 ig.Emit (OpCodes.Ldflda, FieldInfo);
4957 /// Expression that evaluates to a Property. The Assign class
4958 /// might set the 'Value' expression if we are in an assignment.
4960 /// This is not an LValue because we need to re-write the expression, we
4961 /// can not take data from the stack and store it.
4963 public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
4964 public readonly PropertyInfo PropertyInfo;
4966 MethodInfo getter, setter;
4968 public ArrayList PropertyArgs;
4970 Expression instance_expr;
4972 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
4975 eclass = ExprClass.PropertyAccess;
4976 PropertyArgs = null;
4980 type = TypeManager.TypeToCoreType (pi.PropertyType);
4982 ResolveAccessors (ec);
4985 public string Name {
4987 return PropertyInfo.Name;
4991 public bool IsInstance {
4997 public bool IsStatic {
5003 public Type DeclaringType {
5005 return PropertyInfo.DeclaringType;
5010 // The instance expression associated with this expression
5012 public Expression InstanceExpression {
5014 instance_expr = value;
5018 return instance_expr;
5022 public bool VerifyAssignable ()
5024 if (!PropertyInfo.CanWrite){
5025 Report.Error (200, loc,
5026 "The property '" + PropertyInfo.Name +
5027 "' can not be assigned to, as it has not set accessor");
5034 void ResolveAccessors (EmitContext ec)
5036 BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
5037 MemberInfo [] group;
5039 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5040 MemberTypes.Method, flags, "get_" + PropertyInfo.Name);
5043 // The first method is the closest to us
5045 if (group != null && group.Length > 0){
5046 getter = (MethodInfo) group [0];
5048 if (getter.IsStatic)
5053 // The first method is the closest to us
5055 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5056 MemberTypes.Method, flags, "set_" + PropertyInfo.Name);
5057 if (group != null && group.Length > 0){
5058 setter = (MethodInfo) group [0];
5059 if (setter.IsStatic)
5064 override public Expression DoResolve (EmitContext ec)
5066 if (getter == null){
5067 Report.Error (30524, loc,
5068 "The property '" + PropertyInfo.Name +
5069 "' can not be used in " +
5070 "this context because it lacks a get accessor");
5074 if ((instance_expr == null) && ec.IsStatic && !is_static) {
5075 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
5079 if (instance_expr != null) {
5080 instance_expr = instance_expr.DoResolve (ec);
5081 if (instance_expr == null)
5088 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5090 if (setter == null){
5091 Report.Error (30526, loc,
5092 "The property '" + PropertyInfo.Name +
5093 "' can not be used in " +
5094 "this context because it lacks a set accessor");
5098 if (instance_expr != null) {
5099 instance_expr = instance_expr.DoResolve (ec);
5100 if (instance_expr == null)
5107 override public void Emit (EmitContext ec)
5110 // Special case: length of single dimension array property is turned into ldlen
5112 if ((getter == TypeManager.system_int_array_get_length) ||
5113 (getter == TypeManager.int_array_get_length)){
5114 Type iet = instance_expr.Type;
5117 // System.Array.Length can be called, but the Type does not
5118 // support invoking GetArrayRank, so test for that case first
5120 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
5121 instance_expr.Emit (ec);
5122 ec.ig.Emit (OpCodes.Ldlen);
5126 if (PropertyArgs == null)
5127 PropertyArgs = new ArrayList ();
5128 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, PropertyArgs, loc);
5132 // Implements the IAssignMethod interface for assignments
5134 public void EmitAssign (EmitContext ec, Expression source)
5136 Argument arg = new Argument (source, Argument.AType.Expression);
5137 ArrayList args = new ArrayList ();
5140 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, PropertyArgs,loc);
5143 override public void EmitStatement (EmitContext ec)
5146 ec.ig.Emit (OpCodes.Pop);
5151 /// Fully resolved expression that evaluates to an Event
5153 public class EventExpr : Expression, IMemberExpr {
5154 public readonly EventInfo EventInfo;
5155 public Expression instance_expr;
5158 MethodInfo add_accessor, remove_accessor;
5160 public EventExpr (EventInfo ei, Location loc)
5164 eclass = ExprClass.EventAccess;
5166 add_accessor = TypeManager.GetAddMethod (ei);
5167 remove_accessor = TypeManager.GetRemoveMethod (ei);
5169 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5172 if (EventInfo is MyEventBuilder)
5173 type = ((MyEventBuilder) EventInfo).EventType;
5175 type = EventInfo.EventHandlerType;
5178 public string Name {
5180 return EventInfo.Name;
5184 public bool IsInstance {
5190 public bool IsStatic {
5196 public Type DeclaringType {
5198 return EventInfo.DeclaringType;
5202 public Expression InstanceExpression {
5204 return instance_expr;
5208 instance_expr = value;
5212 Expression field_expr = null;
5214 public override Expression DoResolve (EmitContext ec)
5216 if (instance_expr != null) {
5217 instance_expr = instance_expr.DoResolve (ec);
5218 if (instance_expr == null)
5222 if (this.DeclaringType == ec.ContainerType) {
5223 MemberInfo mi = GetFieldFromEvent (this);
5226 field_expr = ExprClassFromMemberInfo (ec, mi, loc);
5227 ((FieldExpr) field_expr).InstanceExpression = instance_expr;
5228 field_expr = field_expr.DoResolve (ec);
5229 if (field_expr == null)
5236 public override void Emit (EmitContext ec)
5238 if (field_expr != null)
5239 field_expr.Emit (ec);
5242 public void EmitAddOrRemove (EmitContext ec, Expression source)
5244 Expression handler = ((Binary) source).Right;
5246 Argument arg = new Argument (handler, Argument.AType.Expression);
5247 ArrayList args = new ArrayList ();
5251 if (((Binary) source).Oper == Binary.Operator.Addition)
5252 Invocation.EmitCall (
5253 ec, false, IsStatic, instance_expr, add_accessor, args, loc);
5255 Invocation.EmitCall (
5256 ec, false, IsStatic, instance_expr, remove_accessor, args, loc);