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 virtual FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
225 // This is used to resolve the expression as a type, a null
226 // value will be returned if the expression is not a type
229 public virtual TypeExpr ResolveAsTypeTerminal (EmitContext ec, bool silent)
231 int errors = Report.Errors;
233 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
236 if (!silent && errors == Report.Errors)
237 Report.Error (118, loc, "Expecting a type.");
241 if (fne.eclass != ExprClass.Type) {
242 if (!silent && (errors == Report.Errors))
243 fne.Error_UnexpectedKind (null, "type", loc);
247 TypeExpr te = fne as TypeExpr;
249 if (!te.CheckAccessLevel (ec.DeclContainer)) {
250 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
254 ConstructedType ct = te as ConstructedType;
255 if ((ct != null) && !ec.ResolvingTypeTree && !ec.ResolvingGenericMethod &&
256 !ct.CheckConstraints (ec))
263 public static void ErrorIsInaccesible (Location loc, string name)
265 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
268 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
270 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
271 + " the qualifier must be of type `{2}' (or derived from it)",
272 TypeManager.GetFullNameSignature (m),
273 TypeManager.CSharpName (qualifier),
274 TypeManager.CSharpName (container));
278 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
280 if (Type.Name == target.Name){
281 Report.ExtraInformation (loc,
283 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
284 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
289 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
290 GetSignatureForError (), TypeManager.CSharpName (target));
294 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
295 bool b = Convert.ExplicitNumericConversion (e, target) != null;
297 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
298 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
299 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
303 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
304 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
305 GetSignatureForError (), TypeManager.CSharpName (target));
309 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
310 Type == TypeManager.anonymous_method_type ?
311 "anonymous method" : "`" + GetSignatureForError () + "'",
312 TypeManager.CSharpName (target));
315 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
317 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
318 TypeManager.CSharpName (type), name);
321 ResolveFlags ExprClassToResolveFlags ()
325 case ExprClass.Namespace:
326 return ResolveFlags.Type;
328 case ExprClass.MethodGroup:
329 return ResolveFlags.MethodGroup;
331 case ExprClass.Value:
332 case ExprClass.Variable:
333 case ExprClass.PropertyAccess:
334 case ExprClass.EventAccess:
335 case ExprClass.IndexerAccess:
336 return ResolveFlags.VariableOrValue;
339 throw new Exception ("Expression " + GetType () +
340 " ExprClass is Invalid after resolve");
346 /// Resolves an expression and performs semantic analysis on it.
350 /// Currently Resolve wraps DoResolve to perform sanity
351 /// checking and assertion checking on what we expect from Resolve.
353 public Expression Resolve (EmitContext ec, ResolveFlags flags)
355 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
356 return ResolveAsTypeStep (ec, false);
358 bool old_do_flow_analysis = ec.DoFlowAnalysis;
359 bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis;
360 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
361 ec.DoFlowAnalysis = false;
362 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
363 ec.OmitStructFlowAnalysis = true;
366 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
367 if (this is SimpleName)
368 e = ((SimpleName) this).DoResolve (ec, intermediate);
373 ec.DoFlowAnalysis = old_do_flow_analysis;
374 ec.OmitStructFlowAnalysis = old_omit_struct_analysis;
379 if ((flags & e.ExprClassToResolveFlags ()) == 0) {
380 e.Error_UnexpectedKind (flags, loc);
384 if (e.type == null && !(e is Namespace)) {
385 throw new Exception (
386 "Expression " + e.GetType () +
387 " did not set its type after Resolve\n" +
388 "called from: " + this.GetType ());
395 /// Resolves an expression and performs semantic analysis on it.
397 public Expression Resolve (EmitContext ec)
399 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
401 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
402 ((MethodGroupExpr) e).ReportUsageError ();
408 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
410 Expression e = Resolve (ec);
414 Constant c = e as Constant;
418 EmptyCast empty = e as EmptyCast;
420 c = empty.Child as Constant;
422 // TODO: not sure about this maybe there is easier way how to use EmptyCast
429 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
434 /// Resolves an expression for LValue assignment
438 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
439 /// checking and assertion checking on what we expect from Resolve
441 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
443 int errors = Report.Errors;
444 Expression e = DoResolveLValue (ec, right_side);
447 if (errors == Report.Errors)
448 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
453 if (e.eclass == ExprClass.Invalid)
454 throw new Exception ("Expression " + e +
455 " ExprClass is Invalid after resolve");
457 if (e.eclass == ExprClass.MethodGroup) {
458 ((MethodGroupExpr) e).ReportUsageError ();
462 if ((e.type == null) && !(e is ConstructedType))
463 throw new Exception ("Expression " + e +
464 " did not set its type after Resolve");
471 /// Emits the code for the expression
475 /// The Emit method is invoked to generate the code
476 /// for the expression.
478 public abstract void Emit (EmitContext ec);
480 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
483 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
487 /// Protected constructor. Only derivate types should
488 /// be able to be created
491 protected Expression ()
493 eclass = ExprClass.Invalid;
498 /// Returns a literalized version of a literal FieldInfo
502 /// The possible return values are:
503 /// IntConstant, UIntConstant
504 /// LongLiteral, ULongConstant
505 /// FloatConstant, DoubleConstant
508 /// The value returned is already resolved.
510 public static Constant Constantify (object v, Type t)
512 if (t == TypeManager.int32_type)
513 return new IntConstant ((int) v, Location.Null);
514 else if (t == TypeManager.uint32_type)
515 return new UIntConstant ((uint) v, Location.Null);
516 else if (t == TypeManager.int64_type)
517 return new LongConstant ((long) v, Location.Null);
518 else if (t == TypeManager.uint64_type)
519 return new ULongConstant ((ulong) v, Location.Null);
520 else if (t == TypeManager.float_type)
521 return new FloatConstant ((float) v, Location.Null);
522 else if (t == TypeManager.double_type)
523 return new DoubleConstant ((double) v, Location.Null);
524 else if (t == TypeManager.string_type)
525 return new StringConstant ((string) v, Location.Null);
526 else if (t == TypeManager.short_type)
527 return new ShortConstant ((short)v, Location.Null);
528 else if (t == TypeManager.ushort_type)
529 return new UShortConstant ((ushort)v, Location.Null);
530 else if (t == TypeManager.sbyte_type)
531 return new SByteConstant ((sbyte)v, Location.Null);
532 else if (t == TypeManager.byte_type)
533 return new ByteConstant ((byte)v, Location.Null);
534 else if (t == TypeManager.char_type)
535 return new CharConstant ((char)v, Location.Null);
536 else if (t == TypeManager.bool_type)
537 return new BoolConstant ((bool) v, Location.Null);
538 else if (t == TypeManager.decimal_type)
539 return new DecimalConstant ((decimal) v, Location.Null);
540 else if (TypeManager.IsEnumType (t)){
541 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
543 real_type = System.Enum.GetUnderlyingType (real_type);
545 Constant e = Constantify (v, real_type);
547 return new EnumConstant (e, t);
548 } else if (v == null && !TypeManager.IsValueType (t))
549 return new NullLiteral (Location.Null);
551 throw new Exception ("Unknown type for constant (" + t +
556 /// Returns a fully formed expression after a MemberLookup
559 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
562 return new EventExpr ((EventInfo) mi, loc);
563 else if (mi is FieldInfo)
564 return new FieldExpr ((FieldInfo) mi, loc);
565 else if (mi is PropertyInfo)
566 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
567 else if (mi is Type){
568 return new TypeExpression ((System.Type) mi, loc);
574 protected static ArrayList almostMatchedMembers = new ArrayList (4);
577 // FIXME: Probably implement a cache for (t,name,current_access_set)?
579 // This code could use some optimizations, but we need to do some
580 // measurements. For example, we could use a delegate to `flag' when
581 // something can not any longer be a method-group (because it is something
585 // If the return value is an Array, then it is an array of
588 // If the return value is an MemberInfo, it is anything, but a Method
592 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
593 // the arguments here and have MemberLookup return only the methods that
594 // match the argument count/type, unlike we are doing now (we delay this
597 // This is so we can catch correctly attempts to invoke instance methods
598 // from a static body (scan for error 120 in ResolveSimpleName).
601 // FIXME: Potential optimization, have a static ArrayList
604 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
605 MemberTypes mt, BindingFlags bf, Location loc)
607 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
611 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
612 // `qualifier_type' or null to lookup members in the current class.
615 public static Expression MemberLookup (Type container_type,
616 Type qualifier_type, Type queried_type,
617 string name, MemberTypes mt,
618 BindingFlags bf, Location loc)
620 almostMatchedMembers.Clear ();
622 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
623 queried_type, mt, bf, name, almostMatchedMembers);
628 int count = mi.Length;
630 if (mi [0] is MethodBase)
631 return new MethodGroupExpr (mi, loc);
636 return ExprClassFromMemberInfo (container_type, mi [0], loc);
639 public const MemberTypes AllMemberTypes =
640 MemberTypes.Constructor |
644 MemberTypes.NestedType |
645 MemberTypes.Property;
647 public const BindingFlags AllBindingFlags =
648 BindingFlags.Public |
649 BindingFlags.Static |
650 BindingFlags.Instance;
652 public static Expression MemberLookup (EmitContext ec, Type queried_type,
653 string name, Location loc)
655 return MemberLookup (ec.ContainerType, null, queried_type, name,
656 AllMemberTypes, AllBindingFlags, loc);
659 public static Expression MemberLookup (Type container_type, Type qualifier_type,
660 Type queried_type, string name, Location loc)
662 return MemberLookup (container_type, qualifier_type,
663 queried_type, name, AllMemberTypes,
664 AllBindingFlags, loc);
667 public static Expression MethodLookup (EmitContext ec, Type queried_type,
668 string name, Location loc)
670 return MemberLookup (ec.ContainerType, null, queried_type, name,
671 MemberTypes.Method, AllBindingFlags, loc);
675 /// This is a wrapper for MemberLookup that is not used to "probe", but
676 /// to find a final definition. If the final definition is not found, we
677 /// look for private members and display a useful debugging message if we
680 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
681 Type queried_type, string name, Location loc)
683 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
684 AllMemberTypes, AllBindingFlags, loc);
687 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
688 Type queried_type, string name,
689 MemberTypes mt, BindingFlags bf,
694 int errors = Report.Errors;
696 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
698 if (e == null && errors == Report.Errors)
699 // No errors were reported by MemberLookup, but there was an error.
700 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
705 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
706 Type queried_type, string name,
707 string class_name, bool complain_if_none_found,
710 if (almostMatchedMembers.Count != 0) {
711 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
712 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
713 for (int j = 0; j < i; ++j) {
714 if (m == almostMatchedMembers [j]) {
722 Type declaring_type = m.DeclaringType;
724 Report.SymbolRelatedToPreviousError (m);
725 if (qualifier_type == null) {
726 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
727 TypeManager.CSharpName (m.DeclaringType),
728 TypeManager.CSharpName (container_type));
730 } else if (qualifier_type != container_type &&
731 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
732 // Although a derived class can access protected members of
733 // its base class it cannot do so through an instance of the
734 // base class (CS1540). If the qualifier_type is a base of the
735 // ec.ContainerType and the lookup succeeds with the latter one,
736 // then we are in this situation.
737 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
739 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
742 almostMatchedMembers.Clear ();
746 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
747 AllMemberTypes, AllBindingFlags |
748 BindingFlags.NonPublic, name, null);
750 if (lookup == null) {
751 if (!complain_if_none_found)
754 if (class_name != null)
755 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
758 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
762 if (TypeManager.MemberLookup (queried_type, null, queried_type,
763 AllMemberTypes, AllBindingFlags |
764 BindingFlags.NonPublic, name, null) == null) {
765 if ((lookup.Length == 1) && (lookup [0] is Type)) {
766 Type t = (Type) lookup [0];
768 Report.Error (305, loc,
769 "Using the generic type `{0}' " +
770 "requires {1} type arguments",
771 TypeManager.CSharpName (t),
772 TypeManager.GetNumberOfTypeArguments (t).ToString ());
777 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
778 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
779 if (name == ".ctor" && ml.Count == 0)
781 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
785 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
789 /// Returns an expression that can be used to invoke operator true
790 /// on the expression if it exists.
792 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
794 return GetOperatorTrueOrFalse (ec, e, true, loc);
798 /// Returns an expression that can be used to invoke operator false
799 /// on the expression if it exists.
801 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
803 return GetOperatorTrueOrFalse (ec, e, false, loc);
806 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
809 Expression operator_group;
811 if (TypeManager.IsNullableType (e.Type))
812 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
814 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
815 if (operator_group == null)
818 ArrayList arguments = new ArrayList ();
819 arguments.Add (new Argument (e, Argument.AType.Expression));
820 method = Invocation.OverloadResolve (
821 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
826 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
830 /// Resolves the expression `e' into a boolean expression: either through
831 /// an implicit conversion, or through an `operator true' invocation
833 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
839 if (e.Type == TypeManager.bool_type)
842 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
844 if (converted != null)
848 // If no implicit conversion to bool exists, try using `operator true'
850 converted = Expression.GetOperatorTrue (ec, e, loc);
851 if (converted == null){
852 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
858 public virtual string ExprClassName
862 case ExprClass.Invalid:
864 case ExprClass.Value:
866 case ExprClass.Variable:
868 case ExprClass.Namespace:
872 case ExprClass.MethodGroup:
873 return "method group";
874 case ExprClass.PropertyAccess:
875 return "property access";
876 case ExprClass.EventAccess:
877 return "event access";
878 case ExprClass.IndexerAccess:
879 return "indexer access";
880 case ExprClass.Nothing:
883 throw new Exception ("Should not happen");
888 /// Reports that we were expecting `expr' to be of class `expected'
890 public void Error_UnexpectedKind (EmitContext ec, string expected, Location loc)
892 Error_UnexpectedKind (ec, expected, ExprClassName, loc);
895 public void Error_UnexpectedKind (EmitContext ec, string expected, string was, Location loc)
897 string name = GetSignatureForError ();
899 name = ec.DeclContainer.GetSignatureForError () + '.' + name;
901 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
902 name, was, expected);
905 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
907 string [] valid = new string [4];
910 if ((flags & ResolveFlags.VariableOrValue) != 0) {
911 valid [count++] = "variable";
912 valid [count++] = "value";
915 if ((flags & ResolveFlags.Type) != 0)
916 valid [count++] = "type";
918 if ((flags & ResolveFlags.MethodGroup) != 0)
919 valid [count++] = "method group";
922 valid [count++] = "unknown";
924 StringBuilder sb = new StringBuilder (valid [0]);
925 for (int i = 1; i < count - 1; i++) {
927 sb.Append (valid [i]);
930 sb.Append ("' or `");
931 sb.Append (valid [count - 1]);
934 Report.Error (119, loc,
935 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
938 public static void UnsafeError (Location loc)
940 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
944 // Load the object from the pointer.
946 public static void LoadFromPtr (ILGenerator ig, Type t)
948 if (t == TypeManager.int32_type)
949 ig.Emit (OpCodes.Ldind_I4);
950 else if (t == TypeManager.uint32_type)
951 ig.Emit (OpCodes.Ldind_U4);
952 else if (t == TypeManager.short_type)
953 ig.Emit (OpCodes.Ldind_I2);
954 else if (t == TypeManager.ushort_type)
955 ig.Emit (OpCodes.Ldind_U2);
956 else if (t == TypeManager.char_type)
957 ig.Emit (OpCodes.Ldind_U2);
958 else if (t == TypeManager.byte_type)
959 ig.Emit (OpCodes.Ldind_U1);
960 else if (t == TypeManager.sbyte_type)
961 ig.Emit (OpCodes.Ldind_I1);
962 else if (t == TypeManager.uint64_type)
963 ig.Emit (OpCodes.Ldind_I8);
964 else if (t == TypeManager.int64_type)
965 ig.Emit (OpCodes.Ldind_I8);
966 else if (t == TypeManager.float_type)
967 ig.Emit (OpCodes.Ldind_R4);
968 else if (t == TypeManager.double_type)
969 ig.Emit (OpCodes.Ldind_R8);
970 else if (t == TypeManager.bool_type)
971 ig.Emit (OpCodes.Ldind_I1);
972 else if (t == TypeManager.intptr_type)
973 ig.Emit (OpCodes.Ldind_I);
974 else if (TypeManager.IsEnumType (t)) {
975 if (t == TypeManager.enum_type)
976 ig.Emit (OpCodes.Ldind_Ref);
978 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
979 } else if (t.IsValueType || t.IsGenericParameter)
980 ig.Emit (OpCodes.Ldobj, t);
981 else if (t.IsPointer)
982 ig.Emit (OpCodes.Ldind_I);
984 ig.Emit (OpCodes.Ldind_Ref);
988 // The stack contains the pointer and the value of type `type'
990 public static void StoreFromPtr (ILGenerator ig, Type type)
992 if (TypeManager.IsEnumType (type))
993 type = TypeManager.EnumToUnderlying (type);
994 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
995 ig.Emit (OpCodes.Stind_I4);
996 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
997 ig.Emit (OpCodes.Stind_I8);
998 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
999 type == TypeManager.ushort_type)
1000 ig.Emit (OpCodes.Stind_I2);
1001 else if (type == TypeManager.float_type)
1002 ig.Emit (OpCodes.Stind_R4);
1003 else if (type == TypeManager.double_type)
1004 ig.Emit (OpCodes.Stind_R8);
1005 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1006 type == TypeManager.bool_type)
1007 ig.Emit (OpCodes.Stind_I1);
1008 else if (type == TypeManager.intptr_type)
1009 ig.Emit (OpCodes.Stind_I);
1010 else if (type.IsValueType || type.IsGenericParameter)
1011 ig.Emit (OpCodes.Stobj, type);
1013 ig.Emit (OpCodes.Stind_Ref);
1017 // Returns the size of type `t' if known, otherwise, 0
1019 public static int GetTypeSize (Type t)
1021 t = TypeManager.TypeToCoreType (t);
1022 if (t == TypeManager.int32_type ||
1023 t == TypeManager.uint32_type ||
1024 t == TypeManager.float_type)
1026 else if (t == TypeManager.int64_type ||
1027 t == TypeManager.uint64_type ||
1028 t == TypeManager.double_type)
1030 else if (t == TypeManager.byte_type ||
1031 t == TypeManager.sbyte_type ||
1032 t == TypeManager.bool_type)
1034 else if (t == TypeManager.short_type ||
1035 t == TypeManager.char_type ||
1036 t == TypeManager.ushort_type)
1038 else if (t == TypeManager.decimal_type)
1044 public static void Error_NegativeArrayIndex (Location loc)
1046 Report.Error (248, loc, "Cannot create an array with a negative size");
1049 protected void Error_CannotCallAbstractBase (string name)
1051 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1055 // Converts `source' to an int, uint, long or ulong.
1057 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1061 bool old_checked = ec.CheckState;
1062 ec.CheckState = true;
1064 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1065 if (target == null){
1066 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1067 if (target == null){
1068 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1069 if (target == null){
1070 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1072 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1076 ec.CheckState = old_checked;
1079 // Only positive constants are allowed at compile time
1081 if (target is Constant){
1082 if (target is IntConstant){
1083 if (((IntConstant) target).Value < 0){
1084 Error_NegativeArrayIndex (loc);
1089 if (target is LongConstant){
1090 if (((LongConstant) target).Value < 0){
1091 Error_NegativeArrayIndex (loc);
1104 /// This is just a base class for expressions that can
1105 /// appear on statements (invocations, object creation,
1106 /// assignments, post/pre increment and decrement). The idea
1107 /// being that they would support an extra Emition interface that
1108 /// does not leave a result on the stack.
1110 public abstract class ExpressionStatement : Expression {
1112 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1114 Expression e = Resolve (ec);
1118 ExpressionStatement es = e as ExpressionStatement;
1120 Error (201, "Only assignment, call, increment, decrement and new object " +
1121 "expressions can be used as a statement");
1127 /// Requests the expression to be emitted in a `statement'
1128 /// context. This means that no new value is left on the
1129 /// stack after invoking this method (constrasted with
1130 /// Emit that will always leave a value on the stack).
1132 public abstract void EmitStatement (EmitContext ec);
1136 /// This kind of cast is used to encapsulate the child
1137 /// whose type is child.Type into an expression that is
1138 /// reported to return "return_type". This is used to encapsulate
1139 /// expressions which have compatible types, but need to be dealt
1140 /// at higher levels with.
1142 /// For example, a "byte" expression could be encapsulated in one
1143 /// of these as an "unsigned int". The type for the expression
1144 /// would be "unsigned int".
1147 public class EmptyCast : Expression {
1148 protected Expression child;
1150 public Expression Child {
1156 public EmptyCast (Expression child, Type return_type)
1158 eclass = child.eclass;
1159 loc = child.Location;
1164 public override Expression DoResolve (EmitContext ec)
1166 // This should never be invoked, we are born in fully
1167 // initialized state.
1172 public override void Emit (EmitContext ec)
1178 /// This is a numeric cast to a Decimal
1180 public class CastToDecimal : EmptyCast {
1182 MethodInfo conversion_operator;
1184 public CastToDecimal (Expression child)
1185 : this (child, false)
1189 public CastToDecimal (Expression child, bool find_explicit)
1190 : base (child, TypeManager.decimal_type)
1192 conversion_operator = GetConversionOperator (find_explicit);
1194 if (conversion_operator == null)
1195 throw new InternalErrorException ("Outer conversion routine is out of sync");
1198 // Returns the implicit operator that converts from
1199 // 'child.Type' to System.Decimal.
1200 MethodInfo GetConversionOperator (bool find_explicit)
1202 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1204 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1205 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1207 foreach (MethodInfo oper in mi) {
1208 ParameterData pd = TypeManager.GetParameterData (oper);
1210 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1216 public override void Emit (EmitContext ec)
1218 ILGenerator ig = ec.ig;
1221 ig.Emit (OpCodes.Call, conversion_operator);
1226 /// This is an explicit numeric cast from a Decimal
1228 public class CastFromDecimal : EmptyCast
1230 static IDictionary operators;
1232 public CastFromDecimal (Expression child, Type return_type)
1233 : base (child, return_type)
1235 if (child.Type != TypeManager.decimal_type)
1236 throw new InternalErrorException (
1237 "The expected type is Decimal, instead it is " + child.Type.FullName);
1240 // Returns the explicit operator that converts from an
1241 // express of type System.Decimal to 'type'.
1242 public Expression Resolve ()
1244 if (operators == null) {
1245 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1246 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1247 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1249 operators = new System.Collections.Specialized.HybridDictionary ();
1250 foreach (MethodInfo oper in all_oper) {
1251 ParameterData pd = TypeManager.GetParameterData (oper);
1252 if (pd.ParameterType (0) == TypeManager.decimal_type)
1253 operators.Add (oper.ReturnType, oper);
1257 return operators.Contains (type) ? this : null;
1260 public override void Emit (EmitContext ec)
1262 ILGenerator ig = ec.ig;
1265 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1270 // We need to special case this since an empty cast of
1271 // a NullLiteral is still a Constant
1273 public class NullCast : Constant {
1274 public Constant child;
1276 public NullCast (Constant child, Type return_type):
1277 base (Location.Null)
1279 eclass = child.eclass;
1284 override public string AsString ()
1289 public override object GetValue ()
1294 public override Expression DoResolve (EmitContext ec)
1296 // This should never be invoked, we are born in fully
1297 // initialized state.
1302 public override void Emit (EmitContext ec)
1307 public override Constant Increment ()
1309 throw new NotSupportedException ();
1312 public override bool IsDefaultValue {
1318 public override bool IsNegative {
1324 public override Constant Reduce (EmitContext ec, Type target_type)
1326 if (type == target_type)
1327 return child.Reduce (ec, target_type);
1336 /// This class is used to wrap literals which belong inside Enums
1338 public class EnumConstant : Constant {
1339 public Constant Child;
1341 public EnumConstant (Constant child, Type enum_type):
1342 base (child.Location)
1344 eclass = child.eclass;
1349 public override Expression DoResolve (EmitContext ec)
1351 // This should never be invoked, we are born in fully
1352 // initialized state.
1357 public override void Emit (EmitContext ec)
1362 public override string GetSignatureForError()
1364 return TypeManager.CSharpName (Type);
1367 public override object GetValue ()
1369 return Child.GetValue ();
1372 public override object GetTypedValue ()
1374 // FIXME: runtime is not ready to work with just emited enums
1375 if (!RootContext.StdLib) {
1376 return Child.GetValue ();
1379 return System.Enum.ToObject (type, Child.GetValue ());
1382 public override string AsString ()
1384 return Child.AsString ();
1387 public override DoubleConstant ConvertToDouble ()
1389 return Child.ConvertToDouble ();
1392 public override FloatConstant ConvertToFloat ()
1394 return Child.ConvertToFloat ();
1397 public override ULongConstant ConvertToULong ()
1399 return Child.ConvertToULong ();
1402 public override LongConstant ConvertToLong ()
1404 return Child.ConvertToLong ();
1407 public override UIntConstant ConvertToUInt ()
1409 return Child.ConvertToUInt ();
1412 public override IntConstant ConvertToInt ()
1414 return Child.ConvertToInt ();
1417 public override Constant Increment()
1419 return new EnumConstant (Child.Increment (), type);
1422 public override bool IsDefaultValue {
1424 return Child.IsDefaultValue;
1428 public override bool IsZeroInteger {
1429 get { return Child.IsZeroInteger; }
1432 public override bool IsNegative {
1434 return Child.IsNegative;
1438 public override Constant Reduce(EmitContext ec, Type target_type)
1440 if (Child.Type == target_type)
1443 return Child.Reduce (ec, target_type);
1446 public override Constant ToType (Type type, Location loc)
1449 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1450 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1453 if (type.UnderlyingSystemType != Child.Type)
1454 Child = Child.ToType (type.UnderlyingSystemType, loc);
1458 if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, this, type)){
1459 Error_ValueCannotBeConverted (loc, type, false);
1463 return Child.ToType (type, loc);
1469 /// This kind of cast is used to encapsulate Value Types in objects.
1471 /// The effect of it is to box the value type emitted by the previous
1474 public class BoxedCast : EmptyCast {
1476 public BoxedCast (Expression expr, Type target_type)
1477 : base (expr, target_type)
1479 eclass = ExprClass.Value;
1482 public override Expression DoResolve (EmitContext ec)
1484 // This should never be invoked, we are born in fully
1485 // initialized state.
1490 public override void Emit (EmitContext ec)
1494 ec.ig.Emit (OpCodes.Box, child.Type);
1498 public class UnboxCast : EmptyCast {
1499 public UnboxCast (Expression expr, Type return_type)
1500 : base (expr, return_type)
1504 public override Expression DoResolve (EmitContext ec)
1506 // This should never be invoked, we are born in fully
1507 // initialized state.
1512 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1514 if (right_side == EmptyExpression.LValueMemberAccess)
1515 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1516 return base.DoResolveLValue (ec, right_side);
1519 public override void Emit (EmitContext ec)
1522 ILGenerator ig = ec.ig;
1525 if (t.IsGenericParameter)
1526 ig.Emit (OpCodes.Unbox_Any, t);
1528 ig.Emit (OpCodes.Unbox, t);
1530 LoadFromPtr (ig, t);
1536 /// This is used to perform explicit numeric conversions.
1538 /// Explicit numeric conversions might trigger exceptions in a checked
1539 /// context, so they should generate the conv.ovf opcodes instead of
1542 public class ConvCast : EmptyCast {
1543 public enum Mode : byte {
1544 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1546 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1547 U2_I1, U2_U1, U2_I2, U2_CH,
1548 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1549 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1550 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1551 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1552 CH_I1, CH_U1, CH_I2,
1553 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1554 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1559 public ConvCast (Expression child, Type return_type, Mode m)
1560 : base (child, return_type)
1565 public override Expression DoResolve (EmitContext ec)
1567 // This should never be invoked, we are born in fully
1568 // initialized state.
1573 public override string ToString ()
1575 return String.Format ("ConvCast ({0}, {1})", mode, child);
1578 public override void Emit (EmitContext ec)
1580 ILGenerator ig = ec.ig;
1586 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1587 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1588 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1589 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1590 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1592 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1593 case Mode.U1_CH: /* nothing */ break;
1595 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1596 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1597 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1598 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1599 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1600 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1602 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1603 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1604 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1605 case Mode.U2_CH: /* nothing */ break;
1607 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1608 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1609 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1610 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1611 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1612 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1613 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1615 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1616 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1617 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1618 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1619 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1620 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1622 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1623 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1624 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1625 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1626 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1627 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1628 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1629 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1631 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1632 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1633 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1634 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1635 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1636 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1637 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1638 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1640 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1641 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1642 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1644 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1645 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1646 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1647 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1648 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1649 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1650 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1651 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1652 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1654 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1655 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1656 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1657 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1658 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1659 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1660 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1661 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1662 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1663 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1667 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1668 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1669 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1670 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1671 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1673 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1674 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1676 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1677 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1678 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1679 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1680 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1681 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1683 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1684 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1685 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1686 case Mode.U2_CH: /* nothing */ break;
1688 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1689 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1690 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1691 case Mode.I4_U4: /* nothing */ break;
1692 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1693 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1694 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1696 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1697 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1698 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1699 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1700 case Mode.U4_I4: /* nothing */ break;
1701 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1703 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1704 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1705 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1706 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1707 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1708 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1709 case Mode.I8_U8: /* nothing */ break;
1710 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1712 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1713 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1714 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1715 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1716 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1717 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1718 case Mode.U8_I8: /* nothing */ break;
1719 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1721 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1722 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1723 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1725 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1726 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1727 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1728 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1729 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1730 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1731 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1732 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1733 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1735 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1736 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1737 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1738 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1739 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1740 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1741 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1742 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1743 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1744 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1750 public class OpcodeCast : EmptyCast {
1754 public OpcodeCast (Expression child, Type return_type, OpCode op)
1755 : base (child, return_type)
1759 second_valid = false;
1762 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1763 : base (child, return_type)
1768 second_valid = true;
1771 public override Expression DoResolve (EmitContext ec)
1773 // This should never be invoked, we are born in fully
1774 // initialized state.
1779 public override void Emit (EmitContext ec)
1790 /// This kind of cast is used to encapsulate a child and cast it
1791 /// to the class requested
1793 public class ClassCast : EmptyCast {
1794 public ClassCast (Expression child, Type return_type)
1795 : base (child, return_type)
1800 public override Expression DoResolve (EmitContext ec)
1802 // This should never be invoked, we are born in fully
1803 // initialized state.
1808 public override void Emit (EmitContext ec)
1812 if (child.Type.IsGenericParameter)
1813 ec.ig.Emit (OpCodes.Box, child.Type);
1815 if (type.IsGenericParameter)
1816 ec.ig.Emit (OpCodes.Unbox_Any, type);
1818 ec.ig.Emit (OpCodes.Castclass, type);
1823 /// SimpleName expressions are formed of a single word and only happen at the beginning
1824 /// of a dotted-name.
1826 public class SimpleName : Expression {
1828 public readonly TypeArguments Arguments;
1831 public SimpleName (string name, Location l)
1837 public SimpleName (string name, TypeArguments args, Location l)
1844 public SimpleName (string name, TypeParameter[] type_params, Location l)
1849 Arguments = new TypeArguments (l);
1850 foreach (TypeParameter type_param in type_params)
1851 Arguments.Add (new TypeParameterExpr (type_param, l));
1854 public static string RemoveGenericArity (string name)
1857 StringBuilder sb = new StringBuilder ();
1858 while (start < name.Length) {
1859 int pos = name.IndexOf ('`', start);
1861 sb.Append (name.Substring (start));
1865 sb.Append (name.Substring (start, pos-start));
1868 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1874 return sb.ToString ();
1877 public SimpleName GetMethodGroup ()
1879 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1882 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1884 if (ec.IsFieldInitializer)
1885 Report.Error (236, l,
1886 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1889 if (name.LastIndexOf ('.') > 0)
1890 name = name.Substring (name.LastIndexOf ('.') + 1);
1893 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1898 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1900 return resolved_to != null && resolved_to.Type != null &&
1901 resolved_to.Type.Name == Name &&
1902 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1905 public override Expression DoResolve (EmitContext ec)
1907 return SimpleNameResolve (ec, null, false);
1910 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1912 return SimpleNameResolve (ec, right_side, false);
1916 public Expression DoResolve (EmitContext ec, bool intermediate)
1918 return SimpleNameResolve (ec, null, intermediate);
1921 private bool IsNestedChild (Type t, Type parent)
1926 while (parent != null) {
1927 parent = TypeManager.DropGenericTypeArguments (parent);
1928 if (TypeManager.IsNestedChildOf (t, parent))
1931 parent = parent.BaseType;
1937 FullNamedExpression ResolveNested (EmitContext ec, Type t)
1939 if (!t.IsGenericTypeDefinition)
1942 DeclSpace ds = ec.DeclContainer;
1943 while (ds != null) {
1944 if (IsNestedChild (t, ds.TypeBuilder))
1953 Type[] gen_params = t.GetGenericArguments ();
1955 int arg_count = Arguments != null ? Arguments.Count : 0;
1957 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1958 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1959 TypeArguments new_args = new TypeArguments (loc);
1960 foreach (TypeParameter param in ds.TypeParameters)
1961 new_args.Add (new TypeParameterExpr (param, loc));
1963 if (Arguments != null)
1964 new_args.Add (Arguments);
1966 return new ConstructedType (t, new_args, loc);
1973 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
1975 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
1977 return fne.ResolveAsTypeStep (ec, silent);
1979 int errors = Report.Errors;
1980 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
1983 if (fne.Type == null)
1986 FullNamedExpression nested = ResolveNested (ec, fne.Type);
1988 return nested.ResolveAsTypeStep (ec, false);
1990 if (Arguments != null) {
1991 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
1992 return ct.ResolveAsTypeStep (ec, false);
1998 if (silent || errors != Report.Errors)
2001 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2003 Error_UnexpectedKind (ec, "type", GetMemberType (mc), loc);
2005 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2011 // TODO: I am still not convinced about this. If someone else will need it
2012 // implement this as virtual property in MemberCore hierarchy
2013 string GetMemberType (MemberCore mc)
2015 if (mc is PropertyBase)
2019 if (mc is FieldBase)
2021 if (mc is MethodCore)
2023 if (mc is EnumMember)
2029 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2035 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2039 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2046 /// 7.5.2: Simple Names.
2048 /// Local Variables and Parameters are handled at
2049 /// parse time, so they never occur as SimpleNames.
2051 /// The `intermediate' flag is used by MemberAccess only
2052 /// and it is used to inform us that it is ok for us to
2053 /// avoid the static check, because MemberAccess might end
2054 /// up resolving the Name as a Type name and the access as
2055 /// a static type access.
2057 /// ie: Type Type; .... { Type.GetType (""); }
2059 /// Type is both an instance variable and a Type; Type.GetType
2060 /// is the static method not an instance method of type.
2062 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2064 Expression e = null;
2067 // Stage 1: Performed by the parser (binding to locals or parameters).
2069 Block current_block = ec.CurrentBlock;
2070 if (current_block != null){
2071 LocalInfo vi = current_block.GetLocalInfo (Name);
2073 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2074 if (right_side != null) {
2075 return var.ResolveLValue (ec, right_side, loc);
2077 ResolveFlags rf = ResolveFlags.VariableOrValue;
2079 rf |= ResolveFlags.DisableFlowAnalysis;
2080 return var.Resolve (ec, rf);
2084 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2086 if (right_side != null)
2087 return pref.ResolveLValue (ec, right_side, loc);
2089 return pref.Resolve (ec);
2094 // Stage 2: Lookup members
2097 DeclSpace lookup_ds = ec.DeclContainer;
2098 Type almost_matched_type = null;
2099 ArrayList almost_matched = null;
2101 if (lookup_ds.TypeBuilder == null)
2104 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
2108 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2109 almost_matched_type = lookup_ds.TypeBuilder;
2110 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2113 lookup_ds =lookup_ds.Parent;
2114 } while (lookup_ds != null);
2116 if (e == null && ec.ContainerType != null)
2117 e = MemberLookup (ec, ec.ContainerType, Name, loc);
2120 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2121 almost_matched_type = ec.ContainerType;
2122 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2124 e = ResolveAsTypeStep (ec, true);
2128 if (almost_matched != null)
2129 almostMatchedMembers = almost_matched;
2130 if (almost_matched_type == null)
2131 almost_matched_type = ec.ContainerType;
2132 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2139 if (e is MemberExpr) {
2140 MemberExpr me = (MemberExpr) e;
2143 if (me.IsInstance) {
2144 if (ec.IsStatic || ec.IsFieldInitializer) {
2146 // Note that an MemberExpr can be both IsInstance and IsStatic.
2147 // An unresolved MethodGroupExpr can contain both kinds of methods
2148 // and each predicate is true if the MethodGroupExpr contains
2149 // at least one of that kind of method.
2153 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2154 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2155 return EmptyExpression.Null;
2159 // Pass the buck to MemberAccess and Invocation.
2161 left = EmptyExpression.Null;
2163 left = ec.GetThis (loc);
2166 left = new TypeExpression (ec.ContainerType, loc);
2169 e = me.ResolveMemberAccess (ec, left, loc, null);
2173 me = e as MemberExpr;
2177 if (Arguments != null) {
2178 MethodGroupExpr mg = me as MethodGroupExpr;
2182 return mg.ResolveGeneric (ec, Arguments);
2186 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2187 me.InstanceExpression.Type != me.DeclaringType &&
2188 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2189 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2190 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2191 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2195 return (right_side != null)
2196 ? me.DoResolveLValue (ec, right_side)
2197 : me.DoResolve (ec);
2203 public override void Emit (EmitContext ec)
2206 // If this is ever reached, then we failed to
2207 // find the name as a namespace
2210 Error (103, "The name `" + Name +
2211 "' does not exist in the class `" +
2212 ec.DeclContainer.Name + "'");
2215 public override string ToString ()
2220 public override string GetSignatureForError ()
2227 /// Represents a namespace or a type. The name of the class was inspired by
2228 /// section 10.8.1 (Fully Qualified Names).
2230 public abstract class FullNamedExpression : Expression {
2231 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2236 public abstract string FullName {
2242 /// Expression that evaluates to a type
2244 public abstract class TypeExpr : FullNamedExpression {
2245 override public FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2247 TypeExpr t = DoResolveAsTypeStep (ec);
2251 eclass = ExprClass.Type;
2255 override public Expression DoResolve (EmitContext ec)
2257 return ResolveAsTypeTerminal (ec, false);
2260 override public void Emit (EmitContext ec)
2262 throw new Exception ("Should never be called");
2265 public virtual bool CheckAccessLevel (DeclSpace ds)
2267 return ds.CheckAccessLevel (Type);
2270 public virtual bool AsAccessible (DeclSpace ds, int flags)
2272 return ds.AsAccessible (Type, flags);
2275 public virtual bool IsClass {
2276 get { return Type.IsClass; }
2279 public virtual bool IsValueType {
2280 get { return Type.IsValueType; }
2283 public virtual bool IsInterface {
2284 get { return Type.IsInterface; }
2287 public virtual bool IsSealed {
2288 get { return Type.IsSealed; }
2291 public virtual bool CanInheritFrom ()
2293 if (Type == TypeManager.enum_type ||
2294 (Type == TypeManager.value_type && RootContext.StdLib) ||
2295 Type == TypeManager.multicast_delegate_type ||
2296 Type == TypeManager.delegate_type ||
2297 Type == TypeManager.array_type)
2303 protected abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
2305 public Type ResolveType (EmitContext ec)
2307 TypeExpr t = ResolveAsTypeTerminal (ec, false);
2311 if (ec.TestObsoleteMethodUsage) {
2312 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (t.Type);
2313 if (obsolete_attr != null) {
2314 AttributeTester.Report_ObsoleteMessage (obsolete_attr, Name, Location);
2321 public abstract string Name {
2325 public override bool Equals (object obj)
2327 TypeExpr tobj = obj as TypeExpr;
2331 return Type == tobj.Type;
2334 public override int GetHashCode ()
2336 return Type.GetHashCode ();
2339 public override string ToString ()
2346 /// Fully resolved Expression that already evaluated to a type
2348 public class TypeExpression : TypeExpr {
2349 public TypeExpression (Type t, Location l)
2352 eclass = ExprClass.Type;
2356 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2361 public override string Name {
2362 get { return Type.ToString (); }
2365 public override string FullName {
2366 get { return Type.FullName; }
2371 /// Used to create types from a fully qualified name. These are just used
2372 /// by the parser to setup the core types. A TypeLookupExpression is always
2373 /// classified as a type.
2375 public class TypeLookupExpression : TypeExpr {
2378 public TypeLookupExpression (string name)
2383 static readonly char [] dot_array = { '.' };
2384 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2389 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2391 string lookup_name = name;
2392 int pos = name.IndexOf ('.');
2394 rest = name.Substring (pos + 1);
2395 lookup_name = name.Substring (0, pos);
2398 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2400 if (resolved != null && rest != null) {
2401 // Now handle the rest of the the name.
2402 string [] elements = rest.Split (dot_array);
2404 int count = elements.Length;
2406 while (i < count && resolved != null && resolved is Namespace) {
2407 Namespace ns = resolved as Namespace;
2408 element = elements [i++];
2409 lookup_name += "." + element;
2410 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2413 if (resolved != null && resolved is TypeExpr) {
2414 Type t = ((TypeExpr) resolved).Type;
2416 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2418 lookup_name = t.FullName;
2425 t = TypeManager.GetNestedType (t, elements [i++]);
2430 if (resolved == null) {
2431 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2435 if (!(resolved is TypeExpr)) {
2436 resolved.Error_UnexpectedKind (ec, "type", loc);
2440 type = ((TypeExpr) resolved).ResolveType (ec);
2444 public override string Name {
2445 get { return name; }
2448 public override string FullName {
2449 get { return name; }
2454 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2457 public class UnboundTypeExpression : TypeExpr
2461 public UnboundTypeExpression (MemberName name, Location l)
2467 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2470 if (name.Left != null) {
2471 Expression lexpr = name.Left.GetTypeExpression ();
2472 expr = new MemberAccess (lexpr, name.Basename, loc);
2474 expr = new SimpleName (name.Basename, loc);
2477 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2482 return new TypeExpression (type, loc);
2485 public override string Name {
2486 get { return name.FullName; }
2489 public override string FullName {
2490 get { return name.FullName; }
2494 public class TypeAliasExpression : TypeExpr {
2495 FullNamedExpression alias;
2500 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2506 eclass = ExprClass.Type;
2508 name = alias.FullName + "<" + args.ToString () + ">";
2510 name = alias.FullName;
2513 public override string Name {
2514 get { return alias.FullName; }
2517 public override string FullName {
2518 get { return name; }
2521 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2523 texpr = alias.ResolveAsTypeTerminal (ec, false);
2527 Type type = texpr.ResolveType (ec);
2528 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2531 if (num_args == 0) {
2532 Report.Error (308, loc,
2533 "The non-generic type `{0}' cannot " +
2534 "be used with type arguments.",
2535 TypeManager.CSharpName (type));
2539 ConstructedType ctype = new ConstructedType (type, args, loc);
2540 return ctype.ResolveAsTypeTerminal (ec, false);
2541 } else if (num_args > 0) {
2542 Report.Error (305, loc,
2543 "Using the generic type `{0}' " +
2544 "requires {1} type arguments",
2545 TypeManager.CSharpName (type), num_args.ToString ());
2549 return new TypeExpression (type, loc);
2552 public override bool CheckAccessLevel (DeclSpace ds)
2554 return texpr.CheckAccessLevel (ds);
2557 public override bool AsAccessible (DeclSpace ds, int flags)
2559 return texpr.AsAccessible (ds, flags);
2562 public override bool IsClass {
2563 get { return texpr.IsClass; }
2566 public override bool IsValueType {
2567 get { return texpr.IsValueType; }
2570 public override bool IsInterface {
2571 get { return texpr.IsInterface; }
2574 public override bool IsSealed {
2575 get { return texpr.IsSealed; }
2580 /// This class denotes an expression which evaluates to a member
2581 /// of a struct or a class.
2583 public abstract class MemberExpr : Expression
2586 /// The name of this member.
2588 public abstract string Name {
2593 /// Whether this is an instance member.
2595 public abstract bool IsInstance {
2600 /// Whether this is a static member.
2602 public abstract bool IsStatic {
2607 /// The type which declares this member.
2609 public abstract Type DeclaringType {
2614 /// The instance expression associated with this member, if it's a
2615 /// non-static member.
2617 public Expression InstanceExpression;
2619 public static void error176 (Location loc, string name)
2621 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2622 "with an instance reference, qualify it with a type name instead", name);
2625 // TODO: possible optimalization
2626 // Cache resolved constant result in FieldBuilder <-> expression map
2627 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2628 SimpleName original)
2632 // original == null || original.Resolve (...) ==> left
2635 if (left is TypeExpr) {
2637 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2645 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2648 error176 (loc, GetSignatureForError ());
2652 InstanceExpression = left;
2657 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2662 if (InstanceExpression == EmptyExpression.Null) {
2663 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2667 if (InstanceExpression.Type.IsValueType) {
2668 if (InstanceExpression is IMemoryLocation) {
2669 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2671 LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
2672 InstanceExpression.Emit (ec);
2674 t.AddressOf (ec, AddressOp.Store);
2677 InstanceExpression.Emit (ec);
2679 if (prepare_for_load)
2680 ec.ig.Emit (OpCodes.Dup);
2685 /// MethodGroup Expression.
2687 /// This is a fully resolved expression that evaluates to a type
2689 public class MethodGroupExpr : MemberExpr {
2690 public MethodBase [] Methods;
2691 bool has_type_arguments = false;
2692 bool identical_type_name = false;
2695 public MethodGroupExpr (MemberInfo [] mi, Location l)
2697 Methods = new MethodBase [mi.Length];
2698 mi.CopyTo (Methods, 0);
2699 eclass = ExprClass.MethodGroup;
2700 type = TypeManager.object_type;
2704 public MethodGroupExpr (ArrayList list, Location l)
2706 Methods = new MethodBase [list.Count];
2709 list.CopyTo (Methods, 0);
2711 foreach (MemberInfo m in list){
2712 if (!(m is MethodBase)){
2713 Console.WriteLine ("Name " + m.Name);
2714 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2721 eclass = ExprClass.MethodGroup;
2722 type = TypeManager.object_type;
2725 public override Type DeclaringType {
2728 // We assume that the top-level type is in the end
2730 return Methods [Methods.Length - 1].DeclaringType;
2731 //return Methods [0].DeclaringType;
2735 public bool HasTypeArguments {
2737 return has_type_arguments;
2741 has_type_arguments = value;
2745 public bool IdenticalTypeName {
2747 return identical_type_name;
2751 identical_type_name = value;
2755 public bool IsBase {
2764 public override string GetSignatureForError ()
2766 return TypeManager.CSharpSignature (Methods [0]);
2769 public override string Name {
2771 return Methods [0].Name;
2775 public override bool IsInstance {
2777 foreach (MethodBase mb in Methods)
2785 public override bool IsStatic {
2787 foreach (MethodBase mb in Methods)
2795 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2796 SimpleName original)
2798 if (!(left is TypeExpr) &&
2799 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2800 IdenticalTypeName = true;
2802 return base.ResolveMemberAccess (ec, left, loc, original);
2805 override public Expression DoResolve (EmitContext ec)
2808 InstanceExpression = null;
2810 if (InstanceExpression != null) {
2811 InstanceExpression = InstanceExpression.DoResolve (ec);
2812 if (InstanceExpression == null)
2819 public void ReportUsageError ()
2821 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2822 Name + "()' is referenced without parentheses");
2825 override public void Emit (EmitContext ec)
2827 ReportUsageError ();
2830 bool RemoveMethods (bool keep_static)
2832 ArrayList smethods = new ArrayList ();
2834 foreach (MethodBase mb in Methods){
2835 if (mb.IsStatic == keep_static)
2839 if (smethods.Count == 0)
2842 Methods = new MethodBase [smethods.Count];
2843 smethods.CopyTo (Methods, 0);
2849 /// Removes any instance methods from the MethodGroup, returns
2850 /// false if the resulting set is empty.
2852 public bool RemoveInstanceMethods ()
2854 return RemoveMethods (true);
2858 /// Removes any static methods from the MethodGroup, returns
2859 /// false if the resulting set is empty.
2861 public bool RemoveStaticMethods ()
2863 return RemoveMethods (false);
2866 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2868 if (args.Resolve (ec) == false)
2871 Type[] atypes = args.Arguments;
2873 int first_count = 0;
2874 MethodInfo first = null;
2876 ArrayList list = new ArrayList ();
2877 foreach (MethodBase mb in Methods) {
2878 MethodInfo mi = mb as MethodInfo;
2879 if ((mi == null) || !mi.IsGenericMethod)
2882 Type[] gen_params = mi.GetGenericArguments ();
2884 if (first == null) {
2886 first_count = gen_params.Length;
2889 if (gen_params.Length != atypes.Length)
2892 list.Add (mi.MakeGenericMethod (atypes));
2895 if (list.Count > 0) {
2896 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2897 new_mg.InstanceExpression = InstanceExpression;
2898 new_mg.HasTypeArguments = true;
2899 new_mg.IsBase = IsBase;
2905 305, loc, "Using the generic method `{0}' " +
2906 "requires {1} type arguments", Name,
2907 first_count.ToString ());
2910 308, loc, "The non-generic method `{0}' " +
2911 "cannot be used with type arguments", Name);
2918 /// Fully resolved expression that evaluates to a Field
2920 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2921 public readonly FieldInfo FieldInfo;
2922 VariableInfo variable_info;
2924 LocalTemporary temp;
2926 bool in_initializer;
2928 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2931 this.in_initializer = in_initializer;
2934 public FieldExpr (FieldInfo fi, Location l)
2937 eclass = ExprClass.Variable;
2938 type = TypeManager.TypeToCoreType (fi.FieldType);
2942 public override string Name {
2944 return FieldInfo.Name;
2948 public override bool IsInstance {
2950 return !FieldInfo.IsStatic;
2954 public override bool IsStatic {
2956 return FieldInfo.IsStatic;
2960 public override Type DeclaringType {
2962 return FieldInfo.DeclaringType;
2966 public override string GetSignatureForError ()
2968 return TypeManager.GetFullNameSignature (FieldInfo);
2971 public VariableInfo VariableInfo {
2973 return variable_info;
2977 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2978 SimpleName original)
2980 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
2982 Type t = fi.FieldType;
2984 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
2985 IConstant ic = TypeManager.GetConstant (fi);
2988 ic = new ExternalConstant (fi);
2990 ic = ExternalConstant.CreateDecimal (fi);
2992 return base.ResolveMemberAccess (ec, left, loc, original);
2995 TypeManager.RegisterConstant (fi, ic);
2998 bool left_is_type = left is TypeExpr;
2999 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3000 Report.SymbolRelatedToPreviousError (FieldInfo);
3001 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3005 if (ic.ResolveValue ()) {
3006 if (ec.TestObsoleteMethodUsage)
3007 ic.CheckObsoleteness (loc);
3013 if (t.IsPointer && !ec.InUnsafe) {
3018 return base.ResolveMemberAccess (ec, left, loc, original);
3021 override public Expression DoResolve (EmitContext ec)
3023 return DoResolve (ec, false);
3026 Expression DoResolve (EmitContext ec, bool lvalue_instance)
3028 if (ec.InRefOutArgumentResolving && FieldInfo.IsInitOnly && !ec.IsConstructor && FieldInfo.FieldType.IsValueType) {
3029 if (FieldInfo.FieldType is TypeBuilder) {
3030 if (FieldInfo.IsStatic)
3031 Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3032 GetSignatureForError ());
3034 Report.Error (1649, loc, "Members of readonly field `{0}.{1}' cannot be passed ref or out (except in a constructor)",
3035 TypeManager.CSharpName (DeclaringType), Name);
3037 if (FieldInfo.IsStatic)
3038 Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3041 Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3047 if (!FieldInfo.IsStatic){
3048 if (InstanceExpression == null){
3050 // This can happen when referencing an instance field using
3051 // a fully qualified type expression: TypeName.InstanceField = xxx
3053 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3057 // Resolve the field's instance expression while flow analysis is turned
3058 // off: when accessing a field "a.b", we must check whether the field
3059 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3061 if (lvalue_instance) {
3062 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3063 ec.DoFlowAnalysis = false;
3064 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3065 ec.DoFlowAnalysis = old_do_flow_analysis;
3067 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3068 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3071 if (InstanceExpression == null)
3075 if (!in_initializer && !ec.IsFieldInitializer) {
3076 ObsoleteAttribute oa;
3077 FieldBase f = TypeManager.GetField (FieldInfo);
3079 if (ec.TestObsoleteMethodUsage)
3080 f.CheckObsoleteness (loc);
3081 // To be sure that type is external because we do not register generated fields
3082 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3083 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3085 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3089 AnonymousContainer am = ec.CurrentAnonymousMethod;
3091 if (!FieldInfo.IsStatic){
3092 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3093 Report.Error (1673, loc,
3094 "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",
3098 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3099 ec.CaptureField (this);
3103 // If the instance expression is a local variable or parameter.
3104 IVariable var = InstanceExpression as IVariable;
3105 if ((var == null) || (var.VariableInfo == null))
3108 VariableInfo vi = var.VariableInfo;
3109 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3112 variable_info = vi.GetSubStruct (FieldInfo.Name);
3116 void Report_AssignToReadonly (Expression right_side)
3120 bool need_error_sig = false;
3121 if (right_side == EmptyExpression.LValueMemberAccess) {
3124 msg = "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)";
3127 msg = "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)";
3129 need_error_sig = true;
3130 } else if (IsStatic) {
3132 msg = "A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)";
3135 msg = "A readonly field cannot be assigned to (except in a constructor or a variable initializer)";
3139 Report.Error (code, loc, msg, GetSignatureForError ());
3141 Report.Error (code, loc, msg);
3144 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3146 IVariable var = InstanceExpression as IVariable;
3147 if ((var != null) && (var.VariableInfo != null))
3148 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3150 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3152 Expression e = DoResolve (ec, lvalue_instance);
3157 FieldBase fb = TypeManager.GetField (FieldInfo);
3161 if (!FieldInfo.IsInitOnly)
3165 // InitOnly fields can only be assigned in constructors
3168 if (ec.IsConstructor){
3169 if (IsStatic && !ec.IsStatic)
3170 Report_AssignToReadonly (right_side);
3173 if (ec.TypeContainer.CurrentType != null)
3174 ctype = ec.TypeContainer.CurrentType;
3176 ctype = ec.ContainerType;
3178 if (TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3182 Report_AssignToReadonly (right_side);
3187 public override void CheckMarshallByRefAccess (Type container)
3189 if (!IsStatic && Type.IsValueType && !container.IsSubclassOf (TypeManager.mbr_type) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3190 Report.SymbolRelatedToPreviousError (DeclaringType);
3191 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",
3192 GetSignatureForError ());
3196 public bool VerifyFixed ()
3198 IVariable variable = InstanceExpression as IVariable;
3199 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3200 // We defer the InstanceExpression check after the variable check to avoid a
3201 // separate null check on InstanceExpression.
3202 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3205 public override int GetHashCode()
3207 return FieldInfo.GetHashCode ();
3210 public override bool Equals (object obj)
3212 FieldExpr fe = obj as FieldExpr;
3216 if (FieldInfo != fe.FieldInfo)
3219 if (InstanceExpression == null || fe.InstanceExpression == null)
3222 return InstanceExpression.Equals (fe.InstanceExpression);
3225 public void Emit (EmitContext ec, bool leave_copy)
3227 ILGenerator ig = ec.ig;
3228 bool is_volatile = false;
3230 FieldBase f = TypeManager.GetField (FieldInfo);
3232 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3235 f.SetMemberIsUsed ();
3238 if (FieldInfo.IsStatic){
3240 ig.Emit (OpCodes.Volatile);
3242 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3245 EmitInstance (ec, false);
3248 ig.Emit (OpCodes.Volatile);
3250 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3253 ig.Emit (OpCodes.Ldflda, FieldInfo);
3254 ig.Emit (OpCodes.Ldflda, ff.Element);
3257 ig.Emit (OpCodes.Ldfld, FieldInfo);
3262 ec.ig.Emit (OpCodes.Dup);
3263 if (!FieldInfo.IsStatic) {
3264 temp = new LocalTemporary (ec, this.Type);
3270 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3272 FieldAttributes fa = FieldInfo.Attributes;
3273 bool is_static = (fa & FieldAttributes.Static) != 0;
3274 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3275 ILGenerator ig = ec.ig;
3276 prepared = prepare_for_load;
3278 if (is_readonly && !ec.IsConstructor){
3279 Report_AssignToReadonly (source);
3283 EmitInstance (ec, prepare_for_load);
3287 ec.ig.Emit (OpCodes.Dup);
3288 if (!FieldInfo.IsStatic) {
3289 temp = new LocalTemporary (ec, this.Type);
3294 if (FieldInfo is FieldBuilder){
3295 FieldBase f = TypeManager.GetField (FieldInfo);
3297 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3298 ig.Emit (OpCodes.Volatile);
3305 ig.Emit (OpCodes.Stsfld, FieldInfo);
3307 ig.Emit (OpCodes.Stfld, FieldInfo);
3313 public override void Emit (EmitContext ec)
3318 public void AddressOf (EmitContext ec, AddressOp mode)
3320 ILGenerator ig = ec.ig;
3322 if (FieldInfo is FieldBuilder){
3323 FieldBase f = TypeManager.GetField (FieldInfo);
3325 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3326 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3327 f.GetSignatureForError ());
3331 if ((mode & AddressOp.Store) != 0)
3333 if ((mode & AddressOp.Load) != 0)
3334 f.SetMemberIsUsed ();
3339 // Handle initonly fields specially: make a copy and then
3340 // get the address of the copy.
3343 if (FieldInfo.IsInitOnly){
3345 if (ec.IsConstructor){
3346 if (FieldInfo.IsStatic){
3358 local = ig.DeclareLocal (type);
3359 ig.Emit (OpCodes.Stloc, local);
3360 ig.Emit (OpCodes.Ldloca, local);
3365 if (FieldInfo.IsStatic){
3366 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3369 EmitInstance (ec, false);
3370 ig.Emit (OpCodes.Ldflda, FieldInfo);
3376 // A FieldExpr whose address can not be taken
3378 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3379 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3383 public new void AddressOf (EmitContext ec, AddressOp mode)
3385 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3390 /// Expression that evaluates to a Property. The Assign class
3391 /// might set the `Value' expression if we are in an assignment.
3393 /// This is not an LValue because we need to re-write the expression, we
3394 /// can not take data from the stack and store it.
3396 public class PropertyExpr : MemberExpr, IAssignMethod {
3397 public readonly PropertyInfo PropertyInfo;
3400 // This is set externally by the `BaseAccess' class
3403 MethodInfo getter, setter;
3408 LocalTemporary temp;
3411 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3413 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3416 eclass = ExprClass.PropertyAccess;
3420 type = TypeManager.TypeToCoreType (pi.PropertyType);
3422 ResolveAccessors (containerType);
3425 public override string Name {
3427 return PropertyInfo.Name;
3431 public override bool IsInstance {
3437 public override bool IsStatic {
3443 public override Type DeclaringType {
3445 return PropertyInfo.DeclaringType;
3449 public override string GetSignatureForError ()
3451 return TypeManager.GetFullNameSignature (PropertyInfo);
3454 void FindAccessors (Type invocation_type)
3456 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3457 BindingFlags.Static | BindingFlags.Instance |
3458 BindingFlags.DeclaredOnly;
3460 Type current = PropertyInfo.DeclaringType;
3461 for (; current != null; current = current.BaseType) {
3462 MemberInfo[] group = TypeManager.MemberLookup (
3463 invocation_type, invocation_type, current,
3464 MemberTypes.Property, flags, PropertyInfo.Name, null);
3469 if (group.Length != 1)
3470 // Oooops, can this ever happen ?
3473 PropertyInfo pi = (PropertyInfo) group [0];
3476 getter = pi.GetGetMethod (true);
3479 setter = pi.GetSetMethod (true);
3481 MethodInfo accessor = getter != null ? getter : setter;
3483 if (!accessor.IsVirtual)
3489 // We also perform the permission checking here, as the PropertyInfo does not
3490 // hold the information for the accessibility of its setter/getter
3492 void ResolveAccessors (Type containerType)
3494 FindAccessors (containerType);
3496 if (getter != null) {
3497 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3498 IMethodData md = TypeManager.GetMethod (the_getter);
3500 md.SetMemberIsUsed ();
3502 AccessorTable [getter] = PropertyInfo;
3503 is_static = getter.IsStatic;
3506 if (setter != null) {
3507 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3508 IMethodData md = TypeManager.GetMethod (the_setter);
3510 md.SetMemberIsUsed ();
3512 AccessorTable [setter] = PropertyInfo;
3513 is_static = setter.IsStatic;
3517 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3520 InstanceExpression = null;
3524 if (InstanceExpression == null) {
3525 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3529 if (lvalue_instance)
3530 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3532 InstanceExpression = InstanceExpression.DoResolve (ec);
3533 if (InstanceExpression == null)
3536 InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
3538 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3539 InstanceExpression.Type != ec.ContainerType &&
3540 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3541 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3542 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3549 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3551 // TODO: correctly we should compare arguments but it will lead to bigger changes
3552 if (mi is MethodBuilder) {
3553 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3557 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3559 ParameterData iparams = TypeManager.GetParameterData (mi);
3560 sig.Append (getter ? "get_" : "set_");
3562 sig.Append (iparams.GetSignatureForError ());
3564 Report.SymbolRelatedToPreviousError (mi);
3565 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3566 Name, sig.ToString ());
3569 override public Expression DoResolve (EmitContext ec)
3574 if (getter != null){
3575 if (TypeManager.GetParameterData (getter).Count != 0){
3576 Error_PropertyNotFound (getter, true);
3581 if (getter == null){
3583 // The following condition happens if the PropertyExpr was
3584 // created, but is invalid (ie, the property is inaccessible),
3585 // and we did not want to embed the knowledge about this in
3586 // the caller routine. This only avoids double error reporting.
3591 if (InstanceExpression != EmptyExpression.Null) {
3592 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3593 TypeManager.GetFullNameSignature (PropertyInfo));
3598 bool must_do_cs1540_check = false;
3599 if (getter != null &&
3600 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3601 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3602 if (pm != null && pm.HasCustomAccessModifier) {
3603 Report.SymbolRelatedToPreviousError (pm);
3604 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3605 TypeManager.CSharpSignature (getter));
3608 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3612 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3616 // Only base will allow this invocation to happen.
3618 if (IsBase && getter.IsAbstract) {
3619 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3623 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3633 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3635 if (right_side == EmptyExpression.OutAccess) {
3636 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3637 GetSignatureForError ());
3641 if (right_side == EmptyExpression.LValueMemberAccess) {
3642 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3643 GetSignatureForError ());
3647 if (setter == null){
3649 // The following condition happens if the PropertyExpr was
3650 // created, but is invalid (ie, the property is inaccessible),
3651 // and we did not want to embed the knowledge about this in
3652 // the caller routine. This only avoids double error reporting.
3656 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3657 GetSignatureForError ());
3661 if (TypeManager.GetParameterData (setter).Count != 1){
3662 Error_PropertyNotFound (setter, false);
3666 bool must_do_cs1540_check;
3667 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3668 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3669 if (pm != null && pm.HasCustomAccessModifier) {
3670 Report.SymbolRelatedToPreviousError (pm);
3671 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3672 TypeManager.CSharpSignature (setter));
3675 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3679 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3683 // Only base will allow this invocation to happen.
3685 if (IsBase && setter.IsAbstract){
3686 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3693 public override void Emit (EmitContext ec)
3698 public void Emit (EmitContext ec, bool leave_copy)
3701 // Special case: length of single dimension array property is turned into ldlen
3703 if ((getter == TypeManager.system_int_array_get_length) ||
3704 (getter == TypeManager.int_array_get_length)){
3705 Type iet = InstanceExpression.Type;
3708 // System.Array.Length can be called, but the Type does not
3709 // support invoking GetArrayRank, so test for that case first
3711 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3713 EmitInstance (ec, false);
3714 ec.ig.Emit (OpCodes.Ldlen);
3715 ec.ig.Emit (OpCodes.Conv_I4);
3720 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3723 ec.ig.Emit (OpCodes.Dup);
3725 temp = new LocalTemporary (ec, this.Type);
3732 // Implements the IAssignMethod interface for assignments
3734 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3736 Expression my_source = source;
3738 prepared = prepare_for_load;
3743 ec.ig.Emit (OpCodes.Dup);
3745 temp = new LocalTemporary (ec, this.Type);
3749 } else if (leave_copy) {
3752 temp = new LocalTemporary (ec, this.Type);
3758 ArrayList args = new ArrayList (1);
3759 args.Add (new Argument (my_source, Argument.AType.Expression));
3761 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3769 /// Fully resolved expression that evaluates to an Event
3771 public class EventExpr : MemberExpr {
3772 public readonly EventInfo EventInfo;
3775 MethodInfo add_accessor, remove_accessor;
3777 public EventExpr (EventInfo ei, Location loc)
3781 eclass = ExprClass.EventAccess;
3783 add_accessor = TypeManager.GetAddMethod (ei);
3784 remove_accessor = TypeManager.GetRemoveMethod (ei);
3786 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3789 if (EventInfo is MyEventBuilder){
3790 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3791 type = eb.EventType;
3794 type = EventInfo.EventHandlerType;
3797 public override string Name {
3799 return EventInfo.Name;
3803 public override bool IsInstance {
3809 public override bool IsStatic {
3815 public override Type DeclaringType {
3817 return EventInfo.DeclaringType;
3821 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3822 SimpleName original)
3825 // If the event is local to this class, we transform ourselves into a FieldExpr
3828 if (EventInfo.DeclaringType == ec.ContainerType ||
3829 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3830 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3833 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3836 Report.Error (-200, loc, "Internal error!!");
3840 InstanceExpression = null;
3842 return ml.ResolveMemberAccess (ec, left, loc, original);
3846 return base.ResolveMemberAccess (ec, left, loc, original);
3850 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3853 InstanceExpression = null;
3857 if (InstanceExpression == null) {
3858 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
3862 InstanceExpression = InstanceExpression.DoResolve (ec);
3863 if (InstanceExpression == null)
3867 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3868 // However, in the Event case, we reported a CS0122 instead.
3870 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3871 InstanceExpression.Type != ec.ContainerType &&
3872 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3873 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3880 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3882 return DoResolve (ec);
3885 public override Expression DoResolve (EmitContext ec)
3887 bool must_do_cs1540_check;
3888 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3889 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3890 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3894 if (!InstanceResolve (ec, must_do_cs1540_check))
3900 public override void Emit (EmitContext ec)
3902 if (InstanceExpression is This)
3903 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3905 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3906 "(except on the defining type)", Name);
3909 public override string GetSignatureForError ()
3911 return TypeManager.CSharpSignature (EventInfo);
3914 public void EmitAddOrRemove (EmitContext ec, Expression source)
3916 BinaryDelegate source_del = (BinaryDelegate) source;
3917 Expression handler = source_del.Right;
3919 Argument arg = new Argument (handler, Argument.AType.Expression);
3920 ArrayList args = new ArrayList ();
3924 if (source_del.IsAddition)
3925 Invocation.EmitCall (
3926 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3928 Invocation.EmitCall (
3929 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3934 public class TemporaryVariable : Expression, IMemoryLocation
3938 public TemporaryVariable (Type type, Location loc)
3942 eclass = ExprClass.Value;
3945 public override Expression DoResolve (EmitContext ec)
3950 TypeExpr te = new TypeExpression (type, loc);
3951 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3952 if (!li.Resolve (ec))
3955 AnonymousContainer am = ec.CurrentAnonymousMethod;
3956 if ((am != null) && am.IsIterator)
3957 ec.CaptureVariable (li);
3962 public override void Emit (EmitContext ec)
3964 ILGenerator ig = ec.ig;
3966 if (li.FieldBuilder != null) {
3967 ig.Emit (OpCodes.Ldarg_0);
3968 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3970 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3974 public void EmitLoadAddress (EmitContext ec)
3976 ILGenerator ig = ec.ig;
3978 if (li.FieldBuilder != null) {
3979 ig.Emit (OpCodes.Ldarg_0);
3980 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
3982 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
3986 public void Store (EmitContext ec, Expression right_side)
3988 if (li.FieldBuilder != null)
3989 ec.ig.Emit (OpCodes.Ldarg_0);
3991 right_side.Emit (ec);
3992 if (li.FieldBuilder != null) {
3993 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
3995 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
3999 public void EmitThis (EmitContext ec)
4001 if (li.FieldBuilder != null) {
4002 ec.ig.Emit (OpCodes.Ldarg_0);
4006 public void EmitStore (ILGenerator ig)
4008 if (li.FieldBuilder != null)
4009 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4011 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4014 public void AddressOf (EmitContext ec, AddressOp mode)
4016 EmitLoadAddress (ec);