2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
11 namespace Mono.CSharp {
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 is used to tell Resolve in which types of expressions we're
44 public enum ResolveFlags {
45 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
48 // Returns a type expression.
51 // Returns a method group.
54 // Mask of all the expression class flags.
57 // Disable control flow analysis while resolving the expression.
58 // This is used when resolving the instance expression of a field expression.
59 DisableFlowAnalysis = 8,
61 // Set if this is resolving the first part of a MemberAccess.
64 // Disable control flow analysis _of struct_ while resolving the expression.
65 // This is used when resolving the instance expression of a field expression.
66 DisableStructFlowAnalysis = 32,
71 // This is just as a hint to AddressOf of what will be done with the
74 public enum AddressOp {
81 /// This interface is implemented by variables
83 public interface IMemoryLocation {
85 /// The AddressOf method should generate code that loads
86 /// the address of the object and leaves it on the stack.
88 /// The `mode' argument is used to notify the expression
89 /// of whether this will be used to read from the address or
90 /// write to the address.
92 /// This is just a hint that can be used to provide good error
93 /// reporting, and should have no other side effects.
95 void AddressOf (EmitContext ec, AddressOp mode);
99 /// This interface is implemented by variables
101 public interface IVariable {
102 VariableInfo VariableInfo {
110 /// Base class for expressions
112 public abstract class Expression {
113 public ExprClass eclass;
115 protected Location loc;
119 set { type = value; }
122 public virtual Location Location {
127 /// Utility wrapper routine for Error, just to beautify the code
129 public void Error (int error, string s)
132 Report.Error (error, s);
134 Report.Error (error, loc, s);
137 // Not nice but we have broken hierarchy
138 public virtual void CheckMarshallByRefAccess (Type container) {}
140 public virtual string GetSignatureForError ()
142 return TypeManager.CSharpName (type);
145 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
147 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
149 must_do_cs1540_check = false; // by default we do not check for this
151 if (ma == MethodAttributes.Public)
155 // If only accessible to the current class or children
157 if (ma == MethodAttributes.Private)
158 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
159 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
161 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
162 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
163 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
166 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
170 // Family and FamANDAssem require that we derive.
171 // FamORAssem requires that we derive if in different assemblies.
172 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
175 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
176 must_do_cs1540_check = true;
182 /// Performs semantic analysis on the Expression
186 /// The Resolve method is invoked to perform the semantic analysis
189 /// The return value is an expression (it can be the
190 /// same expression in some cases) or a new
191 /// expression that better represents this node.
193 /// For example, optimizations of Unary (LiteralInt)
194 /// would return a new LiteralInt with a negated
197 /// If there is an error during semantic analysis,
198 /// then an error should be reported (using Report)
199 /// and a null value should be returned.
201 /// There are two side effects expected from calling
202 /// Resolve(): the the field variable "eclass" should
203 /// be set to any value of the enumeration
204 /// `ExprClass' and the type variable should be set
205 /// to a valid type (this is the type of the
208 public abstract Expression DoResolve (EmitContext ec);
210 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
216 // This is used if the expression should be resolved as a type or namespace name.
217 // the default implementation fails.
219 public FullNamedExpression ResolveAsTypeStep (EmitContext ec)
221 return ResolveAsTypeStep (ec, false);
224 public virtual FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
230 // This is used to resolve the expression as a type, a null
231 // value will be returned if the expression is not a type
234 public TypeExpr ResolveAsTypeTerminal (EmitContext ec)
236 return ResolveAsTypeTerminal (ec, false);
239 public virtual TypeExpr ResolveAsTypeTerminal (EmitContext ec, bool silent)
241 int errors = Report.Errors;
243 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
246 if (!silent && errors == Report.Errors)
247 Report.Error (118, loc, "Expecting a type.");
251 if (fne.eclass != ExprClass.Type) {
252 if (!silent && (errors == Report.Errors))
253 fne.Error_UnexpectedKind (null, "type", loc);
257 TypeExpr te = fne as TypeExpr;
259 if (!te.CheckAccessLevel (ec.DeclSpace)) {
260 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
264 ConstructedType ct = te as ConstructedType;
265 if ((ct != null) && !ec.ResolvingTypeTree && !ec.ResolvingGenericMethod &&
266 !ct.CheckConstraints (ec))
273 public static void ErrorIsInaccesible (Location loc, string name)
275 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
278 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
280 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
281 + " the qualifier must be of type `{2}' (or derived from it)",
282 TypeManager.GetFullNameSignature (m),
283 TypeManager.CSharpName (qualifier),
284 TypeManager.CSharpName (container));
288 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
290 if (Type.Name == target.Name){
291 Report.ExtraInformation (loc,
293 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
294 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
299 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
300 GetSignatureForError (), TypeManager.CSharpName (target));
304 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
305 bool b = Convert.ExplicitNumericConversion (e, target) != null;
307 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
308 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
309 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
313 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
314 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
315 GetSignatureForError (), TypeManager.CSharpName (target));
319 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
320 Type == TypeManager.anonymous_method_type ?
321 "anonymous method" : "`" + GetSignatureForError () + "'",
322 TypeManager.CSharpName (target));
325 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
327 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
328 TypeManager.CSharpName (type), name);
331 ResolveFlags ExprClassToResolveFlags ()
335 case ExprClass.Namespace:
336 return ResolveFlags.Type;
338 case ExprClass.MethodGroup:
339 return ResolveFlags.MethodGroup;
341 case ExprClass.Value:
342 case ExprClass.Variable:
343 case ExprClass.PropertyAccess:
344 case ExprClass.EventAccess:
345 case ExprClass.IndexerAccess:
346 return ResolveFlags.VariableOrValue;
349 throw new Exception ("Expression " + GetType () +
350 " ExprClass is Invalid after resolve");
356 /// Resolves an expression and performs semantic analysis on it.
360 /// Currently Resolve wraps DoResolve to perform sanity
361 /// checking and assertion checking on what we expect from Resolve.
363 public Expression Resolve (EmitContext ec, ResolveFlags flags)
365 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
366 return ResolveAsTypeStep (ec, false);
368 bool old_do_flow_analysis = ec.DoFlowAnalysis;
369 bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis;
370 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
371 ec.DoFlowAnalysis = false;
372 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
373 ec.OmitStructFlowAnalysis = true;
376 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
377 if (this is SimpleName)
378 e = ((SimpleName) this).DoResolve (ec, intermediate);
383 ec.DoFlowAnalysis = old_do_flow_analysis;
384 ec.OmitStructFlowAnalysis = old_omit_struct_analysis;
389 if ((flags & e.ExprClassToResolveFlags ()) == 0) {
390 e.Error_UnexpectedKind (flags, loc);
394 if (e.type == null && !(e is Namespace)) {
395 throw new Exception (
396 "Expression " + e.GetType () +
397 " did not set its type after Resolve\n" +
398 "called from: " + this.GetType ());
405 /// Resolves an expression and performs semantic analysis on it.
407 public Expression Resolve (EmitContext ec)
409 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
411 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
412 ((MethodGroupExpr) e).ReportUsageError ();
418 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
420 Expression e = Resolve (ec);
424 Constant c = e as Constant;
428 EmptyCast empty = e as EmptyCast;
430 c = empty.Child as Constant;
432 // TODO: not sure about this maybe there is easier way how to use EmptyCast
439 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
444 /// Resolves an expression for LValue assignment
448 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
449 /// checking and assertion checking on what we expect from Resolve
451 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
453 int errors = Report.Errors;
454 Expression e = DoResolveLValue (ec, right_side);
457 if (errors == Report.Errors)
458 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
463 if (e.eclass == ExprClass.Invalid)
464 throw new Exception ("Expression " + e +
465 " ExprClass is Invalid after resolve");
467 if (e.eclass == ExprClass.MethodGroup) {
468 ((MethodGroupExpr) e).ReportUsageError ();
472 if ((e.type == null) && !(e is ConstructedType))
473 throw new Exception ("Expression " + e +
474 " did not set its type after Resolve");
481 /// Emits the code for the expression
485 /// The Emit method is invoked to generate the code
486 /// for the expression.
488 public abstract void Emit (EmitContext ec);
490 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
493 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
497 /// Protected constructor. Only derivate types should
498 /// be able to be created
501 protected Expression ()
503 eclass = ExprClass.Invalid;
508 /// Returns a literalized version of a literal FieldInfo
512 /// The possible return values are:
513 /// IntConstant, UIntConstant
514 /// LongLiteral, ULongConstant
515 /// FloatConstant, DoubleConstant
518 /// The value returned is already resolved.
520 public static Constant Constantify (object v, Type t)
522 if (t == TypeManager.int32_type)
523 return new IntConstant ((int) v, Location.Null);
524 else if (t == TypeManager.uint32_type)
525 return new UIntConstant ((uint) v, Location.Null);
526 else if (t == TypeManager.int64_type)
527 return new LongConstant ((long) v, Location.Null);
528 else if (t == TypeManager.uint64_type)
529 return new ULongConstant ((ulong) v, Location.Null);
530 else if (t == TypeManager.float_type)
531 return new FloatConstant ((float) v, Location.Null);
532 else if (t == TypeManager.double_type)
533 return new DoubleConstant ((double) v, Location.Null);
534 else if (t == TypeManager.string_type)
535 return new StringConstant ((string) v, Location.Null);
536 else if (t == TypeManager.short_type)
537 return new ShortConstant ((short)v, Location.Null);
538 else if (t == TypeManager.ushort_type)
539 return new UShortConstant ((ushort)v, Location.Null);
540 else if (t == TypeManager.sbyte_type)
541 return new SByteConstant ((sbyte)v, Location.Null);
542 else if (t == TypeManager.byte_type)
543 return new ByteConstant ((byte)v, Location.Null);
544 else if (t == TypeManager.char_type)
545 return new CharConstant ((char)v, Location.Null);
546 else if (t == TypeManager.bool_type)
547 return new BoolConstant ((bool) v, Location.Null);
548 else if (t == TypeManager.decimal_type)
549 return new DecimalConstant ((decimal) v, Location.Null);
550 else if (TypeManager.IsEnumType (t)){
551 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
553 real_type = System.Enum.GetUnderlyingType (real_type);
555 Constant e = Constantify (v, real_type);
557 return new EnumConstant (e, t);
558 } else if (v == null && !TypeManager.IsValueType (t))
559 return new NullLiteral (Location.Null);
561 throw new Exception ("Unknown type for constant (" + t +
566 /// Returns a fully formed expression after a MemberLookup
569 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
572 return new EventExpr ((EventInfo) mi, loc);
573 else if (mi is FieldInfo)
574 return new FieldExpr ((FieldInfo) mi, loc);
575 else if (mi is PropertyInfo)
576 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
577 else if (mi is Type){
578 return new TypeExpression ((System.Type) mi, loc);
584 protected static ArrayList almostMatchedMembers = new ArrayList (4);
587 // FIXME: Probably implement a cache for (t,name,current_access_set)?
589 // This code could use some optimizations, but we need to do some
590 // measurements. For example, we could use a delegate to `flag' when
591 // something can not any longer be a method-group (because it is something
595 // If the return value is an Array, then it is an array of
598 // If the return value is an MemberInfo, it is anything, but a Method
602 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
603 // the arguments here and have MemberLookup return only the methods that
604 // match the argument count/type, unlike we are doing now (we delay this
607 // This is so we can catch correctly attempts to invoke instance methods
608 // from a static body (scan for error 120 in ResolveSimpleName).
611 // FIXME: Potential optimization, have a static ArrayList
614 public static Expression MemberLookup (EmitContext ec, Type queried_type, string name,
615 MemberTypes mt, BindingFlags bf, Location loc)
617 return MemberLookup (ec, ec.ContainerType, null, queried_type, name, mt, bf, loc);
621 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
622 // `qualifier_type' or null to lookup members in the current class.
625 public static Expression MemberLookup (EmitContext ec, Type container_type,
626 Type qualifier_type, Type queried_type,
627 string name, MemberTypes mt,
628 BindingFlags bf, Location loc)
630 almostMatchedMembers.Clear ();
632 MemberInfo [] mi = TypeManager.MemberLookup (
633 container_type, qualifier_type, queried_type, mt, bf, name,
634 almostMatchedMembers);
639 int count = mi.Length;
641 if (mi [0] is MethodBase)
642 return new MethodGroupExpr (mi, loc);
647 return ExprClassFromMemberInfo (ec, mi [0], loc);
650 public const MemberTypes AllMemberTypes =
651 MemberTypes.Constructor |
655 MemberTypes.NestedType |
656 MemberTypes.Property;
658 public const BindingFlags AllBindingFlags =
659 BindingFlags.Public |
660 BindingFlags.Static |
661 BindingFlags.Instance;
663 public static Expression MemberLookup (EmitContext ec, Type queried_type,
664 string name, Location loc)
666 return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
667 AllMemberTypes, AllBindingFlags, loc);
670 public static Expression MemberLookup (EmitContext ec, Type qualifier_type,
671 Type queried_type, string name, Location loc)
673 if (ec.ResolvingTypeTree)
674 return MemberLookup (ec, ec.ContainerType, qualifier_type,
675 queried_type, name, MemberTypes.NestedType,
676 AllBindingFlags, loc);
678 return MemberLookup (ec, ec.ContainerType, qualifier_type,
679 queried_type, name, AllMemberTypes,
680 AllBindingFlags, loc);
683 public static Expression MethodLookup (EmitContext ec, Type queried_type,
684 string name, Location loc)
686 return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
687 MemberTypes.Method, AllBindingFlags, loc);
691 /// This is a wrapper for MemberLookup that is not used to "probe", but
692 /// to find a final definition. If the final definition is not found, we
693 /// look for private members and display a useful debugging message if we
696 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
697 Type queried_type, string name,
700 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
701 AllMemberTypes, AllBindingFlags, loc);
704 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
705 Type queried_type, string name,
706 MemberTypes mt, BindingFlags bf,
711 int errors = Report.Errors;
713 e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
716 if (e == null && errors == Report.Errors)
717 // No errors were reported by MemberLookup, but there was an error.
718 MemberLookupFailed (ec, qualifier_type, queried_type, name, null, true, loc);
723 public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
724 Type queried_type, string name,
725 string class_name, bool complain_if_none_found,
728 if (almostMatchedMembers.Count != 0) {
729 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
730 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
731 for (int j = 0; j < i; ++j) {
732 if (m == almostMatchedMembers [j]) {
740 Type declaring_type = m.DeclaringType;
742 Report.SymbolRelatedToPreviousError (m);
743 if (qualifier_type == null) {
744 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
745 TypeManager.CSharpName (m.DeclaringType),
746 TypeManager.CSharpName (ec.ContainerType));
747 } else if (qualifier_type != ec.ContainerType &&
748 TypeManager.IsNestedFamilyAccessible (ec.ContainerType, declaring_type)) {
749 // Although a derived class can access protected members of
750 // its base class it cannot do so through an instance of the
751 // base class (CS1540). If the qualifier_type is a base of the
752 // ec.ContainerType and the lookup succeeds with the latter one,
753 // then we are in this situation.
754 Error_CannotAccessProtected (loc, m, qualifier_type, ec.ContainerType);
756 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
759 almostMatchedMembers.Clear ();
763 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
764 AllMemberTypes, AllBindingFlags |
765 BindingFlags.NonPublic, name, null);
767 if (lookup == null) {
768 if (!complain_if_none_found)
771 if (class_name != null)
772 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
775 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
779 if (TypeManager.MemberLookup (queried_type, null, queried_type,
780 AllMemberTypes, AllBindingFlags |
781 BindingFlags.NonPublic, name, null) == null) {
782 if ((lookup.Length == 1) && (lookup [0] is Type)) {
783 Type t = (Type) lookup [0];
785 Report.Error (305, loc,
786 "Using the generic type `{0}' " +
787 "requires {1} type arguments",
788 TypeManager.CSharpName (t),
789 TypeManager.GetNumberOfTypeArguments (t).ToString ());
794 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
795 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
796 if (name == ".ctor" && ml.Count == 0)
798 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
802 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
806 /// Returns an expression that can be used to invoke operator true
807 /// on the expression if it exists.
809 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
811 return GetOperatorTrueOrFalse (ec, e, true, loc);
815 /// Returns an expression that can be used to invoke operator false
816 /// on the expression if it exists.
818 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
820 return GetOperatorTrueOrFalse (ec, e, false, loc);
823 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
826 Expression operator_group;
828 if (TypeManager.IsNullableType (e.Type))
829 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
831 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
832 if (operator_group == null)
835 ArrayList arguments = new ArrayList ();
836 arguments.Add (new Argument (e, Argument.AType.Expression));
837 method = Invocation.OverloadResolve (
838 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
843 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
847 /// Resolves the expression `e' into a boolean expression: either through
848 /// an implicit conversion, or through an `operator true' invocation
850 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
856 if (e.Type == TypeManager.bool_type)
859 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
861 if (converted != null)
865 // If no implicit conversion to bool exists, try using `operator true'
867 converted = Expression.GetOperatorTrue (ec, e, loc);
868 if (converted == null){
869 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
875 public virtual string ExprClassName
879 case ExprClass.Invalid:
881 case ExprClass.Value:
883 case ExprClass.Variable:
885 case ExprClass.Namespace:
889 case ExprClass.MethodGroup:
890 return "method group";
891 case ExprClass.PropertyAccess:
892 return "property access";
893 case ExprClass.EventAccess:
894 return "event access";
895 case ExprClass.IndexerAccess:
896 return "indexer access";
897 case ExprClass.Nothing:
900 throw new Exception ("Should not happen");
905 /// Reports that we were expecting `expr' to be of class `expected'
907 public void Error_UnexpectedKind (EmitContext ec, string expected, Location loc)
909 Error_UnexpectedKind (ec, expected, ExprClassName, loc);
912 public void Error_UnexpectedKind (EmitContext ec, string expected, string was, Location loc)
914 string name = GetSignatureForError ();
916 name = ec.DeclSpace.GetSignatureForError () + '.' + name;
918 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
919 name, was, expected);
922 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
924 string [] valid = new string [4];
927 if ((flags & ResolveFlags.VariableOrValue) != 0) {
928 valid [count++] = "variable";
929 valid [count++] = "value";
932 if ((flags & ResolveFlags.Type) != 0)
933 valid [count++] = "type";
935 if ((flags & ResolveFlags.MethodGroup) != 0)
936 valid [count++] = "method group";
939 valid [count++] = "unknown";
941 StringBuilder sb = new StringBuilder (valid [0]);
942 for (int i = 1; i < count - 1; i++) {
944 sb.Append (valid [i]);
947 sb.Append ("' or `");
948 sb.Append (valid [count - 1]);
951 Report.Error (119, loc,
952 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
955 public static void UnsafeError (Location loc)
957 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
961 // Load the object from the pointer.
963 public static void LoadFromPtr (ILGenerator ig, Type t)
965 if (t == TypeManager.int32_type)
966 ig.Emit (OpCodes.Ldind_I4);
967 else if (t == TypeManager.uint32_type)
968 ig.Emit (OpCodes.Ldind_U4);
969 else if (t == TypeManager.short_type)
970 ig.Emit (OpCodes.Ldind_I2);
971 else if (t == TypeManager.ushort_type)
972 ig.Emit (OpCodes.Ldind_U2);
973 else if (t == TypeManager.char_type)
974 ig.Emit (OpCodes.Ldind_U2);
975 else if (t == TypeManager.byte_type)
976 ig.Emit (OpCodes.Ldind_U1);
977 else if (t == TypeManager.sbyte_type)
978 ig.Emit (OpCodes.Ldind_I1);
979 else if (t == TypeManager.uint64_type)
980 ig.Emit (OpCodes.Ldind_I8);
981 else if (t == TypeManager.int64_type)
982 ig.Emit (OpCodes.Ldind_I8);
983 else if (t == TypeManager.float_type)
984 ig.Emit (OpCodes.Ldind_R4);
985 else if (t == TypeManager.double_type)
986 ig.Emit (OpCodes.Ldind_R8);
987 else if (t == TypeManager.bool_type)
988 ig.Emit (OpCodes.Ldind_I1);
989 else if (t == TypeManager.intptr_type)
990 ig.Emit (OpCodes.Ldind_I);
991 else if (TypeManager.IsEnumType (t)) {
992 if (t == TypeManager.enum_type)
993 ig.Emit (OpCodes.Ldind_Ref);
995 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
996 } else if (t.IsValueType || t.IsGenericParameter)
997 ig.Emit (OpCodes.Ldobj, t);
998 else if (t.IsPointer)
999 ig.Emit (OpCodes.Ldind_I);
1001 ig.Emit (OpCodes.Ldind_Ref);
1005 // The stack contains the pointer and the value of type `type'
1007 public static void StoreFromPtr (ILGenerator ig, Type type)
1009 if (TypeManager.IsEnumType (type))
1010 type = TypeManager.EnumToUnderlying (type);
1011 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1012 ig.Emit (OpCodes.Stind_I4);
1013 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1014 ig.Emit (OpCodes.Stind_I8);
1015 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1016 type == TypeManager.ushort_type)
1017 ig.Emit (OpCodes.Stind_I2);
1018 else if (type == TypeManager.float_type)
1019 ig.Emit (OpCodes.Stind_R4);
1020 else if (type == TypeManager.double_type)
1021 ig.Emit (OpCodes.Stind_R8);
1022 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1023 type == TypeManager.bool_type)
1024 ig.Emit (OpCodes.Stind_I1);
1025 else if (type == TypeManager.intptr_type)
1026 ig.Emit (OpCodes.Stind_I);
1027 else if (type.IsValueType || type.IsGenericParameter)
1028 ig.Emit (OpCodes.Stobj, type);
1030 ig.Emit (OpCodes.Stind_Ref);
1034 // Returns the size of type `t' if known, otherwise, 0
1036 public static int GetTypeSize (Type t)
1038 t = TypeManager.TypeToCoreType (t);
1039 if (t == TypeManager.int32_type ||
1040 t == TypeManager.uint32_type ||
1041 t == TypeManager.float_type)
1043 else if (t == TypeManager.int64_type ||
1044 t == TypeManager.uint64_type ||
1045 t == TypeManager.double_type)
1047 else if (t == TypeManager.byte_type ||
1048 t == TypeManager.sbyte_type ||
1049 t == TypeManager.bool_type)
1051 else if (t == TypeManager.short_type ||
1052 t == TypeManager.char_type ||
1053 t == TypeManager.ushort_type)
1055 else if (t == TypeManager.decimal_type)
1061 public static void Error_NegativeArrayIndex (Location loc)
1063 Report.Error (248, loc, "Cannot create an array with a negative size");
1066 protected void Error_CannotCallAbstractBase (string name)
1068 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1072 // Converts `source' to an int, uint, long or ulong.
1074 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1078 bool old_checked = ec.CheckState;
1079 ec.CheckState = true;
1081 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1082 if (target == null){
1083 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1084 if (target == null){
1085 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1086 if (target == null){
1087 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1089 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1093 ec.CheckState = old_checked;
1096 // Only positive constants are allowed at compile time
1098 if (target is Constant){
1099 if (target is IntConstant){
1100 if (((IntConstant) target).Value < 0){
1101 Error_NegativeArrayIndex (loc);
1106 if (target is LongConstant){
1107 if (((LongConstant) target).Value < 0){
1108 Error_NegativeArrayIndex (loc);
1121 /// This is just a base class for expressions that can
1122 /// appear on statements (invocations, object creation,
1123 /// assignments, post/pre increment and decrement). The idea
1124 /// being that they would support an extra Emition interface that
1125 /// does not leave a result on the stack.
1127 public abstract class ExpressionStatement : Expression {
1129 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1131 Expression e = Resolve (ec);
1135 ExpressionStatement es = e as ExpressionStatement;
1137 Error (201, "Only assignment, call, increment, decrement and new object " +
1138 "expressions can be used as a statement");
1144 /// Requests the expression to be emitted in a `statement'
1145 /// context. This means that no new value is left on the
1146 /// stack after invoking this method (constrasted with
1147 /// Emit that will always leave a value on the stack).
1149 public abstract void EmitStatement (EmitContext ec);
1153 /// This kind of cast is used to encapsulate the child
1154 /// whose type is child.Type into an expression that is
1155 /// reported to return "return_type". This is used to encapsulate
1156 /// expressions which have compatible types, but need to be dealt
1157 /// at higher levels with.
1159 /// For example, a "byte" expression could be encapsulated in one
1160 /// of these as an "unsigned int". The type for the expression
1161 /// would be "unsigned int".
1164 public class EmptyCast : Expression {
1165 protected Expression child;
1167 public Expression Child {
1173 public EmptyCast (Expression child, Type return_type)
1175 eclass = child.eclass;
1176 loc = child.Location;
1181 public override Expression DoResolve (EmitContext ec)
1183 // This should never be invoked, we are born in fully
1184 // initialized state.
1189 public override void Emit (EmitContext ec)
1195 /// This is a numeric cast to a Decimal
1197 public class CastToDecimal : EmptyCast {
1199 MethodInfo conversion_operator;
1201 public CastToDecimal (Expression child)
1202 : this (child, false)
1206 public CastToDecimal (Expression child, bool find_explicit)
1207 : base (child, TypeManager.decimal_type)
1209 conversion_operator = GetConversionOperator (find_explicit);
1211 if (conversion_operator == null)
1212 throw new InternalErrorException ("Outer conversion routine is out of sync");
1215 // Returns the implicit operator that converts from
1216 // 'child.Type' to System.Decimal.
1217 MethodInfo GetConversionOperator (bool find_explicit)
1219 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1221 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1222 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1224 foreach (MethodInfo oper in mi) {
1225 ParameterData pd = TypeManager.GetParameterData (oper);
1227 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1233 public override void Emit (EmitContext ec)
1235 ILGenerator ig = ec.ig;
1238 ig.Emit (OpCodes.Call, conversion_operator);
1243 /// This is an explicit numeric cast from a Decimal
1245 public class CastFromDecimal : EmptyCast
1247 static IDictionary operators;
1249 public CastFromDecimal (Expression child, Type return_type)
1250 : base (child, return_type)
1252 if (child.Type != TypeManager.decimal_type)
1253 throw new InternalErrorException (
1254 "The expected type is Decimal, instead it is " + child.Type.FullName);
1257 // Returns the explicit operator that converts from an
1258 // express of type System.Decimal to 'type'.
1259 public Expression Resolve ()
1261 if (operators == null) {
1262 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1263 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1264 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1266 operators = new System.Collections.Specialized.HybridDictionary ();
1267 foreach (MethodInfo oper in all_oper) {
1268 ParameterData pd = TypeManager.GetParameterData (oper);
1269 if (pd.ParameterType (0) == TypeManager.decimal_type)
1270 operators.Add (oper.ReturnType, oper);
1274 return operators.Contains (type) ? this : null;
1277 public override void Emit (EmitContext ec)
1279 ILGenerator ig = ec.ig;
1282 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1287 // We need to special case this since an empty cast of
1288 // a NullLiteral is still a Constant
1290 public class NullCast : Constant {
1291 public Constant child;
1293 public NullCast (Constant child, Type return_type):
1294 base (Location.Null)
1296 eclass = child.eclass;
1301 override public string AsString ()
1306 public override object GetValue ()
1311 public override Expression DoResolve (EmitContext ec)
1313 // This should never be invoked, we are born in fully
1314 // initialized state.
1319 public override void Emit (EmitContext ec)
1324 public override Constant Increment ()
1326 throw new NotSupportedException ();
1329 public override bool IsDefaultValue {
1335 public override bool IsNegative {
1341 public override Constant Reduce (EmitContext ec, Type target_type)
1343 if (type == target_type)
1344 return child.Reduce (ec, target_type);
1353 /// This class is used to wrap literals which belong inside Enums
1355 public class EnumConstant : Constant {
1356 public Constant Child;
1358 public EnumConstant (Constant child, Type enum_type):
1359 base (child.Location)
1361 eclass = child.eclass;
1366 public override Expression DoResolve (EmitContext ec)
1368 // This should never be invoked, we are born in fully
1369 // initialized state.
1374 public override void Emit (EmitContext ec)
1379 public override string GetSignatureForError()
1381 return TypeManager.CSharpName (Type);
1384 public override object GetValue ()
1386 return Child.GetValue ();
1389 public override object GetTypedValue ()
1391 // FIXME: runtime is not ready to work with just emited enums
1392 if (!RootContext.StdLib) {
1393 return Child.GetValue ();
1396 return System.Enum.ToObject (type, Child.GetValue ());
1399 public override string AsString ()
1401 return Child.AsString ();
1404 public override DoubleConstant ConvertToDouble ()
1406 return Child.ConvertToDouble ();
1409 public override FloatConstant ConvertToFloat ()
1411 return Child.ConvertToFloat ();
1414 public override ULongConstant ConvertToULong ()
1416 return Child.ConvertToULong ();
1419 public override LongConstant ConvertToLong ()
1421 return Child.ConvertToLong ();
1424 public override UIntConstant ConvertToUInt ()
1426 return Child.ConvertToUInt ();
1429 public override IntConstant ConvertToInt ()
1431 return Child.ConvertToInt ();
1434 public override Constant Increment()
1436 return new EnumConstant (Child.Increment (), type);
1439 public override bool IsDefaultValue {
1441 return Child.IsDefaultValue;
1445 public override bool IsZeroInteger {
1446 get { return Child.IsZeroInteger; }
1449 public override bool IsNegative {
1451 return Child.IsNegative;
1455 public override Constant Reduce(EmitContext ec, Type target_type)
1457 if (Child.Type == target_type)
1460 return Child.Reduce (ec, target_type);
1463 public override Constant ToType (Type type, Location loc)
1466 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1467 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1470 if (type.UnderlyingSystemType != Child.Type)
1471 Child = Child.ToType (type.UnderlyingSystemType, loc);
1475 if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){
1476 Error_ValueCannotBeConverted (loc, type, false);
1480 return Child.ToType (type, loc);
1486 /// This kind of cast is used to encapsulate Value Types in objects.
1488 /// The effect of it is to box the value type emitted by the previous
1491 public class BoxedCast : EmptyCast {
1493 public BoxedCast (Expression expr, Type target_type)
1494 : base (expr, target_type)
1496 eclass = ExprClass.Value;
1499 public override Expression DoResolve (EmitContext ec)
1501 // This should never be invoked, we are born in fully
1502 // initialized state.
1507 public override void Emit (EmitContext ec)
1511 ec.ig.Emit (OpCodes.Box, child.Type);
1515 public class UnboxCast : EmptyCast {
1516 public UnboxCast (Expression expr, Type return_type)
1517 : base (expr, return_type)
1521 public override Expression DoResolve (EmitContext ec)
1523 // This should never be invoked, we are born in fully
1524 // initialized state.
1529 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1531 if (right_side == EmptyExpression.LValueMemberAccess)
1532 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1533 return base.DoResolveLValue (ec, right_side);
1536 public override void Emit (EmitContext ec)
1539 ILGenerator ig = ec.ig;
1542 if (t.IsGenericParameter)
1543 ig.Emit (OpCodes.Unbox_Any, t);
1545 ig.Emit (OpCodes.Unbox, t);
1547 LoadFromPtr (ig, t);
1553 /// This is used to perform explicit numeric conversions.
1555 /// Explicit numeric conversions might trigger exceptions in a checked
1556 /// context, so they should generate the conv.ovf opcodes instead of
1559 public class ConvCast : EmptyCast {
1560 public enum Mode : byte {
1561 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1563 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1564 U2_I1, U2_U1, U2_I2, U2_CH,
1565 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1566 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1567 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1568 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1569 CH_I1, CH_U1, CH_I2,
1570 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1571 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1576 public ConvCast (Expression child, Type return_type, Mode m)
1577 : base (child, return_type)
1582 public override Expression DoResolve (EmitContext ec)
1584 // This should never be invoked, we are born in fully
1585 // initialized state.
1590 public override string ToString ()
1592 return String.Format ("ConvCast ({0}, {1})", mode, child);
1595 public override void Emit (EmitContext ec)
1597 ILGenerator ig = ec.ig;
1603 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1604 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1605 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1606 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1607 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1609 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1610 case Mode.U1_CH: /* nothing */ break;
1612 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1613 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1614 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1615 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1616 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1617 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1619 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1620 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1621 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1622 case Mode.U2_CH: /* nothing */ break;
1624 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1625 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1626 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1627 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1628 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1629 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1630 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1632 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1633 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1634 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1635 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1636 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1637 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1639 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1640 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1641 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1642 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1643 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1644 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1645 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1646 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1648 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1649 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1650 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1651 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1652 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1653 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1654 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1655 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1657 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1658 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1659 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1661 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1662 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1663 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1664 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1665 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1666 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1667 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1668 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1669 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1671 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1672 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1673 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1674 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1675 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1676 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1677 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1678 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1679 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1680 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1684 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1685 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1686 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1687 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1688 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1691 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1693 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1694 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1695 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1696 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1697 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1698 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1700 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1701 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1702 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1703 case Mode.U2_CH: /* nothing */ break;
1705 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1706 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1707 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1708 case Mode.I4_U4: /* nothing */ break;
1709 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1710 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1711 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1713 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1714 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1715 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1716 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1717 case Mode.U4_I4: /* nothing */ break;
1718 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1720 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1721 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1722 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1723 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1724 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1725 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1726 case Mode.I8_U8: /* nothing */ break;
1727 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1729 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1730 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1731 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1732 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1733 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1734 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1735 case Mode.U8_I8: /* nothing */ break;
1736 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1738 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1739 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1740 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1742 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1743 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1744 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1745 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1746 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1747 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1748 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1749 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1750 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1752 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1753 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1754 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1755 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1756 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1757 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1758 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1759 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1760 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1761 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1767 public class OpcodeCast : EmptyCast {
1771 public OpcodeCast (Expression child, Type return_type, OpCode op)
1772 : base (child, return_type)
1776 second_valid = false;
1779 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1780 : base (child, return_type)
1785 second_valid = true;
1788 public override Expression DoResolve (EmitContext ec)
1790 // This should never be invoked, we are born in fully
1791 // initialized state.
1796 public override void Emit (EmitContext ec)
1807 /// This kind of cast is used to encapsulate a child and cast it
1808 /// to the class requested
1810 public class ClassCast : EmptyCast {
1811 public ClassCast (Expression child, Type return_type)
1812 : base (child, return_type)
1817 public override Expression DoResolve (EmitContext ec)
1819 // This should never be invoked, we are born in fully
1820 // initialized state.
1825 public override void Emit (EmitContext ec)
1829 if (child.Type.IsGenericParameter)
1830 ec.ig.Emit (OpCodes.Box, child.Type);
1832 if (type.IsGenericParameter)
1833 ec.ig.Emit (OpCodes.Unbox_Any, type);
1835 ec.ig.Emit (OpCodes.Castclass, type);
1840 /// SimpleName expressions are formed of a single word and only happen at the beginning
1841 /// of a dotted-name.
1843 public class SimpleName : Expression {
1845 public readonly TypeArguments Arguments;
1848 public SimpleName (string name, Location l)
1854 public SimpleName (string name, TypeArguments args, Location l)
1861 public SimpleName (string name, TypeParameter[] type_params, Location l)
1866 Arguments = new TypeArguments (l);
1867 foreach (TypeParameter type_param in type_params)
1868 Arguments.Add (new TypeParameterExpr (type_param, l));
1871 public static string RemoveGenericArity (string name)
1874 StringBuilder sb = new StringBuilder ();
1875 while (start < name.Length) {
1876 int pos = name.IndexOf ('`', start);
1878 sb.Append (name.Substring (start));
1882 sb.Append (name.Substring (start, pos-start));
1885 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1891 return sb.ToString ();
1894 public SimpleName GetMethodGroup ()
1896 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1899 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1901 if (ec.IsFieldInitializer)
1902 Report.Error (236, l,
1903 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1906 if (name.LastIndexOf ('.') > 0)
1907 name = name.Substring (name.LastIndexOf ('.') + 1);
1910 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1915 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1917 return resolved_to != null && resolved_to.Type != null &&
1918 resolved_to.Type.Name == Name &&
1919 (ec.DeclSpace.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1922 public override Expression DoResolve (EmitContext ec)
1924 return SimpleNameResolve (ec, null, false);
1927 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1929 return SimpleNameResolve (ec, right_side, false);
1933 public Expression DoResolve (EmitContext ec, bool intermediate)
1935 return SimpleNameResolve (ec, null, intermediate);
1938 private bool IsNestedChild (Type t, Type parent)
1943 while (parent != null) {
1944 parent = TypeManager.DropGenericTypeArguments (parent);
1945 if (TypeManager.IsNestedChildOf (t, parent))
1948 parent = parent.BaseType;
1954 FullNamedExpression ResolveNested (EmitContext ec, Type t)
1956 if (!t.IsGenericTypeDefinition)
1959 DeclSpace ds = ec.DeclSpace;
1960 while (ds != null) {
1961 if (IsNestedChild (t, ds.TypeBuilder))
1970 Type[] gen_params = t.GetGenericArguments ();
1972 int arg_count = Arguments != null ? Arguments.Count : 0;
1974 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1975 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1976 TypeArguments new_args = new TypeArguments (loc);
1977 foreach (TypeParameter param in ds.TypeParameters)
1978 new_args.Add (new TypeParameterExpr (param, loc));
1980 if (Arguments != null)
1981 new_args.Add (Arguments);
1983 return new ConstructedType (t, new_args, loc);
1990 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
1992 FullNamedExpression fne = ec.DeclSpace.LookupGeneric (Name, loc);
1994 return fne.ResolveAsTypeStep (ec, silent);
1996 int errors = Report.Errors;
1997 fne = ec.DeclSpace.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2000 if (fne.Type == null)
2003 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2005 return nested.ResolveAsTypeStep (ec);
2007 if (Arguments != null) {
2008 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2009 return ct.ResolveAsTypeStep (ec);
2015 if (silent || errors != Report.Errors)
2018 MemberCore mc = ec.DeclSpace.GetDefinition (Name);
2020 Error_UnexpectedKind (ec, "type", GetMemberType (mc), loc);
2022 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2028 // TODO: I am still not convinced about this. If someone else will need it
2029 // implement this as virtual property in MemberCore hierarchy
2030 string GetMemberType (MemberCore mc)
2032 if (mc is PropertyBase)
2036 if (mc is FieldBase)
2038 if (mc is MethodCore)
2040 if (mc is EnumMember)
2046 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2052 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2056 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2063 /// 7.5.2: Simple Names.
2065 /// Local Variables and Parameters are handled at
2066 /// parse time, so they never occur as SimpleNames.
2068 /// The `intermediate' flag is used by MemberAccess only
2069 /// and it is used to inform us that it is ok for us to
2070 /// avoid the static check, because MemberAccess might end
2071 /// up resolving the Name as a Type name and the access as
2072 /// a static type access.
2074 /// ie: Type Type; .... { Type.GetType (""); }
2076 /// Type is both an instance variable and a Type; Type.GetType
2077 /// is the static method not an instance method of type.
2079 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2081 Expression e = null;
2084 // Stage 1: Performed by the parser (binding to locals or parameters).
2086 Block current_block = ec.CurrentBlock;
2087 if (current_block != null){
2088 LocalInfo vi = current_block.GetLocalInfo (Name);
2090 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2091 if (right_side != null) {
2092 return var.ResolveLValue (ec, right_side, loc);
2094 ResolveFlags rf = ResolveFlags.VariableOrValue;
2096 rf |= ResolveFlags.DisableFlowAnalysis;
2097 return var.Resolve (ec, rf);
2101 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2103 if (right_side != null)
2104 return pref.ResolveLValue (ec, right_side, loc);
2106 return pref.Resolve (ec);
2111 // Stage 2: Lookup members
2114 DeclSpace lookup_ds = ec.DeclSpace;
2115 Type almost_matched_type = null;
2116 ArrayList almost_matched = null;
2118 if (lookup_ds.TypeBuilder == null)
2121 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
2125 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2126 almost_matched_type = lookup_ds.TypeBuilder;
2127 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2130 lookup_ds =lookup_ds.Parent;
2131 } while (lookup_ds != null);
2133 if (e == null && ec.ContainerType != null)
2134 e = MemberLookup (ec, ec.ContainerType, Name, loc);
2137 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2138 almost_matched_type = ec.ContainerType;
2139 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2141 e = ResolveAsTypeStep (ec, true);
2145 if (almost_matched != null)
2146 almostMatchedMembers = almost_matched;
2147 if (almost_matched_type == null)
2148 almost_matched_type = ec.ContainerType;
2149 MemberLookupFailed (ec, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclSpace.Name, true, loc);
2156 if (e is MemberExpr) {
2157 MemberExpr me = (MemberExpr) e;
2160 if (me.IsInstance) {
2161 if (ec.IsStatic || ec.IsFieldInitializer) {
2163 // Note that an MemberExpr can be both IsInstance and IsStatic.
2164 // An unresolved MethodGroupExpr can contain both kinds of methods
2165 // and each predicate is true if the MethodGroupExpr contains
2166 // at least one of that kind of method.
2170 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2171 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2172 return EmptyExpression.Null;
2176 // Pass the buck to MemberAccess and Invocation.
2178 left = EmptyExpression.Null;
2180 left = ec.GetThis (loc);
2183 left = new TypeExpression (ec.ContainerType, loc);
2186 e = me.ResolveMemberAccess (ec, left, loc, null);
2190 me = e as MemberExpr;
2194 if (Arguments != null) {
2195 MethodGroupExpr mg = me as MethodGroupExpr;
2199 return mg.ResolveGeneric (ec, Arguments);
2203 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2204 me.InstanceExpression.Type != me.DeclaringType &&
2205 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2206 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2207 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2208 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2212 return (right_side != null)
2213 ? me.DoResolveLValue (ec, right_side)
2214 : me.DoResolve (ec);
2220 public override void Emit (EmitContext ec)
2223 // If this is ever reached, then we failed to
2224 // find the name as a namespace
2227 Error (103, "The name `" + Name +
2228 "' does not exist in the class `" +
2229 ec.DeclSpace.Name + "'");
2232 public override string ToString ()
2237 public override string GetSignatureForError ()
2244 /// Represents a namespace or a type. The name of the class was inspired by
2245 /// section 10.8.1 (Fully Qualified Names).
2247 public abstract class FullNamedExpression : Expression {
2248 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2253 public abstract string FullName {
2259 /// Expression that evaluates to a type
2261 public abstract class TypeExpr : FullNamedExpression {
2262 override public FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2264 TypeExpr t = DoResolveAsTypeStep (ec);
2268 eclass = ExprClass.Type;
2272 override public Expression DoResolve (EmitContext ec)
2274 return ResolveAsTypeTerminal (ec);
2277 override public void Emit (EmitContext ec)
2279 throw new Exception ("Should never be called");
2282 public virtual bool CheckAccessLevel (DeclSpace ds)
2284 return ds.CheckAccessLevel (Type);
2287 public virtual bool AsAccessible (DeclSpace ds, int flags)
2289 return ds.AsAccessible (Type, flags);
2292 public virtual bool IsClass {
2293 get { return Type.IsClass; }
2296 public virtual bool IsValueType {
2297 get { return Type.IsValueType; }
2300 public virtual bool IsInterface {
2301 get { return Type.IsInterface; }
2304 public virtual bool IsSealed {
2305 get { return Type.IsSealed; }
2308 public virtual bool CanInheritFrom ()
2310 if (Type == TypeManager.enum_type ||
2311 (Type == TypeManager.value_type && RootContext.StdLib) ||
2312 Type == TypeManager.multicast_delegate_type ||
2313 Type == TypeManager.delegate_type ||
2314 Type == TypeManager.array_type)
2320 protected abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
2322 public Type ResolveType (EmitContext ec)
2324 TypeExpr t = ResolveAsTypeTerminal (ec);
2328 if (ec.TestObsoleteMethodUsage) {
2329 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (t.Type);
2330 if (obsolete_attr != null) {
2331 AttributeTester.Report_ObsoleteMessage (obsolete_attr, Name, Location);
2338 public abstract string Name {
2342 public override bool Equals (object obj)
2344 TypeExpr tobj = obj as TypeExpr;
2348 return Type == tobj.Type;
2351 public override int GetHashCode ()
2353 return Type.GetHashCode ();
2356 public override string ToString ()
2363 /// Fully resolved Expression that already evaluated to a type
2365 public class TypeExpression : TypeExpr {
2366 public TypeExpression (Type t, Location l)
2369 eclass = ExprClass.Type;
2373 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2378 public override string Name {
2379 get { return Type.ToString (); }
2382 public override string FullName {
2383 get { return Type.FullName; }
2388 /// Used to create types from a fully qualified name. These are just used
2389 /// by the parser to setup the core types. A TypeLookupExpression is always
2390 /// classified as a type.
2392 public class TypeLookupExpression : TypeExpr {
2395 public TypeLookupExpression (string name)
2400 static readonly char [] dot_array = { '.' };
2401 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2406 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2408 string lookup_name = name;
2409 int pos = name.IndexOf ('.');
2411 rest = name.Substring (pos + 1);
2412 lookup_name = name.Substring (0, pos);
2415 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclSpace, lookup_name, Location.Null);
2417 if (resolved != null && rest != null) {
2418 // Now handle the rest of the the name.
2419 string [] elements = rest.Split (dot_array);
2421 int count = elements.Length;
2423 while (i < count && resolved != null && resolved is Namespace) {
2424 Namespace ns = resolved as Namespace;
2425 element = elements [i++];
2426 lookup_name += "." + element;
2427 resolved = ns.Lookup (ec.DeclSpace, element, Location.Null);
2430 if (resolved != null && resolved is TypeExpr) {
2431 Type t = ((TypeExpr) resolved).Type;
2433 if (!ec.DeclSpace.CheckAccessLevel (t)) {
2435 lookup_name = t.FullName;
2442 t = TypeManager.GetNestedType (t, elements [i++]);
2447 if (resolved == null) {
2448 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2452 if (!(resolved is TypeExpr)) {
2453 resolved.Error_UnexpectedKind (ec, "type", loc);
2457 type = ((TypeExpr) resolved).ResolveType (ec);
2461 public override string Name {
2462 get { return name; }
2465 public override string FullName {
2466 get { return name; }
2471 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2474 public class UnboundTypeExpression : TypeExpr
2478 public UnboundTypeExpression (MemberName name, Location l)
2484 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2487 if (name.Left != null) {
2488 Expression lexpr = name.Left.GetTypeExpression ();
2489 expr = new MemberAccess (lexpr, name.Basename, loc);
2491 expr = new SimpleName (name.Basename, loc);
2494 FullNamedExpression fne = expr.ResolveAsTypeStep (ec);
2499 return new TypeExpression (type, loc);
2502 public override string Name {
2503 get { return name.FullName; }
2506 public override string FullName {
2507 get { return name.FullName; }
2511 public class TypeAliasExpression : TypeExpr {
2512 FullNamedExpression alias;
2517 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2523 eclass = ExprClass.Type;
2525 name = alias.FullName + "<" + args.ToString () + ">";
2527 name = alias.FullName;
2530 public override string Name {
2531 get { return alias.FullName; }
2534 public override string FullName {
2535 get { return name; }
2538 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2540 texpr = alias.ResolveAsTypeTerminal (ec);
2544 Type type = texpr.ResolveType (ec);
2545 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2548 if (num_args == 0) {
2549 Report.Error (308, loc,
2550 "The non-generic type `{0}' cannot " +
2551 "be used with type arguments.",
2552 TypeManager.CSharpName (type));
2556 ConstructedType ctype = new ConstructedType (type, args, loc);
2557 return ctype.ResolveAsTypeTerminal (ec);
2558 } else if (num_args > 0) {
2559 Report.Error (305, loc,
2560 "Using the generic type `{0}' " +
2561 "requires {1} type arguments",
2562 TypeManager.CSharpName (type), num_args.ToString ());
2566 return new TypeExpression (type, loc);
2569 public override bool CheckAccessLevel (DeclSpace ds)
2571 return texpr.CheckAccessLevel (ds);
2574 public override bool AsAccessible (DeclSpace ds, int flags)
2576 return texpr.AsAccessible (ds, flags);
2579 public override bool IsClass {
2580 get { return texpr.IsClass; }
2583 public override bool IsValueType {
2584 get { return texpr.IsValueType; }
2587 public override bool IsInterface {
2588 get { return texpr.IsInterface; }
2591 public override bool IsSealed {
2592 get { return texpr.IsSealed; }
2597 /// This class denotes an expression which evaluates to a member
2598 /// of a struct or a class.
2600 public abstract class MemberExpr : Expression
2603 /// The name of this member.
2605 public abstract string Name {
2610 /// Whether this is an instance member.
2612 public abstract bool IsInstance {
2617 /// Whether this is a static member.
2619 public abstract bool IsStatic {
2624 /// The type which declares this member.
2626 public abstract Type DeclaringType {
2631 /// The instance expression associated with this member, if it's a
2632 /// non-static member.
2634 public Expression InstanceExpression;
2636 public static void error176 (Location loc, string name)
2638 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2639 "with an instance reference, qualify it with a type name instead", name);
2642 // TODO: possible optimalization
2643 // Cache resolved constant result in FieldBuilder <-> expression map
2644 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2645 SimpleName original)
2649 // original == null || original.Resolve (...) ==> left
2652 if (left is TypeExpr) {
2654 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2662 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2665 error176 (loc, GetSignatureForError ());
2669 InstanceExpression = left;
2674 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2679 if (InstanceExpression == EmptyExpression.Null) {
2680 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2684 if (InstanceExpression.Type.IsValueType) {
2685 if (InstanceExpression is IMemoryLocation) {
2686 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2688 LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
2689 InstanceExpression.Emit (ec);
2691 t.AddressOf (ec, AddressOp.Store);
2694 InstanceExpression.Emit (ec);
2696 if (prepare_for_load)
2697 ec.ig.Emit (OpCodes.Dup);
2702 /// MethodGroup Expression.
2704 /// This is a fully resolved expression that evaluates to a type
2706 public class MethodGroupExpr : MemberExpr {
2707 public MethodBase [] Methods;
2708 bool has_type_arguments = false;
2709 bool identical_type_name = false;
2712 public MethodGroupExpr (MemberInfo [] mi, Location l)
2714 Methods = new MethodBase [mi.Length];
2715 mi.CopyTo (Methods, 0);
2716 eclass = ExprClass.MethodGroup;
2717 type = TypeManager.object_type;
2721 public MethodGroupExpr (ArrayList list, Location l)
2723 Methods = new MethodBase [list.Count];
2726 list.CopyTo (Methods, 0);
2728 foreach (MemberInfo m in list){
2729 if (!(m is MethodBase)){
2730 Console.WriteLine ("Name " + m.Name);
2731 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2738 eclass = ExprClass.MethodGroup;
2739 type = TypeManager.object_type;
2742 public override Type DeclaringType {
2745 // We assume that the top-level type is in the end
2747 return Methods [Methods.Length - 1].DeclaringType;
2748 //return Methods [0].DeclaringType;
2752 public bool HasTypeArguments {
2754 return has_type_arguments;
2758 has_type_arguments = value;
2762 public bool IdenticalTypeName {
2764 return identical_type_name;
2768 identical_type_name = value;
2772 public bool IsBase {
2781 public override string GetSignatureForError ()
2783 return TypeManager.CSharpSignature (Methods [0]);
2786 public override string Name {
2788 return Methods [0].Name;
2792 public override bool IsInstance {
2794 foreach (MethodBase mb in Methods)
2802 public override bool IsStatic {
2804 foreach (MethodBase mb in Methods)
2812 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2813 SimpleName original)
2815 if (!(left is TypeExpr) &&
2816 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2817 IdenticalTypeName = true;
2819 return base.ResolveMemberAccess (ec, left, loc, original);
2822 override public Expression DoResolve (EmitContext ec)
2825 InstanceExpression = null;
2827 if (InstanceExpression != null) {
2828 InstanceExpression = InstanceExpression.DoResolve (ec);
2829 if (InstanceExpression == null)
2836 public void ReportUsageError ()
2838 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2839 Name + "()' is referenced without parentheses");
2842 override public void Emit (EmitContext ec)
2844 ReportUsageError ();
2847 bool RemoveMethods (bool keep_static)
2849 ArrayList smethods = new ArrayList ();
2851 foreach (MethodBase mb in Methods){
2852 if (mb.IsStatic == keep_static)
2856 if (smethods.Count == 0)
2859 Methods = new MethodBase [smethods.Count];
2860 smethods.CopyTo (Methods, 0);
2866 /// Removes any instance methods from the MethodGroup, returns
2867 /// false if the resulting set is empty.
2869 public bool RemoveInstanceMethods ()
2871 return RemoveMethods (true);
2875 /// Removes any static methods from the MethodGroup, returns
2876 /// false if the resulting set is empty.
2878 public bool RemoveStaticMethods ()
2880 return RemoveMethods (false);
2883 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2885 if (args.Resolve (ec) == false)
2888 Type[] atypes = args.Arguments;
2890 int first_count = 0;
2891 MethodInfo first = null;
2893 ArrayList list = new ArrayList ();
2894 foreach (MethodBase mb in Methods) {
2895 MethodInfo mi = mb as MethodInfo;
2896 if ((mi == null) || !mi.IsGenericMethod)
2899 Type[] gen_params = mi.GetGenericArguments ();
2901 if (first == null) {
2903 first_count = gen_params.Length;
2906 if (gen_params.Length != atypes.Length)
2909 list.Add (mi.MakeGenericMethod (atypes));
2912 if (list.Count > 0) {
2913 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2914 new_mg.InstanceExpression = InstanceExpression;
2915 new_mg.HasTypeArguments = true;
2916 new_mg.IsBase = IsBase;
2922 305, loc, "Using the generic method `{0}' " +
2923 "requires {1} type arguments", Name,
2924 first_count.ToString ());
2927 308, loc, "The non-generic method `{0}' " +
2928 "cannot be used with type arguments", Name);
2935 /// Fully resolved expression that evaluates to a Field
2937 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2938 public readonly FieldInfo FieldInfo;
2939 VariableInfo variable_info;
2941 LocalTemporary temp;
2943 bool in_initializer;
2945 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2948 this.in_initializer = in_initializer;
2951 public FieldExpr (FieldInfo fi, Location l)
2954 eclass = ExprClass.Variable;
2955 type = TypeManager.TypeToCoreType (fi.FieldType);
2959 public override string Name {
2961 return FieldInfo.Name;
2965 public override bool IsInstance {
2967 return !FieldInfo.IsStatic;
2971 public override bool IsStatic {
2973 return FieldInfo.IsStatic;
2977 public override Type DeclaringType {
2979 return FieldInfo.DeclaringType;
2983 public override string GetSignatureForError ()
2985 return TypeManager.GetFullNameSignature (FieldInfo);
2988 public VariableInfo VariableInfo {
2990 return variable_info;
2994 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2995 SimpleName original)
2997 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
2999 Type t = fi.FieldType;
3001 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3002 IConstant ic = TypeManager.GetConstant (fi);
3005 ic = new ExternalConstant (fi);
3007 ic = ExternalConstant.CreateDecimal (fi);
3009 return base.ResolveMemberAccess (ec, left, loc, original);
3012 TypeManager.RegisterConstant (fi, ic);
3015 bool left_is_type = left is TypeExpr;
3016 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3017 Report.SymbolRelatedToPreviousError (FieldInfo);
3018 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3022 if (ic.ResolveValue ()) {
3023 if (ec.TestObsoleteMethodUsage)
3024 ic.CheckObsoleteness (loc);
3030 if (t.IsPointer && !ec.InUnsafe) {
3035 return base.ResolveMemberAccess (ec, left, loc, original);
3038 override public Expression DoResolve (EmitContext ec)
3040 return DoResolve (ec, false);
3043 Expression DoResolve (EmitContext ec, bool lvalue_instance)
3045 if (ec.InRefOutArgumentResolving && FieldInfo.IsInitOnly && !ec.IsConstructor && FieldInfo.FieldType.IsValueType) {
3046 if (FieldInfo.FieldType is TypeBuilder) {
3047 if (FieldInfo.IsStatic)
3048 Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3049 GetSignatureForError ());
3051 Report.Error (1649, loc, "Members of readonly field `{0}.{1}' cannot be passed ref or out (except in a constructor)",
3052 TypeManager.CSharpName (DeclaringType), Name);
3054 if (FieldInfo.IsStatic)
3055 Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3058 Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3064 if (!FieldInfo.IsStatic){
3065 if (InstanceExpression == null){
3067 // This can happen when referencing an instance field using
3068 // a fully qualified type expression: TypeName.InstanceField = xxx
3070 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3074 // Resolve the field's instance expression while flow analysis is turned
3075 // off: when accessing a field "a.b", we must check whether the field
3076 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3078 if (lvalue_instance) {
3079 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3080 ec.DoFlowAnalysis = false;
3081 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3082 ec.DoFlowAnalysis = old_do_flow_analysis;
3084 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3085 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3088 if (InstanceExpression == null)
3092 if (!in_initializer && !ec.IsFieldInitializer) {
3093 ObsoleteAttribute oa;
3094 FieldBase f = TypeManager.GetField (FieldInfo);
3096 if (ec.TestObsoleteMethodUsage)
3097 f.CheckObsoleteness (loc);
3098 // To be sure that type is external because we do not register generated fields
3099 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3100 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3102 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3106 AnonymousContainer am = ec.CurrentAnonymousMethod;
3108 if (!FieldInfo.IsStatic){
3109 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3110 Report.Error (1673, loc,
3111 "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
3115 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3116 ec.CaptureField (this);
3120 // If the instance expression is a local variable or parameter.
3121 IVariable var = InstanceExpression as IVariable;
3122 if ((var == null) || (var.VariableInfo == null))
3125 VariableInfo vi = var.VariableInfo;
3126 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3129 variable_info = vi.GetSubStruct (FieldInfo.Name);
3133 void Report_AssignToReadonly (Expression right_side)
3137 bool need_error_sig = false;
3138 if (right_side == EmptyExpression.LValueMemberAccess) {
3141 msg = "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)";
3144 msg = "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)";
3146 need_error_sig = true;
3147 } else if (IsStatic) {
3149 msg = "A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)";
3152 msg = "A readonly field cannot be assigned to (except in a constructor or a variable initializer)";
3156 Report.Error (code, loc, msg, GetSignatureForError ());
3158 Report.Error (code, loc, msg);
3161 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3163 IVariable var = InstanceExpression as IVariable;
3164 if ((var != null) && (var.VariableInfo != null))
3165 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3167 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3169 Expression e = DoResolve (ec, lvalue_instance);
3174 FieldBase fb = TypeManager.GetField (FieldInfo);
3178 if (!FieldInfo.IsInitOnly)
3182 // InitOnly fields can only be assigned in constructors
3185 if (ec.IsConstructor){
3186 if (IsStatic && !ec.IsStatic)
3187 Report_AssignToReadonly (right_side);
3190 if (ec.TypeContainer.CurrentType != null)
3191 ctype = ec.TypeContainer.CurrentType;
3193 ctype = ec.ContainerType;
3195 if (TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3199 Report_AssignToReadonly (right_side);
3204 public override void CheckMarshallByRefAccess (Type container)
3206 if (!IsStatic && Type.IsValueType && !container.IsSubclassOf (TypeManager.mbr_type) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3207 Report.SymbolRelatedToPreviousError (DeclaringType);
3208 Report.Error (1690, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3209 GetSignatureForError ());
3213 public bool VerifyFixed ()
3215 IVariable variable = InstanceExpression as IVariable;
3216 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3217 // We defer the InstanceExpression check after the variable check to avoid a
3218 // separate null check on InstanceExpression.
3219 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3222 public override int GetHashCode()
3224 return FieldInfo.GetHashCode ();
3227 public override bool Equals (object obj)
3229 FieldExpr fe = obj as FieldExpr;
3233 if (FieldInfo != fe.FieldInfo)
3236 if (InstanceExpression == null || fe.InstanceExpression == null)
3239 return InstanceExpression.Equals (fe.InstanceExpression);
3242 public void Emit (EmitContext ec, bool leave_copy)
3244 ILGenerator ig = ec.ig;
3245 bool is_volatile = false;
3247 FieldBase f = TypeManager.GetField (FieldInfo);
3249 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3252 f.SetMemberIsUsed ();
3255 if (FieldInfo.IsStatic){
3257 ig.Emit (OpCodes.Volatile);
3259 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3262 EmitInstance (ec, false);
3265 ig.Emit (OpCodes.Volatile);
3267 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3270 ig.Emit (OpCodes.Ldflda, FieldInfo);
3271 ig.Emit (OpCodes.Ldflda, ff.Element);
3274 ig.Emit (OpCodes.Ldfld, FieldInfo);
3279 ec.ig.Emit (OpCodes.Dup);
3280 if (!FieldInfo.IsStatic) {
3281 temp = new LocalTemporary (ec, this.Type);
3287 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3289 FieldAttributes fa = FieldInfo.Attributes;
3290 bool is_static = (fa & FieldAttributes.Static) != 0;
3291 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3292 ILGenerator ig = ec.ig;
3293 prepared = prepare_for_load;
3295 if (is_readonly && !ec.IsConstructor){
3296 Report_AssignToReadonly (source);
3300 EmitInstance (ec, prepare_for_load);
3304 ec.ig.Emit (OpCodes.Dup);
3305 if (!FieldInfo.IsStatic) {
3306 temp = new LocalTemporary (ec, this.Type);
3311 if (FieldInfo is FieldBuilder){
3312 FieldBase f = TypeManager.GetField (FieldInfo);
3314 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3315 ig.Emit (OpCodes.Volatile);
3322 ig.Emit (OpCodes.Stsfld, FieldInfo);
3324 ig.Emit (OpCodes.Stfld, FieldInfo);
3330 public override void Emit (EmitContext ec)
3335 public void AddressOf (EmitContext ec, AddressOp mode)
3337 ILGenerator ig = ec.ig;
3339 if (FieldInfo is FieldBuilder){
3340 FieldBase f = TypeManager.GetField (FieldInfo);
3342 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3343 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3344 f.GetSignatureForError ());
3348 if ((mode & AddressOp.Store) != 0)
3350 if ((mode & AddressOp.Load) != 0)
3351 f.SetMemberIsUsed ();
3356 // Handle initonly fields specially: make a copy and then
3357 // get the address of the copy.
3360 if (FieldInfo.IsInitOnly){
3362 if (ec.IsConstructor){
3363 if (FieldInfo.IsStatic){
3375 local = ig.DeclareLocal (type);
3376 ig.Emit (OpCodes.Stloc, local);
3377 ig.Emit (OpCodes.Ldloca, local);
3382 if (FieldInfo.IsStatic){
3383 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3385 EmitInstance (ec, false);
3386 ig.Emit (OpCodes.Ldflda, FieldInfo);
3392 // A FieldExpr whose address can not be taken
3394 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3395 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3399 public new void AddressOf (EmitContext ec, AddressOp mode)
3401 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3406 /// Expression that evaluates to a Property. The Assign class
3407 /// might set the `Value' expression if we are in an assignment.
3409 /// This is not an LValue because we need to re-write the expression, we
3410 /// can not take data from the stack and store it.
3412 public class PropertyExpr : MemberExpr, IAssignMethod {
3413 public readonly PropertyInfo PropertyInfo;
3416 // This is set externally by the `BaseAccess' class
3419 MethodInfo getter, setter;
3424 LocalTemporary temp;
3427 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3429 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
3432 eclass = ExprClass.PropertyAccess;
3436 type = TypeManager.TypeToCoreType (pi.PropertyType);
3438 ResolveAccessors (ec);
3441 public override string Name {
3443 return PropertyInfo.Name;
3447 public override bool IsInstance {
3453 public override bool IsStatic {
3459 public override Type DeclaringType {
3461 return PropertyInfo.DeclaringType;
3465 public override string GetSignatureForError ()
3467 return TypeManager.GetFullNameSignature (PropertyInfo);
3470 void FindAccessors (Type invocation_type)
3472 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3473 BindingFlags.Static | BindingFlags.Instance |
3474 BindingFlags.DeclaredOnly;
3476 Type current = PropertyInfo.DeclaringType;
3477 for (; current != null; current = current.BaseType) {
3478 MemberInfo[] group = TypeManager.MemberLookup (
3479 invocation_type, invocation_type, current,
3480 MemberTypes.Property, flags, PropertyInfo.Name, null);
3485 if (group.Length != 1)
3486 // Oooops, can this ever happen ?
3489 PropertyInfo pi = (PropertyInfo) group [0];
3492 getter = pi.GetGetMethod (true);
3495 setter = pi.GetSetMethod (true);
3497 MethodInfo accessor = getter != null ? getter : setter;
3499 if (!accessor.IsVirtual)
3505 // We also perform the permission checking here, as the PropertyInfo does not
3506 // hold the information for the accessibility of its setter/getter
3508 void ResolveAccessors (EmitContext ec)
3510 FindAccessors (ec.ContainerType);
3512 if (getter != null) {
3513 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3514 IMethodData md = TypeManager.GetMethod (the_getter);
3516 md.SetMemberIsUsed ();
3518 AccessorTable [getter] = PropertyInfo;
3519 is_static = getter.IsStatic;
3522 if (setter != null) {
3523 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3524 IMethodData md = TypeManager.GetMethod (the_setter);
3526 md.SetMemberIsUsed ();
3528 AccessorTable [setter] = PropertyInfo;
3529 is_static = setter.IsStatic;
3533 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3536 InstanceExpression = null;
3540 if (InstanceExpression == null) {
3541 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3545 if (lvalue_instance)
3546 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3548 InstanceExpression = InstanceExpression.DoResolve (ec);
3549 if (InstanceExpression == null)
3552 InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
3554 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3555 InstanceExpression.Type != ec.ContainerType &&
3556 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3557 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3558 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3565 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3567 // TODO: correctly we should compare arguments but it will lead to bigger changes
3568 if (mi is MethodBuilder) {
3569 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3573 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3575 ParameterData iparams = TypeManager.GetParameterData (mi);
3576 sig.Append (getter ? "get_" : "set_");
3578 sig.Append (iparams.GetSignatureForError ());
3580 Report.SymbolRelatedToPreviousError (mi);
3581 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3582 Name, sig.ToString ());
3585 override public Expression DoResolve (EmitContext ec)
3590 if (getter != null){
3591 if (TypeManager.GetParameterData (getter).Count != 0){
3592 Error_PropertyNotFound (getter, true);
3597 if (getter == null){
3599 // The following condition happens if the PropertyExpr was
3600 // created, but is invalid (ie, the property is inaccessible),
3601 // and we did not want to embed the knowledge about this in
3602 // the caller routine. This only avoids double error reporting.
3607 if (InstanceExpression != EmptyExpression.Null) {
3608 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3609 TypeManager.GetFullNameSignature (PropertyInfo));
3614 bool must_do_cs1540_check = false;
3615 if (getter != null &&
3616 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3617 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3618 if (pm != null && pm.HasCustomAccessModifier) {
3619 Report.SymbolRelatedToPreviousError (pm);
3620 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3621 TypeManager.CSharpSignature (getter));
3624 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3628 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3632 // Only base will allow this invocation to happen.
3634 if (IsBase && getter.IsAbstract) {
3635 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3639 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3649 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3651 if (right_side == EmptyExpression.OutAccess) {
3652 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3653 GetSignatureForError ());
3657 if (right_side == EmptyExpression.LValueMemberAccess) {
3658 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3659 GetSignatureForError ());
3663 if (setter == null){
3665 // The following condition happens if the PropertyExpr was
3666 // created, but is invalid (ie, the property is inaccessible),
3667 // and we did not want to embed the knowledge about this in
3668 // the caller routine. This only avoids double error reporting.
3672 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3673 GetSignatureForError ());
3677 if (TypeManager.GetParameterData (setter).Count != 1){
3678 Error_PropertyNotFound (setter, false);
3682 bool must_do_cs1540_check;
3683 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3684 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3685 if (pm != null && pm.HasCustomAccessModifier) {
3686 Report.SymbolRelatedToPreviousError (pm);
3687 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3688 TypeManager.CSharpSignature (setter));
3691 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3695 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3699 // Only base will allow this invocation to happen.
3701 if (IsBase && setter.IsAbstract){
3702 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3709 public override void Emit (EmitContext ec)
3714 public void Emit (EmitContext ec, bool leave_copy)
3717 // Special case: length of single dimension array property is turned into ldlen
3719 if ((getter == TypeManager.system_int_array_get_length) ||
3720 (getter == TypeManager.int_array_get_length)){
3721 Type iet = InstanceExpression.Type;
3724 // System.Array.Length can be called, but the Type does not
3725 // support invoking GetArrayRank, so test for that case first
3727 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3729 EmitInstance (ec, false);
3730 ec.ig.Emit (OpCodes.Ldlen);
3731 ec.ig.Emit (OpCodes.Conv_I4);
3736 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3739 ec.ig.Emit (OpCodes.Dup);
3741 temp = new LocalTemporary (ec, this.Type);
3748 // Implements the IAssignMethod interface for assignments
3750 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3752 Expression my_source = source;
3754 prepared = prepare_for_load;
3759 ec.ig.Emit (OpCodes.Dup);
3761 temp = new LocalTemporary (ec, this.Type);
3765 } else if (leave_copy) {
3768 temp = new LocalTemporary (ec, this.Type);
3774 ArrayList args = new ArrayList (1);
3775 args.Add (new Argument (my_source, Argument.AType.Expression));
3777 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3785 /// Fully resolved expression that evaluates to an Event
3787 public class EventExpr : MemberExpr {
3788 public readonly EventInfo EventInfo;
3791 MethodInfo add_accessor, remove_accessor;
3793 public EventExpr (EventInfo ei, Location loc)
3797 eclass = ExprClass.EventAccess;
3799 add_accessor = TypeManager.GetAddMethod (ei);
3800 remove_accessor = TypeManager.GetRemoveMethod (ei);
3802 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3805 if (EventInfo is MyEventBuilder){
3806 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3807 type = eb.EventType;
3810 type = EventInfo.EventHandlerType;
3813 public override string Name {
3815 return EventInfo.Name;
3819 public override bool IsInstance {
3825 public override bool IsStatic {
3831 public override Type DeclaringType {
3833 return EventInfo.DeclaringType;
3837 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3838 SimpleName original)
3841 // If the event is local to this class, we transform ourselves into a FieldExpr
3844 if (EventInfo.DeclaringType == ec.ContainerType ||
3845 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3846 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3849 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec, mi, loc);
3852 Report.Error (-200, loc, "Internal error!!");
3856 InstanceExpression = null;
3858 return ml.ResolveMemberAccess (ec, left, loc, original);
3862 return base.ResolveMemberAccess (ec, left, loc, original);
3866 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3869 InstanceExpression = null;
3873 if (InstanceExpression == null) {
3874 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
3878 InstanceExpression = InstanceExpression.DoResolve (ec);
3879 if (InstanceExpression == null)
3883 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3884 // However, in the Event case, we reported a CS0122 instead.
3886 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3887 InstanceExpression.Type != ec.ContainerType &&
3888 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3889 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3896 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3898 return DoResolve (ec);
3901 public override Expression DoResolve (EmitContext ec)
3903 bool must_do_cs1540_check;
3904 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3905 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3906 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3910 if (!InstanceResolve (ec, must_do_cs1540_check))
3916 public override void Emit (EmitContext ec)
3918 if (InstanceExpression is This)
3919 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3921 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3922 "(except on the defining type)", Name);
3925 public override string GetSignatureForError ()
3927 return TypeManager.CSharpSignature (EventInfo);
3930 public void EmitAddOrRemove (EmitContext ec, Expression source)
3932 BinaryDelegate source_del = (BinaryDelegate) source;
3933 Expression handler = source_del.Right;
3935 Argument arg = new Argument (handler, Argument.AType.Expression);
3936 ArrayList args = new ArrayList ();
3940 if (source_del.IsAddition)
3941 Invocation.EmitCall (
3942 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3944 Invocation.EmitCall (
3945 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3950 public class TemporaryVariable : Expression, IMemoryLocation
3954 public TemporaryVariable (Type type, Location loc)
3958 eclass = ExprClass.Value;
3961 public override Expression DoResolve (EmitContext ec)
3966 TypeExpr te = new TypeExpression (type, loc);
3967 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3968 if (!li.Resolve (ec))
3971 AnonymousContainer am = ec.CurrentAnonymousMethod;
3972 if ((am != null) && am.IsIterator)
3973 ec.CaptureVariable (li);
3978 public override void Emit (EmitContext ec)
3980 ILGenerator ig = ec.ig;
3982 if (li.FieldBuilder != null) {
3983 ig.Emit (OpCodes.Ldarg_0);
3984 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3986 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3990 public void EmitLoadAddress (EmitContext ec)
3992 ILGenerator ig = ec.ig;
3994 if (li.FieldBuilder != null) {
3995 ig.Emit (OpCodes.Ldarg_0);
3996 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
3998 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4002 public void Store (EmitContext ec, Expression right_side)
4004 if (li.FieldBuilder != null)
4005 ec.ig.Emit (OpCodes.Ldarg_0);
4007 right_side.Emit (ec);
4008 if (li.FieldBuilder != null) {
4009 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4011 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4015 public void EmitThis (EmitContext ec)
4017 if (li.FieldBuilder != null) {
4018 ec.ig.Emit (OpCodes.Ldarg_0);
4022 public void EmitStore (ILGenerator ig)
4024 if (li.FieldBuilder != null)
4025 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4027 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4030 public void AddressOf (EmitContext ec, AddressOp mode)
4032 EmitLoadAddress (ec);