2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
13 using System.Collections;
14 using System.Diagnostics;
15 using System.Reflection;
16 using System.Reflection.Emit;
20 // The ExprClass class contains the is used to pass the
21 // classification of an expression (value, variable, namespace,
22 // type, method group, property access, event access, indexer access,
25 public enum ExprClass : byte {
40 // This interface is implemented by variables
42 public interface IMemoryLocation {
44 // The AddressOf method should generate code that loads
45 // the address of the object and leaves it on the stack
47 void AddressOf (EmitContext ec);
51 // Base class for expressions
53 public abstract class Expression {
54 protected ExprClass eclass;
67 public ExprClass ExprClass {
78 // Utility wrapper routine for Error, just to beautify the code
80 static protected void Error (int error, string s)
82 Report.Error (error, s);
85 static protected void Error (int error, Location loc, string s)
87 Report.Error (error, loc, s);
91 // Utility wrapper routine for Warning, just to beautify the code
93 static protected void Warning (int warning, string s)
95 Report.Warning (warning, s);
98 static public void error30 (Location loc, Type source, Type target)
100 Report.Error (30, loc, "Cannot convert type '" +
101 TypeManager.CSharpName (source) + "' to '" +
102 TypeManager.CSharpName (target) + "'");
106 // Performs semantic analysis on the Expression
110 // The Resolve method is invoked to perform the semantic analysis
113 // The return value is an expression (it can be the
114 // same expression in some cases) or a new
115 // expression that better represents this node.
117 // For example, optimizations of Unary (LiteralInt)
118 // would return a new LiteralInt with a negated
121 // If there is an error during semantic analysis,
122 // then an error should be reported (using Report)
123 // and a null value should be returned.
125 // There are two side effects expected from calling
126 // Resolve(): the the field variable "eclass" should
127 // be set to any value of the enumeration
128 // `ExprClass' and the type variable should be set
129 // to a valid type (this is the type of the
133 public abstract Expression DoResolve (EmitContext ec);
135 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
137 return DoResolve (ec);
141 // Currently Resolve wraps DoResolve to perform sanity
142 // checking and assertion checking on what we expect from Resolve
144 public Expression Resolve (EmitContext ec)
146 Expression e = DoResolve (ec);
149 if (e is SimpleName){
150 SimpleName s = (SimpleName) e;
154 "The name `" + s.Name + "' could not be found in `" +
155 ec.TypeContainer.Name + "'");
159 if (e.ExprClass == ExprClass.Invalid)
160 throw new Exception ("Expression " + e +
161 " ExprClass is Invalid after resolve");
163 if (e.ExprClass != ExprClass.MethodGroup)
165 throw new Exception ("Expression " + e +
166 " did not set its type after Resolve");
173 // Just like `Resolve' above, but this allows SimpleNames to be returned.
174 // This is used by MemberAccess to construct long names that can not be
175 // partially resolved (namespace-qualified names for example).
177 public Expression ResolveWithSimpleName (EmitContext ec)
179 Expression e = DoResolve (ec);
185 if (e.ExprClass == ExprClass.Invalid)
186 throw new Exception ("Expression " + e +
187 " ExprClass is Invalid after resolve");
189 if (e.ExprClass != ExprClass.MethodGroup)
191 throw new Exception ("Expression " + e +
192 " did not set its type after Resolve");
199 // Currently ResolveLValue wraps DoResolveLValue to perform sanity
200 // checking and assertion checking on what we expect from Resolve
202 public Expression ResolveLValue (EmitContext ec, Expression right_side)
204 Expression e = DoResolveLValue (ec, right_side);
207 if (e is SimpleName){
208 SimpleName s = (SimpleName) e;
212 "The name `" + s.Name + "' could not be found in `" +
213 ec.TypeContainer.Name + "'");
217 if (e.ExprClass == ExprClass.Invalid)
218 throw new Exception ("Expression " + e +
219 " ExprClass is Invalid after resolve");
221 if (e.ExprClass != ExprClass.MethodGroup)
223 throw new Exception ("Expression " + e +
224 " did not set its type after Resolve");
231 // Emits the code for the expression
236 // The Emit method is invoked to generate the code
237 // for the expression.
240 public abstract void Emit (EmitContext ec);
243 // This method should perform a reduction of the expression. This should
244 // never return null.
246 public virtual Expression Reduce (EmitContext ec)
252 // Protected constructor. Only derivate types should
253 // be able to be created
256 protected Expression ()
258 eclass = ExprClass.Invalid;
263 // Returns a literalized version of a literal FieldInfo
265 public static Expression Literalize (object v, Type t)
267 if (t == TypeManager.int32_type)
268 return new IntLiteral ((int) v);
269 else if (t == TypeManager.uint32_type)
270 return new UIntLiteral ((uint) v);
271 else if (t == TypeManager.int64_type)
272 return new LongLiteral ((long) v);
273 else if (t == TypeManager.uint64_type)
274 return new ULongLiteral ((ulong) v);
275 else if (t == TypeManager.float_type)
276 return new FloatLiteral ((float) v);
277 else if (t == TypeManager.double_type)
278 return new DoubleLiteral ((double) v);
279 else if (t == TypeManager.string_type)
280 return new StringLiteral ((string) v);
281 else if (t == TypeManager.short_type)
282 return new IntLiteral ((int) ((short)v));
283 else if (t == TypeManager.ushort_type)
284 return new IntLiteral ((int) ((ushort)v));
285 else if (t == TypeManager.sbyte_type)
286 return new IntLiteral ((int) ((sbyte)v));
287 else if (t == TypeManager.byte_type)
288 return new IntLiteral ((int) ((byte)v));
289 else if (t == TypeManager.char_type)
290 return new IntLiteral ((int) ((char)v));
292 throw new Exception ("Unknown type for literal (" + t +
297 // Returns a fully formed expression after a MemberLookup
299 static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
302 return new EventExpr ((EventInfo) mi, loc);
303 else if (mi is FieldInfo)
304 return new FieldExpr ((FieldInfo) mi, loc);
305 else if (mi is PropertyInfo)
306 return new PropertyExpr ((PropertyInfo) mi, loc);
308 return new TypeExpr ((Type) mi);
314 // FIXME: Probably implement a cache for (t,name,current_access_set)?
316 // FIXME: We need to cope with access permissions here, or this wont
319 // This code could use some optimizations, but we need to do some
320 // measurements. For example, we could use a delegate to `flag' when
321 // something can not any longer be a method-group (because it is something
325 // If the return value is an Array, then it is an array of
328 // If the return value is an MemberInfo, it is anything, but a Method
332 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
333 // the arguments here and have MemberLookup return only the methods that
334 // match the argument count/type, unlike we are doing now (we delay this
337 // This is so we can catch correctly attempts to invoke instance methods
338 // from a static body (scan for error 120 in ResolveSimpleName).
340 public static Expression MemberLookup (EmitContext ec, Type t, string name,
341 bool same_type, MemberTypes mt,
342 BindingFlags bf, Location loc)
345 bf |= BindingFlags.NonPublic;
347 MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers (
348 t, mt, bf, Type.FilterName, name);
358 if (mi.Length == 1 && !(mi [0] is MethodBase))
359 return Expression.ExprClassFromMemberInfo (ec, mi [0], loc);
361 for (int i = 0; i < mi.Length; i++)
362 if (!(mi [i] is MethodBase)){
363 Error (-5, "Do not know how to reproduce this case: " +
364 "Methods and non-Method with the same name, " +
365 "report this please");
367 for (i = 0; i < mi.Length; i++){
368 Type tt = mi [i].GetType ();
370 Console.WriteLine (i + ": " + mi [i]);
371 while (tt != TypeManager.object_type){
372 Console.WriteLine (tt);
378 return new MethodGroupExpr (mi);
381 public const MemberTypes AllMemberTypes =
382 MemberTypes.Constructor |
386 MemberTypes.NestedType |
387 MemberTypes.Property;
389 public const BindingFlags AllBindingsFlags =
390 BindingFlags.Public |
391 BindingFlags.Static |
392 BindingFlags.Instance;
394 public static Expression MemberLookup (EmitContext ec, Type t, string name,
395 bool same_type, Location loc)
397 return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags, loc);
400 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
402 Type expr_type = expr.Type;
404 if (target_type == TypeManager.object_type) {
405 if (expr_type.IsClass)
406 return new EmptyCast (expr, target_type);
407 if (expr_type.IsValueType)
408 return new BoxedCast (expr);
409 } else if (expr_type.IsSubclassOf (target_type)) {
410 return new EmptyCast (expr, target_type);
412 // from any class-type S to any interface-type T.
413 if (expr_type.IsClass && target_type.IsInterface) {
415 if (TypeManager.ImplementsInterface (expr_type, target_type))
416 return new EmptyCast (expr, target_type);
421 // from any interface type S to interface-type T.
422 if (expr_type.IsInterface && target_type.IsInterface) {
424 if (TypeManager.ImplementsInterface (expr_type, target_type))
425 return new EmptyCast (expr, target_type);
430 // from an array-type S to an array-type of type T
431 if (expr_type.IsArray && target_type.IsArray) {
432 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
434 Type expr_element_type = expr_type.GetElementType ();
435 Type target_element_type = target_type.GetElementType ();
437 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
438 if (StandardConversionExists (expr_element_type,
439 target_element_type))
440 return new EmptyCast (expr, target_type);
445 // from an array-type to System.Array
446 if (expr_type.IsArray && target_type == TypeManager.array_type)
447 return new EmptyCast (expr, target_type);
449 // from any delegate type to System.Delegate
450 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
451 target_type == TypeManager.delegate_type)
452 return new EmptyCast (expr, target_type);
454 // from any array-type or delegate type into System.ICloneable.
455 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
456 if (target_type == TypeManager.icloneable_type)
457 return new EmptyCast (expr, target_type);
459 // from the null type to any reference-type.
460 if (expr is NullLiteral)
461 return new EmptyCast (expr, target_type);
471 // Handles expressions like this: decimal d; d = 1;
472 // and changes them into: decimal d; d = new System.Decimal (1);
474 static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target)
476 ArrayList args = new ArrayList ();
478 args.Add (new Argument (expr, Argument.AType.Expression));
480 Expression ne = new New (target.FullName, args,
483 return ne.Resolve (ec);
487 // Implicit Numeric Conversions.
489 // expr is the expression to convert, returns a new expression of type
490 // target_type or null if an implicit conversion is not possible.
493 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
494 Type target_type, Location loc)
496 Type expr_type = expr.Type;
499 // Attempt to do the implicit constant expression conversions
501 if (expr is IntLiteral){
504 e = TryImplicitIntConversion (target_type, (IntLiteral) expr);
507 } else if (expr is LongLiteral){
509 // Try the implicit constant expression conversion
510 // from long to ulong, instead of a nice routine,
513 if (((LongLiteral) expr).Value > 0)
514 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
517 if (expr_type == TypeManager.sbyte_type){
519 // From sbyte to short, int, long, float, double.
521 if (target_type == TypeManager.int32_type)
522 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
523 if (target_type == TypeManager.int64_type)
524 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
525 if (target_type == TypeManager.double_type)
526 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
527 if (target_type == TypeManager.float_type)
528 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
529 if (target_type == TypeManager.short_type)
530 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
531 if (target_type == TypeManager.decimal_type)
532 return InternalTypeConstructor (ec, expr, target_type);
533 } else if (expr_type == TypeManager.byte_type){
535 // From byte to short, ushort, int, uint, long, ulong, float, double
537 if ((target_type == TypeManager.short_type) ||
538 (target_type == TypeManager.ushort_type) ||
539 (target_type == TypeManager.int32_type) ||
540 (target_type == TypeManager.uint32_type))
541 return new EmptyCast (expr, target_type);
543 if (target_type == TypeManager.uint64_type)
544 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
545 if (target_type == TypeManager.int64_type)
546 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
548 if (target_type == TypeManager.float_type)
549 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
550 if (target_type == TypeManager.double_type)
551 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
552 if (target_type == TypeManager.decimal_type)
553 return InternalTypeConstructor (ec, expr, target_type);
554 } else if (expr_type == TypeManager.short_type){
556 // From short to int, long, float, double
558 if (target_type == TypeManager.int32_type)
559 return new EmptyCast (expr, target_type);
560 if (target_type == TypeManager.int64_type)
561 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
562 if (target_type == TypeManager.double_type)
563 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
564 if (target_type == TypeManager.float_type)
565 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
566 if (target_type == TypeManager.decimal_type)
567 return InternalTypeConstructor (ec, expr, target_type);
568 } else if (expr_type == TypeManager.ushort_type){
570 // From ushort to int, uint, long, ulong, float, double
572 if (target_type == TypeManager.uint32_type)
573 return new EmptyCast (expr, target_type);
575 if (target_type == TypeManager.uint64_type)
576 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
577 if (target_type == TypeManager.int32_type)
578 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
579 if (target_type == TypeManager.int64_type)
580 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
581 if (target_type == TypeManager.double_type)
582 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
583 if (target_type == TypeManager.float_type)
584 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
585 if (target_type == TypeManager.decimal_type)
586 return InternalTypeConstructor (ec, expr, target_type);
587 } else if (expr_type == TypeManager.int32_type){
589 // From int to long, float, double
591 if (target_type == TypeManager.int64_type)
592 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
593 if (target_type == TypeManager.double_type)
594 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
595 if (target_type == TypeManager.float_type)
596 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
597 if (target_type == TypeManager.decimal_type)
598 return InternalTypeConstructor (ec, expr, target_type);
599 } else if (expr_type == TypeManager.uint32_type){
601 // From uint to long, ulong, float, double
603 if (target_type == TypeManager.int64_type)
604 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
605 if (target_type == TypeManager.uint64_type)
606 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
607 if (target_type == TypeManager.double_type)
608 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
610 if (target_type == TypeManager.float_type)
611 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
613 if (target_type == TypeManager.decimal_type)
614 return InternalTypeConstructor (ec, expr, target_type);
615 } else if ((expr_type == TypeManager.uint64_type) ||
616 (expr_type == TypeManager.int64_type)){
618 // From long/ulong to float, double
620 if (target_type == TypeManager.double_type)
621 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
623 if (target_type == TypeManager.float_type)
624 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
626 if (target_type == TypeManager.decimal_type)
627 return InternalTypeConstructor (ec, expr, target_type);
628 } else if (expr_type == TypeManager.char_type){
630 // From char to ushort, int, uint, long, ulong, float, double
632 if ((target_type == TypeManager.ushort_type) ||
633 (target_type == TypeManager.int32_type) ||
634 (target_type == TypeManager.uint32_type))
635 return new EmptyCast (expr, target_type);
636 if (target_type == TypeManager.uint64_type)
637 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
638 if (target_type == TypeManager.int64_type)
639 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
640 if (target_type == TypeManager.float_type)
641 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
642 if (target_type == TypeManager.double_type)
643 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
644 if (target_type == TypeManager.decimal_type)
645 return InternalTypeConstructor (ec, expr, target_type);
646 } else if (expr_type == TypeManager.float_type){
650 if (target_type == TypeManager.double_type)
651 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
658 // Determines if a standard implicit conversion exists from
659 // expr_type to target_type
661 public static bool StandardConversionExists (Type expr_type, Type target_type)
663 if (expr_type == target_type)
666 // First numeric conversions
668 if (expr_type == TypeManager.sbyte_type){
670 // From sbyte to short, int, long, float, double.
672 if ((target_type == TypeManager.int32_type) ||
673 (target_type == TypeManager.int64_type) ||
674 (target_type == TypeManager.double_type) ||
675 (target_type == TypeManager.float_type) ||
676 (target_type == TypeManager.short_type) ||
677 (target_type == TypeManager.decimal_type))
680 } else if (expr_type == TypeManager.byte_type){
682 // From byte to short, ushort, int, uint, long, ulong, float, double
684 if ((target_type == TypeManager.short_type) ||
685 (target_type == TypeManager.ushort_type) ||
686 (target_type == TypeManager.int32_type) ||
687 (target_type == TypeManager.uint32_type) ||
688 (target_type == TypeManager.uint64_type) ||
689 (target_type == TypeManager.int64_type) ||
690 (target_type == TypeManager.float_type) ||
691 (target_type == TypeManager.double_type) ||
692 (target_type == TypeManager.decimal_type))
695 } else if (expr_type == TypeManager.short_type){
697 // From short to int, long, float, double
699 if ((target_type == TypeManager.int32_type) ||
700 (target_type == TypeManager.int64_type) ||
701 (target_type == TypeManager.double_type) ||
702 (target_type == TypeManager.float_type) ||
703 (target_type == TypeManager.decimal_type))
706 } else if (expr_type == TypeManager.ushort_type){
708 // From ushort to int, uint, long, ulong, float, double
710 if ((target_type == TypeManager.uint32_type) ||
711 (target_type == TypeManager.uint64_type) ||
712 (target_type == TypeManager.int32_type) ||
713 (target_type == TypeManager.int64_type) ||
714 (target_type == TypeManager.double_type) ||
715 (target_type == TypeManager.float_type) ||
716 (target_type == TypeManager.decimal_type))
719 } else if (expr_type == TypeManager.int32_type){
721 // From int to long, float, double
723 if ((target_type == TypeManager.int64_type) ||
724 (target_type == TypeManager.double_type) ||
725 (target_type == TypeManager.float_type) ||
726 (target_type == TypeManager.decimal_type))
729 } else if (expr_type == TypeManager.uint32_type){
731 // From uint to long, ulong, float, double
733 if ((target_type == TypeManager.int64_type) ||
734 (target_type == TypeManager.uint64_type) ||
735 (target_type == TypeManager.double_type) ||
736 (target_type == TypeManager.float_type) ||
737 (target_type == TypeManager.decimal_type))
740 } else if ((expr_type == TypeManager.uint64_type) ||
741 (expr_type == TypeManager.int64_type)) {
743 // From long/ulong to float, double
745 if ((target_type == TypeManager.double_type) ||
746 (target_type == TypeManager.float_type) ||
747 (target_type == TypeManager.decimal_type))
750 } else if (expr_type == TypeManager.char_type){
752 // From char to ushort, int, uint, long, ulong, float, double
754 if ((target_type == TypeManager.ushort_type) ||
755 (target_type == TypeManager.int32_type) ||
756 (target_type == TypeManager.uint32_type) ||
757 (target_type == TypeManager.uint64_type) ||
758 (target_type == TypeManager.int64_type) ||
759 (target_type == TypeManager.float_type) ||
760 (target_type == TypeManager.double_type) ||
761 (target_type == TypeManager.decimal_type))
764 } else if (expr_type == TypeManager.float_type){
768 if (target_type == TypeManager.double_type)
772 // Next reference conversions
774 if (target_type == TypeManager.object_type) {
775 if ((expr_type.IsClass) ||
776 (expr_type.IsValueType))
779 } else if (expr_type.IsSubclassOf (target_type)) {
783 // from any class-type S to any interface-type T.
784 if (expr_type.IsClass && target_type.IsInterface)
787 // from any interface type S to interface-type T.
788 // FIXME : Is it right to use IsAssignableFrom ?
789 if (expr_type.IsInterface && target_type.IsInterface)
790 if (target_type.IsAssignableFrom (expr_type))
793 // from an array-type S to an array-type of type T
794 if (expr_type.IsArray && target_type.IsArray) {
795 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
797 Type expr_element_type = expr_type.GetElementType ();
798 Type target_element_type = target_type.GetElementType ();
800 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
801 if (StandardConversionExists (expr_element_type,
802 target_element_type))
807 // from an array-type to System.Array
808 if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type))
811 // from any delegate type to System.Delegate
812 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
813 target_type == TypeManager.delegate_type)
814 if (target_type.IsAssignableFrom (expr_type))
817 // from any array-type or delegate type into System.ICloneable.
818 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
819 if (target_type == TypeManager.icloneable_type)
822 // from the null type to any reference-type.
823 // FIXME : How do we do this ?
831 // Finds "most encompassed type" according to the spec (13.4.2)
832 // amongst the methods in the MethodGroupExpr which convert from a
833 // type encompassing source_type
835 static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type)
839 for (int i = me.Methods.Length; i > 0; ) {
842 MethodBase mb = me.Methods [i];
843 ParameterData pd = Invocation.GetParameterData (mb);
844 Type param_type = pd.ParameterType (0);
846 if (StandardConversionExists (source_type, param_type)) {
850 if (StandardConversionExists (param_type, best))
859 // Finds "most encompassing type" according to the spec (13.4.2)
860 // amongst the methods in the MethodGroupExpr which convert to a
861 // type encompassed by target_type
863 static Type FindMostEncompassingType (MethodGroupExpr me, Type target)
867 for (int i = me.Methods.Length; i > 0; ) {
870 MethodInfo mi = (MethodInfo) me.Methods [i];
871 Type ret_type = mi.ReturnType;
873 if (StandardConversionExists (ret_type, target)) {
877 if (!StandardConversionExists (ret_type, best))
889 // User-defined Implicit conversions
891 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
892 Type target, Location loc)
894 return UserDefinedConversion (ec, source, target, loc, false);
898 // User-defined Explicit conversions
900 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
901 Type target, Location loc)
903 return UserDefinedConversion (ec, source, target, loc, true);
907 // User-defined conversions
909 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
910 Type target, Location loc,
911 bool look_for_explicit)
913 Expression mg1 = null, mg2 = null, mg3 = null, mg4 = null;
914 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
916 MethodBase method = null;
917 Type source_type = source.Type;
921 // If we have a boolean type, we need to check for the True operator
923 // FIXME : How does the False operator come into the picture ?
924 // FIXME : This doesn't look complete and very correct !
925 if (target == TypeManager.bool_type)
928 op_name = "op_Implicit";
930 mg1 = MemberLookup (ec, source_type, op_name, false, loc);
932 if (source_type.BaseType != null)
933 mg2 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
935 mg3 = MemberLookup (ec, target, op_name, false, loc);
937 if (target.BaseType != null)
938 mg4 = MemberLookup (ec, target.BaseType, op_name, false, loc);
940 MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2);
941 MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4);
943 MethodGroupExpr union3 = Invocation.MakeUnionSet (union1, union2);
945 MethodGroupExpr union4 = null;
947 if (look_for_explicit) {
949 op_name = "op_Explicit";
951 mg5 = MemberLookup (ec, source_type, op_name, false, loc);
953 if (source_type.BaseType != null)
954 mg6 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
956 mg7 = MemberLookup (ec, target, op_name, false, loc);
958 if (target.BaseType != null)
959 mg8 = MemberLookup (ec, target.BaseType, op_name, false, loc);
961 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6);
962 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8);
964 union4 = Invocation.MakeUnionSet (union5, union6);
967 MethodGroupExpr union = Invocation.MakeUnionSet (union3, union4);
971 Type most_specific_source, most_specific_target;
973 most_specific_source = FindMostEncompassedType (union, source_type);
974 if (most_specific_source == null)
977 most_specific_target = FindMostEncompassingType (union, target);
978 if (most_specific_target == null)
983 for (int i = union.Methods.Length; i > 0;) {
986 MethodBase mb = union.Methods [i];
987 ParameterData pd = Invocation.GetParameterData (mb);
988 MethodInfo mi = (MethodInfo) union.Methods [i];
990 if (pd.ParameterType (0) == most_specific_source &&
991 mi.ReturnType == most_specific_target) {
997 if (method == null || count > 1) {
998 Report.Error (-11, loc, "Ambiguous user defined conversion");
1003 // This will do the conversion to the best match that we
1004 // found. Now we need to perform an implict standard conversion
1005 // if the best match was not the type that we were requested
1008 if (look_for_explicit)
1009 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1011 source = ConvertImplicitStandard (ec, source,
1012 most_specific_source, loc);
1017 e = new UserCast ((MethodInfo) method, source);
1019 if (e.Type != target){
1020 if (!look_for_explicit)
1021 e = ConvertImplicitStandard (ec, e, target, loc);
1023 e = ConvertExplicitStandard (ec, e, target, loc);
1034 // Converts implicitly the resolved expression `expr' into the
1035 // `target_type'. It returns a new expression that can be used
1036 // in a context that expects a `target_type'.
1038 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1039 Type target_type, Location loc)
1041 Type expr_type = expr.Type;
1044 if (expr_type == target_type)
1047 if (target_type == null)
1048 Console.WriteLine ("NULL");
1050 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1054 e = ImplicitReferenceConversion (expr, target_type);
1058 e = ImplicitUserConversion (ec, expr, target_type, loc);
1062 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1063 IntLiteral i = (IntLiteral) expr;
1066 return new EmptyCast (expr, target_type);
1074 // Attempts to apply the `Standard Implicit
1075 // Conversion' rules to the expression `expr' into
1076 // the `target_type'. It returns a new expression
1077 // that can be used in a context that expects a
1080 // This is different from `ConvertImplicit' in that the
1081 // user defined implicit conversions are excluded.
1083 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
1084 Type target_type, Location loc)
1086 Type expr_type = expr.Type;
1089 if (expr_type == target_type)
1092 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1096 e = ImplicitReferenceConversion (expr, target_type);
1100 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1101 IntLiteral i = (IntLiteral) expr;
1104 return new EmptyCast (expr, target_type);
1109 // Attemps to perform an implict constant conversion of the IntLiteral
1110 // into a different data type using casts (See Implicit Constant
1111 // Expression Conversions)
1113 static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il)
1115 int value = il.Value;
1117 if (target_type == TypeManager.sbyte_type){
1118 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1120 } else if (target_type == TypeManager.byte_type){
1121 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1123 } else if (target_type == TypeManager.short_type){
1124 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1126 } else if (target_type == TypeManager.ushort_type){
1127 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1129 } else if (target_type == TypeManager.uint32_type){
1131 // we can optimize this case: a positive int32
1132 // always fits on a uint32
1136 } else if (target_type == TypeManager.uint64_type){
1138 // we can optimize this case: a positive int32
1139 // always fits on a uint64. But we need an opcode
1143 return new OpcodeCast (il, target_type, OpCodes.Conv_I8);
1150 // Attemptes to implicityly convert `target' into `type', using
1151 // ConvertImplicit. If there is no implicit conversion, then
1152 // an error is signaled
1154 static public Expression ConvertImplicitRequired (EmitContext ec, Expression target,
1155 Type type, Location loc)
1159 e = ConvertImplicit (ec, target, type, loc);
1163 string msg = "Can not convert implicitly from `"+
1164 TypeManager.CSharpName (target.Type) + "' to `" +
1165 TypeManager.CSharpName (type) + "'";
1167 Error (29, loc, msg);
1173 // Performs the explicit numeric conversions
1175 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr,
1178 Type expr_type = expr.Type;
1180 if (expr_type == TypeManager.sbyte_type){
1182 // From sbyte to byte, ushort, uint, ulong, char
1184 if (target_type == TypeManager.byte_type)
1185 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1186 if (target_type == TypeManager.ushort_type)
1187 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1188 if (target_type == TypeManager.uint32_type)
1189 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1190 if (target_type == TypeManager.uint64_type)
1191 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1192 if (target_type == TypeManager.char_type)
1193 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1194 } else if (expr_type == TypeManager.byte_type){
1196 // From byte to sbyte and char
1198 if (target_type == TypeManager.sbyte_type)
1199 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1200 if (target_type == TypeManager.char_type)
1201 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1202 } else if (expr_type == TypeManager.short_type){
1204 // From short to sbyte, byte, ushort, uint, ulong, char
1206 if (target_type == TypeManager.sbyte_type)
1207 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1208 if (target_type == TypeManager.byte_type)
1209 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1210 if (target_type == TypeManager.ushort_type)
1211 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1212 if (target_type == TypeManager.uint32_type)
1213 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1214 if (target_type == TypeManager.uint64_type)
1215 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1216 if (target_type == TypeManager.char_type)
1217 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1218 } else if (expr_type == TypeManager.ushort_type){
1220 // From ushort to sbyte, byte, short, char
1222 if (target_type == TypeManager.sbyte_type)
1223 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1224 if (target_type == TypeManager.byte_type)
1225 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1226 if (target_type == TypeManager.short_type)
1227 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1228 if (target_type == TypeManager.char_type)
1229 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1230 } else if (expr_type == TypeManager.int32_type){
1232 // From int to sbyte, byte, short, ushort, uint, ulong, char
1234 if (target_type == TypeManager.sbyte_type)
1235 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1236 if (target_type == TypeManager.byte_type)
1237 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1238 if (target_type == TypeManager.short_type)
1239 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1240 if (target_type == TypeManager.ushort_type)
1241 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1242 if (target_type == TypeManager.uint32_type)
1243 return new EmptyCast (expr, target_type);
1244 if (target_type == TypeManager.uint64_type)
1245 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1246 if (target_type == TypeManager.char_type)
1247 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1248 } else if (expr_type == TypeManager.uint32_type){
1250 // From uint to sbyte, byte, short, ushort, int, char
1252 if (target_type == TypeManager.sbyte_type)
1253 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1254 if (target_type == TypeManager.byte_type)
1255 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1256 if (target_type == TypeManager.short_type)
1257 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1258 if (target_type == TypeManager.ushort_type)
1259 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1260 if (target_type == TypeManager.int32_type)
1261 return new EmptyCast (expr, target_type);
1262 if (target_type == TypeManager.char_type)
1263 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1264 } else if (expr_type == TypeManager.int64_type){
1266 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1268 if (target_type == TypeManager.sbyte_type)
1269 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1270 if (target_type == TypeManager.byte_type)
1271 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1272 if (target_type == TypeManager.short_type)
1273 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1274 if (target_type == TypeManager.ushort_type)
1275 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1276 if (target_type == TypeManager.int32_type)
1277 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1278 if (target_type == TypeManager.uint32_type)
1279 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1280 if (target_type == TypeManager.uint64_type)
1281 return new EmptyCast (expr, target_type);
1282 if (target_type == TypeManager.char_type)
1283 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1284 } else if (expr_type == TypeManager.uint64_type){
1286 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1288 if (target_type == TypeManager.sbyte_type)
1289 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1290 if (target_type == TypeManager.byte_type)
1291 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1292 if (target_type == TypeManager.short_type)
1293 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1294 if (target_type == TypeManager.ushort_type)
1295 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1296 if (target_type == TypeManager.int32_type)
1297 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1298 if (target_type == TypeManager.uint32_type)
1299 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1300 if (target_type == TypeManager.int64_type)
1301 return new EmptyCast (expr, target_type);
1302 if (target_type == TypeManager.char_type)
1303 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1304 } else if (expr_type == TypeManager.char_type){
1306 // From char to sbyte, byte, short
1308 if (target_type == TypeManager.sbyte_type)
1309 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1310 if (target_type == TypeManager.byte_type)
1311 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1312 if (target_type == TypeManager.short_type)
1313 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1314 } else if (expr_type == TypeManager.float_type){
1316 // From float to sbyte, byte, short,
1317 // ushort, int, uint, long, ulong, char
1320 if (target_type == TypeManager.sbyte_type)
1321 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1322 if (target_type == TypeManager.byte_type)
1323 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1324 if (target_type == TypeManager.short_type)
1325 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1326 if (target_type == TypeManager.ushort_type)
1327 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1328 if (target_type == TypeManager.int32_type)
1329 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1330 if (target_type == TypeManager.uint32_type)
1331 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1332 if (target_type == TypeManager.int64_type)
1333 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1334 if (target_type == TypeManager.uint64_type)
1335 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1336 if (target_type == TypeManager.char_type)
1337 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1338 if (target_type == TypeManager.decimal_type)
1339 return InternalTypeConstructor (ec, expr, target_type);
1340 } else if (expr_type == TypeManager.double_type){
1342 // From double to byte, byte, short,
1343 // ushort, int, uint, long, ulong,
1344 // char, float or decimal
1346 if (target_type == TypeManager.sbyte_type)
1347 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1348 if (target_type == TypeManager.byte_type)
1349 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1350 if (target_type == TypeManager.short_type)
1351 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1352 if (target_type == TypeManager.ushort_type)
1353 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1354 if (target_type == TypeManager.int32_type)
1355 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1356 if (target_type == TypeManager.uint32_type)
1357 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1358 if (target_type == TypeManager.int64_type)
1359 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1360 if (target_type == TypeManager.uint64_type)
1361 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1362 if (target_type == TypeManager.char_type)
1363 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1364 if (target_type == TypeManager.float_type)
1365 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
1366 if (target_type == TypeManager.decimal_type)
1367 return InternalTypeConstructor (ec, expr, target_type);
1370 // decimal is taken care of by the op_Explicit methods.
1376 // Returns whether an explicit reference conversion can be performed
1377 // from source_type to target_type
1379 static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1381 bool target_is_value_type = target_type.IsValueType;
1383 if (source_type == target_type)
1387 // From object to any reference type
1389 if (source_type == TypeManager.object_type && !target_is_value_type)
1393 // From any class S to any class-type T, provided S is a base class of T
1395 if (target_type.IsSubclassOf (source_type))
1399 // From any interface type S to any interface T provided S is not derived from T
1401 if (source_type.IsInterface && target_type.IsInterface){
1402 if (!target_type.IsSubclassOf (source_type))
1407 // From any class type S to any interface T, provides S is not sealed
1408 // and provided S does not implement T.
1410 if (target_type.IsInterface && !source_type.IsSealed &&
1411 !target_type.IsAssignableFrom (source_type))
1415 // From any interface-type S to to any class type T, provided T is not
1416 // sealed, or provided T implements S.
1418 if (source_type.IsInterface &&
1419 (!target_type.IsSealed || source_type.IsAssignableFrom (target_type)))
1422 // From an array type S with an element type Se to an array type T with an
1423 // element type Te provided all the following are true:
1424 // * S and T differe only in element type, in other words, S and T
1425 // have the same number of dimensions.
1426 // * Both Se and Te are reference types
1427 // * An explicit referenc conversions exist from Se to Te
1429 if (source_type.IsArray && target_type.IsArray) {
1430 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1432 Type source_element_type = source_type.GetElementType ();
1433 Type target_element_type = target_type.GetElementType ();
1435 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1436 if (ExplicitReferenceConversionExists (source_element_type,
1437 target_element_type))
1443 // From System.Array to any array-type
1444 if (source_type == TypeManager.array_type &&
1445 target_type.IsSubclassOf (TypeManager.array_type)){
1450 // From System delegate to any delegate-type
1452 if (source_type == TypeManager.delegate_type &&
1453 target_type.IsSubclassOf (TypeManager.delegate_type))
1457 // From ICloneable to Array or Delegate types
1459 if (source_type == TypeManager.icloneable_type &&
1460 (target_type == TypeManager.array_type ||
1461 target_type == TypeManager.delegate_type))
1468 // Implements Explicit Reference conversions
1470 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
1472 Type source_type = source.Type;
1473 bool target_is_value_type = target_type.IsValueType;
1476 // From object to any reference type
1478 if (source_type == TypeManager.object_type && !target_is_value_type)
1479 return new ClassCast (source, target_type);
1483 // From any class S to any class-type T, provided S is a base class of T
1485 if (target_type.IsSubclassOf (source_type))
1486 return new ClassCast (source, target_type);
1489 // From any interface type S to any interface T provided S is not derived from T
1491 if (source_type.IsInterface && target_type.IsInterface){
1493 Type [] ifaces = source_type.GetInterfaces ();
1495 if (TypeManager.ImplementsInterface (source_type, target_type))
1498 return new ClassCast (source, target_type);
1502 // From any class type S to any interface T, provides S is not sealed
1503 // and provided S does not implement T.
1505 if (target_type.IsInterface && !source_type.IsSealed) {
1507 if (TypeManager.ImplementsInterface (source_type, target_type))
1510 return new ClassCast (source, target_type);
1515 // From any interface-type S to to any class type T, provided T is not
1516 // sealed, or provided T implements S.
1518 if (source_type.IsInterface) {
1520 if (target_type.IsSealed)
1523 if (TypeManager.ImplementsInterface (target_type, source_type))
1524 return new ClassCast (source, target_type);
1529 // From an array type S with an element type Se to an array type T with an
1530 // element type Te provided all the following are true:
1531 // * S and T differe only in element type, in other words, S and T
1532 // have the same number of dimensions.
1533 // * Both Se and Te are reference types
1534 // * An explicit referenc conversions exist from Se to Te
1536 if (source_type.IsArray && target_type.IsArray) {
1537 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1539 Type source_element_type = source_type.GetElementType ();
1540 Type target_element_type = target_type.GetElementType ();
1542 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1543 if (ExplicitReferenceConversionExists (source_element_type,
1544 target_element_type))
1545 return new ClassCast (source, target_type);
1550 // From System.Array to any array-type
1551 if (source_type == TypeManager.array_type &&
1552 target_type.IsSubclassOf (TypeManager.array_type)){
1553 return new ClassCast (source, target_type);
1557 // From System delegate to any delegate-type
1559 if (source_type == TypeManager.delegate_type &&
1560 target_type.IsSubclassOf (TypeManager.delegate_type))
1561 return new ClassCast (source, target_type);
1564 // From ICloneable to Array or Delegate types
1566 if (source_type == TypeManager.icloneable_type &&
1567 (target_type == TypeManager.array_type ||
1568 target_type == TypeManager.delegate_type))
1569 return new ClassCast (source, target_type);
1575 // Performs an explicit conversion of the expression `expr' whose
1576 // type is expr.Type to `target_type'.
1578 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
1579 Type target_type, Location loc)
1581 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
1586 ne = ConvertNumericExplicit (ec, expr, target_type);
1590 ne = ConvertReferenceExplicit (expr, target_type);
1594 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1598 error30 (loc, expr.Type, target_type);
1603 // Same as ConverExplicit, only it doesn't include user defined conversions
1605 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
1606 Type target_type, Location l)
1608 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
1613 ne = ConvertNumericExplicit (ec, expr, target_type);
1617 ne = ConvertReferenceExplicit (expr, target_type);
1621 error30 (l, expr.Type, target_type);
1625 static string ExprClassName (ExprClass c)
1628 case ExprClass.Invalid:
1630 case ExprClass.Value:
1632 case ExprClass.Variable:
1634 case ExprClass.Namespace:
1636 case ExprClass.Type:
1638 case ExprClass.MethodGroup:
1639 return "method group";
1640 case ExprClass.PropertyAccess:
1641 return "property access";
1642 case ExprClass.EventAccess:
1643 return "event access";
1644 case ExprClass.IndexerAccess:
1645 return "indexer access";
1646 case ExprClass.Nothing:
1649 throw new Exception ("Should not happen");
1653 // Reports that we were expecting `expr' to be of class `expected'
1655 protected void report118 (Location loc, Expression expr, string expected)
1657 string kind = "Unknown";
1660 kind = ExprClassName (expr.ExprClass);
1662 Error (118, loc, "Expression denotes a '" + kind +
1663 "' where an " + expected + " was expected");
1667 // This function tries to reduce the expression performing
1668 // constant folding and common subexpression elimination
1670 static public Expression Reduce (EmitContext ec, Expression e)
1672 //Console.WriteLine ("Calling reduce");
1673 return e.Reduce (ec);
1678 // This is just a base class for expressions that can
1679 // appear on statements (invocations, object creation,
1680 // assignments, post/pre increment and decrement). The idea
1681 // being that they would support an extra Emition interface that
1682 // does not leave a result on the stack.
1685 public abstract class ExpressionStatement : Expression {
1688 // Requests the expression to be emitted in a `statement'
1689 // context. This means that no new value is left on the
1690 // stack after invoking this method (constrasted with
1691 // Emit that will always leave a value on the stack).
1693 public abstract void EmitStatement (EmitContext ec);
1697 // This kind of cast is used to encapsulate the child
1698 // whose type is child.Type into an expression that is
1699 // reported to return "return_type". This is used to encapsulate
1700 // expressions which have compatible types, but need to be dealt
1701 // at higher levels with.
1703 // For example, a "byte" expression could be encapsulated in one
1704 // of these as an "unsigned int". The type for the expression
1705 // would be "unsigned int".
1709 public class EmptyCast : Expression {
1710 protected Expression child;
1712 public EmptyCast (Expression child, Type return_type)
1714 ExprClass = child.ExprClass;
1719 public override Expression DoResolve (EmitContext ec)
1721 // This should never be invoked, we are born in fully
1722 // initialized state.
1727 public override void Emit (EmitContext ec)
1735 // This class is used to wrap literals which belong inside Enums
1738 public class EnumLiteral : Literal {
1741 public EnumLiteral (Expression child, Type enum_type)
1743 ExprClass = child.ExprClass;
1748 public override Expression DoResolve (EmitContext ec)
1750 // This should never be invoked, we are born in fully
1751 // initialized state.
1756 public override void Emit (EmitContext ec)
1761 public override object GetValue ()
1763 return ((Literal) child).GetValue ();
1766 public override string AsString ()
1768 return ((Literal) child).AsString ();
1773 // This kind of cast is used to encapsulate Value Types in objects.
1775 // The effect of it is to box the value type emitted by the previous
1778 public class BoxedCast : EmptyCast {
1780 public BoxedCast (Expression expr)
1781 : base (expr, TypeManager.object_type)
1785 public override Expression DoResolve (EmitContext ec)
1787 // This should never be invoked, we are born in fully
1788 // initialized state.
1793 public override void Emit (EmitContext ec)
1796 ec.ig.Emit (OpCodes.Box, child.Type);
1801 // This kind of cast is used to encapsulate a child expression
1802 // that can be trivially converted to a target type using one or
1803 // two opcodes. The opcodes are passed as arguments.
1805 public class OpcodeCast : EmptyCast {
1809 public OpcodeCast (Expression child, Type return_type, OpCode op)
1810 : base (child, return_type)
1814 second_valid = false;
1817 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1818 : base (child, return_type)
1823 second_valid = true;
1826 public override Expression DoResolve (EmitContext ec)
1828 // This should never be invoked, we are born in fully
1829 // initialized state.
1834 public override void Emit (EmitContext ec)
1846 // This kind of cast is used to encapsulate a child and cast it
1847 // to the class requested
1849 public class ClassCast : EmptyCast {
1850 public ClassCast (Expression child, Type return_type)
1851 : base (child, return_type)
1856 public override Expression DoResolve (EmitContext ec)
1858 // This should never be invoked, we are born in fully
1859 // initialized state.
1864 public override void Emit (EmitContext ec)
1868 ec.ig.Emit (OpCodes.Castclass, type);
1874 // SimpleName expressions are initially formed of a single
1875 // word and it only happens at the beginning of the expression.
1877 // The expression will try to be bound to a Field, a Method
1878 // group or a Property. If those fail we pass the name to our
1879 // caller and the SimpleName is compounded to perform a type
1880 // lookup. The idea behind this process is that we want to avoid
1881 // creating a namespace map from the assemblies, as that requires
1882 // the GetExportedTypes function to be called and a hashtable to
1883 // be constructed which reduces startup time. If later we find
1884 // that this is slower, we should create a `NamespaceExpr' expression
1885 // that fully participates in the resolution process.
1887 // For example `System.Console.WriteLine' is decomposed into
1888 // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
1890 // The first SimpleName wont produce a match on its own, so it will
1892 // MemberAccess (SimpleName ("System.Console"), "WriteLine").
1894 // System.Console will produce a TypeExpr match.
1896 // The downside of this is that we might be hitting `LookupType' too many
1897 // times with this scheme.
1899 public class SimpleName : Expression {
1900 public readonly string Name;
1901 public readonly Location Location;
1903 public SimpleName (string name, Location l)
1909 public static void Error120 (Location l, string name)
1913 "An object reference is required " +
1914 "for the non-static field `"+name+"'");
1918 // Checks whether we are trying to access an instance
1919 // property, method or field from a static body.
1921 Expression MemberStaticCheck (Expression e)
1923 if (e is FieldExpr){
1924 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1927 Error120 (Location, Name);
1930 } else if (e is MethodGroupExpr){
1931 MethodGroupExpr mg = (MethodGroupExpr) e;
1933 if (!mg.RemoveInstanceMethods ()){
1934 Error120 (Location, mg.Methods [0].Name);
1938 } else if (e is PropertyExpr){
1939 if (!((PropertyExpr) e).IsStatic){
1940 Error120 (Location, Name);
1949 // 7.5.2: Simple Names.
1951 // Local Variables and Parameters are handled at
1952 // parse time, so they never occur as SimpleNames.
1954 public override Expression DoResolve (EmitContext ec)
1959 // Stage 1: Performed by the parser (binding to local or parameters).
1963 // Stage 2: Lookup members
1965 e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true, Location);
1968 // Stage 3: Lookup symbol in the various namespaces.
1972 if ((t = ec.TypeContainer.LookupType (Name, true)) != null)
1973 return new TypeExpr (t);
1976 // Stage 3 part b: Lookup up if we are an alias to a type
1979 // Since we are cheating: we only do the Alias lookup for
1980 // namespaces if the name does not include any dots in it
1983 // IMPLEMENT ME. Read mcs/mcs/TODO for ideas, or rewrite
1984 // using NamespaceExprs (dunno how that fixes the alias
1985 // per-file though).
1987 // No match, maybe our parent can compose us
1988 // into something meaningful.
1993 // Step 2, continues here.
1997 if (e is FieldExpr){
1998 FieldExpr fe = (FieldExpr) e;
2000 if (!fe.FieldInfo.IsStatic)
2001 fe.InstanceExpression = new This (Location.Null);
2005 return MemberStaticCheck (e);
2010 public override void Emit (EmitContext ec)
2013 // If this is ever reached, then we failed to
2014 // find the name as a namespace
2017 Error (103, Location, "The name `" + Name +
2018 "' does not exist in the class `" +
2019 ec.TypeContainer.Name + "'");
2024 // Fully resolved expression that evaluates to a type
2026 public class TypeExpr : Expression {
2027 public TypeExpr (Type t)
2030 eclass = ExprClass.Type;
2033 override public Expression DoResolve (EmitContext ec)
2038 override public void Emit (EmitContext ec)
2040 throw new Exception ("Implement me");
2045 // MethodGroup Expression.
2047 // This is a fully resolved expression that evaluates to a type
2049 public class MethodGroupExpr : Expression {
2050 public MethodBase [] Methods;
2051 Expression instance_expression = null;
2053 public MethodGroupExpr (MemberInfo [] mi)
2055 Methods = new MethodBase [mi.Length];
2056 mi.CopyTo (Methods, 0);
2057 eclass = ExprClass.MethodGroup;
2060 public MethodGroupExpr (ArrayList l)
2062 Methods = new MethodBase [l.Count];
2064 l.CopyTo (Methods, 0);
2065 eclass = ExprClass.MethodGroup;
2069 // `A method group may have associated an instance expression'
2071 public Expression InstanceExpression {
2073 return instance_expression;
2077 instance_expression = value;
2081 override public Expression DoResolve (EmitContext ec)
2086 override public void Emit (EmitContext ec)
2088 throw new Exception ("This should never be reached");
2091 bool RemoveMethods (bool keep_static)
2093 ArrayList smethods = new ArrayList ();
2094 int top = Methods.Length;
2097 for (i = 0; i < top; i++){
2098 MethodBase mb = Methods [i];
2100 if (mb.IsStatic == keep_static)
2104 if (smethods.Count == 0)
2107 Methods = new MethodBase [smethods.Count];
2108 smethods.CopyTo (Methods, 0);
2114 // Removes any instance methods from the MethodGroup, returns
2115 // false if the resulting set is empty.
2117 public bool RemoveInstanceMethods ()
2119 return RemoveMethods (true);
2123 // Removes any static methods from the MethodGroup, returns
2124 // false if the resulting set is empty.
2126 public bool RemoveStaticMethods ()
2128 return RemoveMethods (false);
2133 // Fully resolved expression that evaluates to a Field
2135 public class FieldExpr : Expression, IAssignMethod, IMemoryLocation {
2136 public readonly FieldInfo FieldInfo;
2137 public Expression InstanceExpression;
2140 public FieldExpr (FieldInfo fi, Location l)
2143 eclass = ExprClass.Variable;
2144 type = fi.FieldType;
2148 override public Expression DoResolve (EmitContext ec)
2150 if (!FieldInfo.IsStatic){
2151 if (InstanceExpression == null){
2152 throw new Exception ("non-static FieldExpr without instance var\n" +
2153 "You have to assign the Instance variable\n" +
2154 "Of the FieldExpr to set this\n");
2157 InstanceExpression = InstanceExpression.Resolve (ec);
2158 if (InstanceExpression == null)
2165 public Expression DoResolveLValue (EmitContext ec)
2167 if (!FieldInfo.IsInitOnly)
2171 // InitOnly fields can only be assigned in constructors
2174 if (ec.IsConstructor)
2177 Report.Error (191, loc,
2178 "Readonly field can not be assigned outside " +
2179 "of constructor or variable initializer");
2184 override public void Emit (EmitContext ec)
2186 ILGenerator ig = ec.ig;
2188 if (FieldInfo.IsStatic)
2189 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2191 InstanceExpression.Emit (ec);
2193 ig.Emit (OpCodes.Ldfld, FieldInfo);
2197 public void EmitAssign (EmitContext ec, Expression source)
2199 bool is_static = FieldInfo.IsStatic;
2202 InstanceExpression.Emit (ec);
2206 ec.ig.Emit (OpCodes.Stsfld, FieldInfo);
2208 ec.ig.Emit (OpCodes.Stfld, FieldInfo);
2212 public void AddressOf (EmitContext ec)
2214 if (FieldInfo.IsStatic)
2215 ec.ig.Emit (OpCodes.Ldsflda, FieldInfo);
2217 InstanceExpression.Emit (ec);
2218 ec.ig.Emit (OpCodes.Ldflda, FieldInfo);
2224 // Expression that evaluates to a Property. The Assign class
2225 // might set the `Value' expression if we are in an assignment.
2227 // This is not an LValue because we need to re-write the expression, we
2228 // can not take data from the stack and store it.
2230 public class PropertyExpr : ExpressionStatement, IAssignMethod {
2231 public readonly PropertyInfo PropertyInfo;
2232 public readonly bool IsStatic;
2233 MethodInfo [] Accessors;
2236 Expression instance_expr;
2238 public PropertyExpr (PropertyInfo pi, Location l)
2241 eclass = ExprClass.PropertyAccess;
2244 Accessors = TypeManager.GetAccessors (pi);
2246 if (Accessors != null)
2247 for (int i = 0; i < Accessors.Length; i++){
2248 if (Accessors [i] != null)
2249 if (Accessors [i].IsStatic)
2253 Accessors = new MethodInfo [2];
2255 type = pi.PropertyType;
2259 // The instance expression associated with this expression
2261 public Expression InstanceExpression {
2263 instance_expr = value;
2267 return instance_expr;
2271 public bool VerifyAssignable ()
2273 if (!PropertyInfo.CanWrite){
2274 Report.Error (200, loc,
2275 "The property `" + PropertyInfo.Name +
2276 "' can not be assigned to, as it has not set accessor");
2283 override public Expression DoResolve (EmitContext ec)
2285 if (!PropertyInfo.CanRead){
2286 Report.Error (154, loc,
2287 "The property `" + PropertyInfo.Name +
2288 "' can not be used in " +
2289 "this context because it lacks a get accessor");
2296 override public void Emit (EmitContext ec)
2298 Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null);
2303 // Implements the IAssignMethod interface for assignments
2305 public void EmitAssign (EmitContext ec, Expression source)
2307 Argument arg = new Argument (source, Argument.AType.Expression);
2308 ArrayList args = new ArrayList ();
2311 Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args);
2314 override public void EmitStatement (EmitContext ec)
2317 ec.ig.Emit (OpCodes.Pop);
2322 // Fully resolved expression that evaluates to a Expression
2324 public class EventExpr : Expression {
2325 public readonly EventInfo EventInfo;
2328 public EventExpr (EventInfo ei, Location loc)
2332 eclass = ExprClass.EventAccess;
2335 override public Expression DoResolve (EmitContext ec)
2337 // We are born in resolved state.
2341 override public void Emit (EmitContext ec)
2343 throw new Exception ("Implement me");
2344 // FIXME: Implement.