2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
243 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
244 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
245 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 // Constrains don't need to be checked for overrides
250 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
251 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
256 ConstructedType ct = te as ConstructedType;
257 if ((ct != null) && !ct.CheckConstraints (ec))
263 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
265 int errors = Report.Errors;
267 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
270 if (!silent && errors == Report.Errors)
271 Report.Error (118, loc, "Expecting a type.");
275 if (fne.eclass != ExprClass.Type) {
276 if (!silent && errors == Report.Errors)
277 fne.Error_UnexpectedKind (null, "type", loc);
281 TypeExpr te = fne as TypeExpr;
283 if (!te.CheckAccessLevel (ec.DeclContainer)) {
284 Report.SymbolRelatedToPreviousError (te.Type);
285 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
293 public static void ErrorIsInaccesible (Location loc, string name)
295 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
298 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
300 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
301 + " the qualifier must be of type `{2}' (or derived from it)",
302 TypeManager.GetFullNameSignature (m),
303 TypeManager.CSharpName (qualifier),
304 TypeManager.CSharpName (container));
308 protected void Error_CannotAssign (string to, string roContext)
310 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
314 public static void Error_VoidInvalidInTheContext (Location loc)
316 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
319 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
321 if (Type.FullName == target.FullName){
322 Report.ExtraInformation (loc,
324 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
325 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
330 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
331 GetSignatureForError (), TypeManager.CSharpName (target));
335 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
336 bool b = Convert.ExplicitNumericConversion (e, target) != null;
338 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
339 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
340 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
344 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
345 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
346 GetSignatureForError (), TypeManager.CSharpName (target));
350 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
351 Type == TypeManager.anonymous_method_type ?
352 "anonymous method" : "`" + GetSignatureForError () + "'",
353 TypeManager.CSharpName (target));
356 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
358 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
359 TypeManager.CSharpName (type), name);
362 ResolveFlags ExprClassToResolveFlags
367 case ExprClass.Namespace:
368 return ResolveFlags.Type;
370 case ExprClass.MethodGroup:
371 return ResolveFlags.MethodGroup;
373 case ExprClass.Value:
374 case ExprClass.Variable:
375 case ExprClass.PropertyAccess:
376 case ExprClass.EventAccess:
377 case ExprClass.IndexerAccess:
378 return ResolveFlags.VariableOrValue;
381 throw new Exception ("Expression " + GetType () +
382 " ExprClass is Invalid after resolve");
388 /// Resolves an expression and performs semantic analysis on it.
392 /// Currently Resolve wraps DoResolve to perform sanity
393 /// checking and assertion checking on what we expect from Resolve.
395 public Expression Resolve (EmitContext ec, ResolveFlags flags)
397 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
398 return ResolveAsTypeStep (ec, false);
400 bool do_flow_analysis = ec.DoFlowAnalysis;
401 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
402 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
403 do_flow_analysis = false;
404 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
405 omit_struct_analysis = true;
408 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
409 if (this is SimpleName) {
410 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
411 e = ((SimpleName) this).DoResolve (ec, intermediate);
420 if ((flags & e.ExprClassToResolveFlags) == 0) {
421 e.Error_UnexpectedKind (flags, loc);
425 if (e.type == null && !(e is Namespace)) {
426 throw new Exception (
427 "Expression " + e.GetType () +
428 " did not set its type after Resolve\n" +
429 "called from: " + this.GetType ());
436 /// Resolves an expression and performs semantic analysis on it.
438 public Expression Resolve (EmitContext ec)
440 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
442 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
443 ((MethodGroupExpr) e).ReportUsageError ();
449 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
451 Expression e = Resolve (ec);
455 Constant c = e as Constant;
459 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
464 /// Resolves an expression for LValue assignment
468 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
469 /// checking and assertion checking on what we expect from Resolve
471 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
473 int errors = Report.Errors;
474 bool out_access = right_side == EmptyExpression.OutAccess;
476 Expression e = DoResolveLValue (ec, right_side);
478 if (e != null && out_access && !(e is IMemoryLocation)) {
479 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
480 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
482 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
483 // e.GetType () + " " + e.GetSignatureForError ());
488 if (errors == Report.Errors) {
490 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
492 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
497 if (e.eclass == ExprClass.Invalid)
498 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
500 if (e.eclass == ExprClass.MethodGroup) {
501 ((MethodGroupExpr) e).ReportUsageError ();
505 if ((e.type == null) && !(e is ConstructedType))
506 throw new Exception ("Expression " + e + " did not set its type after Resolve");
512 /// Emits the code for the expression
516 /// The Emit method is invoked to generate the code
517 /// for the expression.
519 public abstract void Emit (EmitContext ec);
521 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
524 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
528 /// Protected constructor. Only derivate types should
529 /// be able to be created
532 protected Expression ()
534 eclass = ExprClass.Invalid;
539 /// Returns a literalized version of a literal FieldInfo
543 /// The possible return values are:
544 /// IntConstant, UIntConstant
545 /// LongLiteral, ULongConstant
546 /// FloatConstant, DoubleConstant
549 /// The value returned is already resolved.
551 public static Constant Constantify (object v, Type t)
553 if (t == TypeManager.int32_type)
554 return new IntConstant ((int) v, Location.Null);
555 else if (t == TypeManager.uint32_type)
556 return new UIntConstant ((uint) v, Location.Null);
557 else if (t == TypeManager.int64_type)
558 return new LongConstant ((long) v, Location.Null);
559 else if (t == TypeManager.uint64_type)
560 return new ULongConstant ((ulong) v, Location.Null);
561 else if (t == TypeManager.float_type)
562 return new FloatConstant ((float) v, Location.Null);
563 else if (t == TypeManager.double_type)
564 return new DoubleConstant ((double) v, Location.Null);
565 else if (t == TypeManager.string_type)
566 return new StringConstant ((string) v, Location.Null);
567 else if (t == TypeManager.short_type)
568 return new ShortConstant ((short)v, Location.Null);
569 else if (t == TypeManager.ushort_type)
570 return new UShortConstant ((ushort)v, Location.Null);
571 else if (t == TypeManager.sbyte_type)
572 return new SByteConstant ((sbyte)v, Location.Null);
573 else if (t == TypeManager.byte_type)
574 return new ByteConstant ((byte)v, Location.Null);
575 else if (t == TypeManager.char_type)
576 return new CharConstant ((char)v, Location.Null);
577 else if (t == TypeManager.bool_type)
578 return new BoolConstant ((bool) v, Location.Null);
579 else if (t == TypeManager.decimal_type)
580 return new DecimalConstant ((decimal) v, Location.Null);
581 else if (TypeManager.IsEnumType (t)){
582 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
584 real_type = System.Enum.GetUnderlyingType (real_type);
586 Constant e = Constantify (v, real_type);
588 return new EnumConstant (e, t);
589 } else if (v == null && !TypeManager.IsValueType (t))
590 return new NullLiteral (Location.Null);
592 throw new Exception ("Unknown type for constant (" + t +
597 /// Returns a fully formed expression after a MemberLookup
600 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
603 return new EventExpr ((EventInfo) mi, loc);
604 else if (mi is FieldInfo)
605 return new FieldExpr ((FieldInfo) mi, loc);
606 else if (mi is PropertyInfo)
607 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
608 else if (mi is Type){
609 return new TypeExpression ((System.Type) mi, loc);
615 protected static ArrayList almostMatchedMembers = new ArrayList (4);
618 // FIXME: Probably implement a cache for (t,name,current_access_set)?
620 // This code could use some optimizations, but we need to do some
621 // measurements. For example, we could use a delegate to `flag' when
622 // something can not any longer be a method-group (because it is something
626 // If the return value is an Array, then it is an array of
629 // If the return value is an MemberInfo, it is anything, but a Method
633 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
634 // the arguments here and have MemberLookup return only the methods that
635 // match the argument count/type, unlike we are doing now (we delay this
638 // This is so we can catch correctly attempts to invoke instance methods
639 // from a static body (scan for error 120 in ResolveSimpleName).
642 // FIXME: Potential optimization, have a static ArrayList
645 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
646 MemberTypes mt, BindingFlags bf, Location loc)
648 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
652 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
653 // `qualifier_type' or null to lookup members in the current class.
656 public static Expression MemberLookup (Type container_type,
657 Type qualifier_type, Type queried_type,
658 string name, MemberTypes mt,
659 BindingFlags bf, Location loc)
661 almostMatchedMembers.Clear ();
663 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
664 queried_type, mt, bf, name, almostMatchedMembers);
670 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
671 MemberInfo non_method = null;
672 ArrayList methods = new ArrayList (2);
674 foreach (MemberInfo m in mi) {
675 if (m is MethodBase) {
680 if (non_method == null) {
685 Report.SymbolRelatedToPreviousError (m);
686 Report.SymbolRelatedToPreviousError (non_method);
687 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
688 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
692 if (methods.Count == 0)
695 if (non_method != null) {
696 MethodBase method = (MethodBase) methods [0];
697 Report.SymbolRelatedToPreviousError (method);
698 Report.SymbolRelatedToPreviousError (non_method);
700 if (method.DeclaringType == non_method.DeclaringType) {
701 // Cannot happen with C# code, but is valid in IL
702 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
703 TypeManager.GetFullNameSignature (non_method),
704 TypeManager.CSharpSignature (method));
709 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
710 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
713 return new MethodGroupExpr (methods, loc);
716 if (mi [0] is MethodBase)
717 return new MethodGroupExpr (mi, loc);
719 return ExprClassFromMemberInfo (container_type, mi [0], loc);
722 public const MemberTypes AllMemberTypes =
723 MemberTypes.Constructor |
727 MemberTypes.NestedType |
728 MemberTypes.Property;
730 public const BindingFlags AllBindingFlags =
731 BindingFlags.Public |
732 BindingFlags.Static |
733 BindingFlags.Instance;
735 public static Expression MemberLookup (Type container_type, Type queried_type,
736 string name, Location loc)
738 return MemberLookup (container_type, null, queried_type, name,
739 AllMemberTypes, AllBindingFlags, loc);
742 public static Expression MemberLookup (Type container_type, Type qualifier_type,
743 Type queried_type, string name, Location loc)
745 return MemberLookup (container_type, qualifier_type, queried_type,
746 name, AllMemberTypes, AllBindingFlags, loc);
749 public static Expression MethodLookup (EmitContext ec, Type queried_type,
750 string name, Location loc)
752 return MemberLookup (ec.ContainerType, null, queried_type, name,
753 MemberTypes.Method, AllBindingFlags, loc);
757 /// This is a wrapper for MemberLookup that is not used to "probe", but
758 /// to find a final definition. If the final definition is not found, we
759 /// look for private members and display a useful debugging message if we
762 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
763 Type queried_type, string name, Location loc)
765 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
766 AllMemberTypes, AllBindingFlags, loc);
769 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
770 Type queried_type, string name,
771 MemberTypes mt, BindingFlags bf,
776 int errors = Report.Errors;
778 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
780 if (e == null && errors == Report.Errors)
781 // No errors were reported by MemberLookup, but there was an error.
782 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
787 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
788 Type queried_type, string name,
789 string class_name, bool complain_if_none_found,
792 if (almostMatchedMembers.Count != 0) {
793 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
794 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
795 for (int j = 0; j < i; ++j) {
796 if (m == almostMatchedMembers [j]) {
804 Type declaring_type = m.DeclaringType;
806 Report.SymbolRelatedToPreviousError (m);
807 if (qualifier_type == null) {
808 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
809 TypeManager.CSharpName (m.DeclaringType),
810 TypeManager.CSharpName (container_type));
812 } else if (qualifier_type != container_type &&
813 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
814 // Although a derived class can access protected members of
815 // its base class it cannot do so through an instance of the
816 // base class (CS1540). If the qualifier_type is a base of the
817 // ec.ContainerType and the lookup succeeds with the latter one,
818 // then we are in this situation.
819 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
821 Report.SymbolRelatedToPreviousError (m);
822 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
825 almostMatchedMembers.Clear ();
829 MemberInfo[] lookup = null;
830 if (queried_type == null) {
831 class_name = "global::";
833 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
834 AllMemberTypes, AllBindingFlags |
835 BindingFlags.NonPublic, name, null);
838 if (lookup == null) {
839 if (!complain_if_none_found)
842 if (class_name != null)
843 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
846 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
850 if (TypeManager.MemberLookup (queried_type, null, queried_type,
851 AllMemberTypes, AllBindingFlags |
852 BindingFlags.NonPublic, name, null) == null) {
853 if ((lookup.Length == 1) && (lookup [0] is Type)) {
854 Type t = (Type) lookup [0];
856 Report.Error (305, loc,
857 "Using the generic type `{0}' " +
858 "requires {1} type arguments",
859 TypeManager.CSharpName (t),
860 TypeManager.GetNumberOfTypeArguments (t).ToString ());
865 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
866 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
867 if (name == ".ctor" && ml.Count == 0)
869 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
873 Report.SymbolRelatedToPreviousError (lookup [0]);
874 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
878 /// Returns an expression that can be used to invoke operator true
879 /// on the expression if it exists.
881 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
883 return GetOperatorTrueOrFalse (ec, e, true, loc);
887 /// Returns an expression that can be used to invoke operator false
888 /// on the expression if it exists.
890 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
892 return GetOperatorTrueOrFalse (ec, e, false, loc);
895 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
898 Expression operator_group;
901 if (TypeManager.IsNullableType (e.Type))
902 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
905 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
906 if (operator_group == null)
909 ArrayList arguments = new ArrayList ();
910 arguments.Add (new Argument (e, Argument.AType.Expression));
911 method = Invocation.OverloadResolve (
912 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
917 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
921 /// Resolves the expression `e' into a boolean expression: either through
922 /// an implicit conversion, or through an `operator true' invocation
924 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
930 if (e.Type == TypeManager.bool_type)
933 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
935 if (converted != null)
939 // If no implicit conversion to bool exists, try using `operator true'
941 converted = Expression.GetOperatorTrue (ec, e, loc);
942 if (converted == null){
943 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
949 public virtual string ExprClassName
953 case ExprClass.Invalid:
955 case ExprClass.Value:
957 case ExprClass.Variable:
959 case ExprClass.Namespace:
963 case ExprClass.MethodGroup:
964 return "method group";
965 case ExprClass.PropertyAccess:
966 return "property access";
967 case ExprClass.EventAccess:
968 return "event access";
969 case ExprClass.IndexerAccess:
970 return "indexer access";
971 case ExprClass.Nothing:
974 throw new Exception ("Should not happen");
979 /// Reports that we were expecting `expr' to be of class `expected'
981 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
983 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
986 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
988 string name = GetSignatureForError ();
990 name = ds.GetSignatureForError () + '.' + name;
992 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
993 name, was, expected);
996 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
998 string [] valid = new string [4];
1001 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1002 valid [count++] = "variable";
1003 valid [count++] = "value";
1006 if ((flags & ResolveFlags.Type) != 0)
1007 valid [count++] = "type";
1009 if ((flags & ResolveFlags.MethodGroup) != 0)
1010 valid [count++] = "method group";
1013 valid [count++] = "unknown";
1015 StringBuilder sb = new StringBuilder (valid [0]);
1016 for (int i = 1; i < count - 1; i++) {
1018 sb.Append (valid [i]);
1021 sb.Append ("' or `");
1022 sb.Append (valid [count - 1]);
1025 Report.Error (119, loc,
1026 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1029 public static void UnsafeError (Location loc)
1031 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1035 // Load the object from the pointer.
1037 public static void LoadFromPtr (ILGenerator ig, Type t)
1039 if (t == TypeManager.int32_type)
1040 ig.Emit (OpCodes.Ldind_I4);
1041 else if (t == TypeManager.uint32_type)
1042 ig.Emit (OpCodes.Ldind_U4);
1043 else if (t == TypeManager.short_type)
1044 ig.Emit (OpCodes.Ldind_I2);
1045 else if (t == TypeManager.ushort_type)
1046 ig.Emit (OpCodes.Ldind_U2);
1047 else if (t == TypeManager.char_type)
1048 ig.Emit (OpCodes.Ldind_U2);
1049 else if (t == TypeManager.byte_type)
1050 ig.Emit (OpCodes.Ldind_U1);
1051 else if (t == TypeManager.sbyte_type)
1052 ig.Emit (OpCodes.Ldind_I1);
1053 else if (t == TypeManager.uint64_type)
1054 ig.Emit (OpCodes.Ldind_I8);
1055 else if (t == TypeManager.int64_type)
1056 ig.Emit (OpCodes.Ldind_I8);
1057 else if (t == TypeManager.float_type)
1058 ig.Emit (OpCodes.Ldind_R4);
1059 else if (t == TypeManager.double_type)
1060 ig.Emit (OpCodes.Ldind_R8);
1061 else if (t == TypeManager.bool_type)
1062 ig.Emit (OpCodes.Ldind_I1);
1063 else if (t == TypeManager.intptr_type)
1064 ig.Emit (OpCodes.Ldind_I);
1065 else if (TypeManager.IsEnumType (t)) {
1066 if (t == TypeManager.enum_type)
1067 ig.Emit (OpCodes.Ldind_Ref);
1069 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1070 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1071 ig.Emit (OpCodes.Ldobj, t);
1072 else if (t.IsPointer)
1073 ig.Emit (OpCodes.Ldind_I);
1075 ig.Emit (OpCodes.Ldind_Ref);
1079 // The stack contains the pointer and the value of type `type'
1081 public static void StoreFromPtr (ILGenerator ig, Type type)
1083 if (TypeManager.IsEnumType (type))
1084 type = TypeManager.EnumToUnderlying (type);
1085 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1086 ig.Emit (OpCodes.Stind_I4);
1087 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1088 ig.Emit (OpCodes.Stind_I8);
1089 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1090 type == TypeManager.ushort_type)
1091 ig.Emit (OpCodes.Stind_I2);
1092 else if (type == TypeManager.float_type)
1093 ig.Emit (OpCodes.Stind_R4);
1094 else if (type == TypeManager.double_type)
1095 ig.Emit (OpCodes.Stind_R8);
1096 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1097 type == TypeManager.bool_type)
1098 ig.Emit (OpCodes.Stind_I1);
1099 else if (type == TypeManager.intptr_type)
1100 ig.Emit (OpCodes.Stind_I);
1101 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1102 ig.Emit (OpCodes.Stobj, type);
1104 ig.Emit (OpCodes.Stind_Ref);
1108 // Returns the size of type `t' if known, otherwise, 0
1110 public static int GetTypeSize (Type t)
1112 t = TypeManager.TypeToCoreType (t);
1113 if (t == TypeManager.int32_type ||
1114 t == TypeManager.uint32_type ||
1115 t == TypeManager.float_type)
1117 else if (t == TypeManager.int64_type ||
1118 t == TypeManager.uint64_type ||
1119 t == TypeManager.double_type)
1121 else if (t == TypeManager.byte_type ||
1122 t == TypeManager.sbyte_type ||
1123 t == TypeManager.bool_type)
1125 else if (t == TypeManager.short_type ||
1126 t == TypeManager.char_type ||
1127 t == TypeManager.ushort_type)
1129 else if (t == TypeManager.decimal_type)
1135 public static void Error_NegativeArrayIndex (Location loc)
1137 Report.Error (248, loc, "Cannot create an array with a negative size");
1140 protected void Error_CannotCallAbstractBase (string name)
1142 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1146 // Converts `source' to an int, uint, long or ulong.
1148 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1152 using (ec.With (EmitContext.Flags.CheckState, true)) {
1153 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1155 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1157 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1159 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1161 if (target == null) {
1162 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1168 // Only positive constants are allowed at compile time
1170 if (target is Constant){
1171 if (target is IntConstant){
1172 if (((IntConstant) target).Value < 0){
1173 Error_NegativeArrayIndex (loc);
1178 if (target is LongConstant){
1179 if (((LongConstant) target).Value < 0){
1180 Error_NegativeArrayIndex (loc);
1193 /// This is just a base class for expressions that can
1194 /// appear on statements (invocations, object creation,
1195 /// assignments, post/pre increment and decrement). The idea
1196 /// being that they would support an extra Emition interface that
1197 /// does not leave a result on the stack.
1199 public abstract class ExpressionStatement : Expression {
1201 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1203 Expression e = Resolve (ec);
1207 ExpressionStatement es = e as ExpressionStatement;
1209 Error (201, "Only assignment, call, increment, decrement and new object " +
1210 "expressions can be used as a statement");
1216 /// Requests the expression to be emitted in a `statement'
1217 /// context. This means that no new value is left on the
1218 /// stack after invoking this method (constrasted with
1219 /// Emit that will always leave a value on the stack).
1221 public abstract void EmitStatement (EmitContext ec);
1225 /// This kind of cast is used to encapsulate the child
1226 /// whose type is child.Type into an expression that is
1227 /// reported to return "return_type". This is used to encapsulate
1228 /// expressions which have compatible types, but need to be dealt
1229 /// at higher levels with.
1231 /// For example, a "byte" expression could be encapsulated in one
1232 /// of these as an "unsigned int". The type for the expression
1233 /// would be "unsigned int".
1236 public class EmptyCast : Expression {
1237 protected readonly Expression child;
1239 public EmptyCast (Expression child, Type return_type)
1241 eclass = child.eclass;
1242 loc = child.Location;
1247 public override Expression DoResolve (EmitContext ec)
1249 // This should never be invoked, we are born in fully
1250 // initialized state.
1255 public override void Emit (EmitContext ec)
1260 public override bool GetAttributableValue (Type valueType, out object value)
1262 return child.GetAttributableValue (valueType, out value);
1267 /// This is a numeric cast to a Decimal
1269 public class CastToDecimal : EmptyCast {
1271 MethodInfo conversion_operator;
1273 public CastToDecimal (Expression child)
1274 : this (child, false)
1278 public CastToDecimal (Expression child, bool find_explicit)
1279 : base (child, TypeManager.decimal_type)
1281 conversion_operator = GetConversionOperator (find_explicit);
1283 if (conversion_operator == null)
1284 throw new InternalErrorException ("Outer conversion routine is out of sync");
1287 // Returns the implicit operator that converts from
1288 // 'child.Type' to System.Decimal.
1289 MethodInfo GetConversionOperator (bool find_explicit)
1291 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1293 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1294 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1296 foreach (MethodInfo oper in mi) {
1297 ParameterData pd = TypeManager.GetParameterData (oper);
1299 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1305 public override void Emit (EmitContext ec)
1307 ILGenerator ig = ec.ig;
1310 ig.Emit (OpCodes.Call, conversion_operator);
1315 /// This is an explicit numeric cast from a Decimal
1317 public class CastFromDecimal : EmptyCast
1319 static IDictionary operators;
1321 public CastFromDecimal (Expression child, Type return_type)
1322 : base (child, return_type)
1324 if (child.Type != TypeManager.decimal_type)
1325 throw new InternalErrorException (
1326 "The expected type is Decimal, instead it is " + child.Type.FullName);
1329 // Returns the explicit operator that converts from an
1330 // express of type System.Decimal to 'type'.
1331 public Expression Resolve ()
1333 if (operators == null) {
1334 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1335 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1336 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1338 operators = new System.Collections.Specialized.HybridDictionary ();
1339 foreach (MethodInfo oper in all_oper) {
1340 ParameterData pd = TypeManager.GetParameterData (oper);
1341 if (pd.ParameterType (0) == TypeManager.decimal_type)
1342 operators.Add (oper.ReturnType, oper);
1346 return operators.Contains (type) ? this : null;
1349 public override void Emit (EmitContext ec)
1351 ILGenerator ig = ec.ig;
1354 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1359 // Constant specialization of EmptyCast.
1360 // We need to special case this since an empty cast of
1361 // a constant is still a constant.
1363 public class EmptyConstantCast : Constant
1365 public readonly Constant child;
1367 public EmptyConstantCast(Constant child, Type type)
1368 : base (child.Location)
1370 eclass = child.eclass;
1375 public override string AsString ()
1377 return child.AsString ();
1380 public override object GetValue ()
1382 return child.GetValue ();
1385 public override Constant Reduce (bool inCheckedContext, Type target_type)
1387 return child.Reduce (inCheckedContext, target_type);
1390 public override Constant Increment ()
1392 return child.Increment ();
1395 public override bool IsDefaultValue
1397 get { return child.IsDefaultValue; }
1400 public override bool IsNegative
1402 get { return child.IsNegative; }
1405 public override void Emit (EmitContext ec)
1410 public override Constant ToType (Type type)
1412 return child.ToType (type);
1418 /// This class is used to wrap literals which belong inside Enums
1420 public class EnumConstant : Constant {
1421 public Constant Child;
1423 public EnumConstant (Constant child, Type enum_type):
1424 base (child.Location)
1426 eclass = child.eclass;
1431 public override Expression DoResolve (EmitContext ec)
1433 // This should never be invoked, we are born in fully
1434 // initialized state.
1439 public override void Emit (EmitContext ec)
1444 public override bool GetAttributableValue (Type valueType, out object value)
1446 value = GetTypedValue ();
1450 public override string GetSignatureForError()
1452 return TypeManager.CSharpName (Type);
1455 public override object GetValue ()
1457 return Child.GetValue ();
1460 public override object GetTypedValue ()
1462 // FIXME: runtime is not ready to work with just emited enums
1463 if (!RootContext.StdLib) {
1464 return Child.GetValue ();
1467 return System.Enum.ToObject (type, Child.GetValue ());
1470 public override string AsString ()
1472 return Child.AsString ();
1475 public override DoubleConstant ConvertToDouble ()
1477 return Child.ConvertToDouble ();
1480 public override FloatConstant ConvertToFloat ()
1482 return Child.ConvertToFloat ();
1485 public override ULongConstant ConvertToULong ()
1487 return Child.ConvertToULong ();
1490 public override LongConstant ConvertToLong ()
1492 return Child.ConvertToLong ();
1495 public override UIntConstant ConvertToUInt ()
1497 return Child.ConvertToUInt ();
1500 public override IntConstant ConvertToInt ()
1502 return Child.ConvertToInt ();
1505 public override Constant Increment()
1507 return new EnumConstant (Child.Increment (), type);
1510 public override bool IsDefaultValue {
1512 return Child.IsDefaultValue;
1516 public override bool IsZeroInteger {
1517 get { return Child.IsZeroInteger; }
1520 public override bool IsNegative {
1522 return Child.IsNegative;
1526 public override Constant Reduce(bool inCheckedContext, Type target_type)
1528 if (Child.Type == target_type)
1531 return Child.Reduce (inCheckedContext, target_type);
1534 public override Constant ToType (Type type)
1537 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1538 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1541 if (type.UnderlyingSystemType != Child.Type)
1542 Child = Child.ToType (type.UnderlyingSystemType);
1546 if (!Convert.ImplicitStandardConversionExists (this, type)){
1550 return Child.ToType (type);
1556 /// This kind of cast is used to encapsulate Value Types in objects.
1558 /// The effect of it is to box the value type emitted by the previous
1561 public class BoxedCast : EmptyCast {
1563 public BoxedCast (Expression expr, Type target_type)
1564 : base (expr, target_type)
1566 eclass = ExprClass.Value;
1569 public override Expression DoResolve (EmitContext ec)
1571 // This should never be invoked, we are born in fully
1572 // initialized state.
1577 public override void Emit (EmitContext ec)
1581 ec.ig.Emit (OpCodes.Box, child.Type);
1585 public class UnboxCast : EmptyCast {
1586 public UnboxCast (Expression expr, Type return_type)
1587 : base (expr, return_type)
1591 public override Expression DoResolve (EmitContext ec)
1593 // This should never be invoked, we are born in fully
1594 // initialized state.
1599 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1601 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1602 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1603 return base.DoResolveLValue (ec, right_side);
1606 public override void Emit (EmitContext ec)
1609 ILGenerator ig = ec.ig;
1613 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1614 ig.Emit (OpCodes.Unbox_Any, t);
1618 ig.Emit (OpCodes.Unbox, t);
1620 LoadFromPtr (ig, t);
1626 /// This is used to perform explicit numeric conversions.
1628 /// Explicit numeric conversions might trigger exceptions in a checked
1629 /// context, so they should generate the conv.ovf opcodes instead of
1632 public class ConvCast : EmptyCast {
1633 public enum Mode : byte {
1634 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1636 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1637 U2_I1, U2_U1, U2_I2, U2_CH,
1638 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1639 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1640 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1641 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1642 CH_I1, CH_U1, CH_I2,
1643 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1644 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1649 public ConvCast (Expression child, Type return_type, Mode m)
1650 : base (child, return_type)
1655 public override Expression DoResolve (EmitContext ec)
1657 // This should never be invoked, we are born in fully
1658 // initialized state.
1663 public override string ToString ()
1665 return String.Format ("ConvCast ({0}, {1})", mode, child);
1668 public override void Emit (EmitContext ec)
1670 ILGenerator ig = ec.ig;
1676 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1677 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1678 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1679 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1680 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1682 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1683 case Mode.U1_CH: /* nothing */ break;
1685 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1686 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1687 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1688 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1689 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1690 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1692 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1693 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1694 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1695 case Mode.U2_CH: /* nothing */ break;
1697 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1698 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1699 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1700 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1701 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1702 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1703 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1705 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1706 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1707 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1708 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1709 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1710 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1712 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1713 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1714 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1715 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1716 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1717 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1718 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1719 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1721 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1722 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1723 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1724 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1725 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1726 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1727 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1728 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1730 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1731 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1732 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1734 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1735 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1736 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1737 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1738 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1739 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1740 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1741 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1742 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1744 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1745 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1746 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1747 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1748 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1749 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1750 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1751 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1752 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1753 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1757 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1758 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1759 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1760 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1761 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1763 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1764 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1767 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1768 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1769 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1770 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1771 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1773 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1774 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1775 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1776 case Mode.U2_CH: /* nothing */ break;
1778 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1779 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1780 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1781 case Mode.I4_U4: /* nothing */ break;
1782 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1783 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1784 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1787 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1788 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1789 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1790 case Mode.U4_I4: /* nothing */ break;
1791 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1793 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1794 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1795 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1796 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1797 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1798 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1799 case Mode.I8_U8: /* nothing */ break;
1800 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1802 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1803 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1804 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1805 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1806 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1807 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1808 case Mode.U8_I8: /* nothing */ break;
1809 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1811 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1812 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1813 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1815 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1816 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1817 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1818 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1819 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1820 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1821 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1822 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1823 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1825 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1826 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1827 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1828 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1829 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1830 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1831 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1832 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1833 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1834 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1840 public class OpcodeCast : EmptyCast {
1844 public OpcodeCast (Expression child, Type return_type, OpCode op)
1845 : base (child, return_type)
1849 second_valid = false;
1852 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1853 : base (child, return_type)
1858 second_valid = true;
1861 public override Expression DoResolve (EmitContext ec)
1863 // This should never be invoked, we are born in fully
1864 // initialized state.
1869 public override void Emit (EmitContext ec)
1880 /// This kind of cast is used to encapsulate a child and cast it
1881 /// to the class requested
1883 public class ClassCast : EmptyCast {
1884 public ClassCast (Expression child, Type return_type)
1885 : base (child, return_type)
1890 public override Expression DoResolve (EmitContext ec)
1892 // This should never be invoked, we are born in fully
1893 // initialized state.
1898 public override void Emit (EmitContext ec)
1902 if (TypeManager.IsGenericParameter (child.Type))
1903 ec.ig.Emit (OpCodes.Box, child.Type);
1906 if (type.IsGenericParameter)
1907 ec.ig.Emit (OpCodes.Unbox_Any, type);
1910 ec.ig.Emit (OpCodes.Castclass, type);
1915 /// SimpleName expressions are formed of a single word and only happen at the beginning
1916 /// of a dotted-name.
1918 public class SimpleName : Expression {
1920 public readonly TypeArguments Arguments;
1923 public SimpleName (string name, Location l)
1929 public SimpleName (string name, TypeArguments args, Location l)
1936 public SimpleName (string name, TypeParameter[] type_params, Location l)
1941 Arguments = new TypeArguments (l);
1942 foreach (TypeParameter type_param in type_params)
1943 Arguments.Add (new TypeParameterExpr (type_param, l));
1946 public static string RemoveGenericArity (string name)
1949 StringBuilder sb = new StringBuilder ();
1950 while (start < name.Length) {
1951 int pos = name.IndexOf ('`', start);
1953 sb.Append (name.Substring (start));
1957 sb.Append (name.Substring (start, pos-start));
1960 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1966 return sb.ToString ();
1969 public SimpleName GetMethodGroup ()
1971 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1974 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1976 if (ec.IsFieldInitializer)
1977 Report.Error (236, l,
1978 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1982 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1986 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1988 return resolved_to != null && resolved_to.Type != null &&
1989 resolved_to.Type.Name == Name &&
1990 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1993 public override Expression DoResolve (EmitContext ec)
1995 return SimpleNameResolve (ec, null, false);
1998 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2000 return SimpleNameResolve (ec, right_side, false);
2004 public Expression DoResolve (EmitContext ec, bool intermediate)
2006 return SimpleNameResolve (ec, null, intermediate);
2009 private bool IsNestedChild (Type t, Type parent)
2014 while (parent != null) {
2015 parent = TypeManager.DropGenericTypeArguments (parent);
2016 if (TypeManager.IsNestedChildOf (t, parent))
2019 parent = parent.BaseType;
2025 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2027 if (!TypeManager.IsGenericTypeDefinition (t))
2030 DeclSpace ds = ec.DeclContainer;
2031 while (ds != null) {
2032 if (IsNestedChild (t, ds.TypeBuilder))
2041 Type[] gen_params = TypeManager.GetTypeArguments (t);
2043 int arg_count = Arguments != null ? Arguments.Count : 0;
2045 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2046 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2047 TypeArguments new_args = new TypeArguments (loc);
2048 foreach (TypeParameter param in ds.TypeParameters)
2049 new_args.Add (new TypeParameterExpr (param, loc));
2051 if (Arguments != null)
2052 new_args.Add (Arguments);
2054 return new ConstructedType (t, new_args, loc);
2061 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2063 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2065 return fne.ResolveAsTypeStep (ec, silent);
2067 int errors = Report.Errors;
2068 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2071 if (fne.Type == null)
2074 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2076 return nested.ResolveAsTypeStep (ec, false);
2078 if (Arguments != null) {
2079 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2080 return ct.ResolveAsTypeStep (ec, false);
2086 if (silent || errors != Report.Errors)
2089 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2091 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2095 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2096 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2097 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2098 Type type = a.GetType (fullname);
2100 Report.SymbolRelatedToPreviousError (type);
2101 Expression.ErrorIsInaccesible (loc, fullname);
2106 Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
2108 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2112 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2116 // TODO: I am still not convinced about this. If someone else will need it
2117 // implement this as virtual property in MemberCore hierarchy
2118 string GetMemberType (MemberCore mc)
2120 if (mc is PropertyBase)
2124 if (mc is FieldBase)
2126 if (mc is MethodCore)
2128 if (mc is EnumMember)
2134 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2140 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2144 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2151 /// 7.5.2: Simple Names.
2153 /// Local Variables and Parameters are handled at
2154 /// parse time, so they never occur as SimpleNames.
2156 /// The `intermediate' flag is used by MemberAccess only
2157 /// and it is used to inform us that it is ok for us to
2158 /// avoid the static check, because MemberAccess might end
2159 /// up resolving the Name as a Type name and the access as
2160 /// a static type access.
2162 /// ie: Type Type; .... { Type.GetType (""); }
2164 /// Type is both an instance variable and a Type; Type.GetType
2165 /// is the static method not an instance method of type.
2167 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2169 Expression e = null;
2172 // Stage 1: Performed by the parser (binding to locals or parameters).
2174 Block current_block = ec.CurrentBlock;
2175 if (current_block != null){
2176 LocalInfo vi = current_block.GetLocalInfo (Name);
2178 if (Arguments != null) {
2179 Report.Error (307, loc,
2180 "The variable `{0}' cannot be used with type arguments",
2185 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2186 if (right_side != null) {
2187 return var.ResolveLValue (ec, right_side, loc);
2189 ResolveFlags rf = ResolveFlags.VariableOrValue;
2191 rf |= ResolveFlags.DisableFlowAnalysis;
2192 return var.Resolve (ec, rf);
2196 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2198 if (Arguments != null) {
2199 Report.Error (307, loc,
2200 "The variable `{0}' cannot be used with type arguments",
2205 if (right_side != null)
2206 return pref.ResolveLValue (ec, right_side, loc);
2208 return pref.Resolve (ec);
2213 // Stage 2: Lookup members
2216 DeclSpace lookup_ds = ec.DeclContainer;
2217 Type almost_matched_type = null;
2218 ArrayList almost_matched = null;
2220 if (lookup_ds.TypeBuilder == null)
2223 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2227 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2228 almost_matched_type = lookup_ds.TypeBuilder;
2229 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2232 lookup_ds =lookup_ds.Parent;
2233 } while (lookup_ds != null);
2235 if (e == null && ec.ContainerType != null)
2236 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2239 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2240 almost_matched_type = ec.ContainerType;
2241 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2243 e = ResolveAsTypeStep (ec, true);
2247 if (almost_matched != null)
2248 almostMatchedMembers = almost_matched;
2249 if (almost_matched_type == null)
2250 almost_matched_type = ec.ContainerType;
2251 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2255 if (e is TypeExpr) {
2256 if (Arguments == null)
2259 ConstructedType ct = new ConstructedType (
2260 (FullNamedExpression) e, Arguments, loc);
2261 return ct.ResolveAsTypeStep (ec, false);
2264 if (e is MemberExpr) {
2265 MemberExpr me = (MemberExpr) e;
2268 if (me.IsInstance) {
2269 if (ec.IsStatic || ec.IsFieldInitializer) {
2271 // Note that an MemberExpr can be both IsInstance and IsStatic.
2272 // An unresolved MethodGroupExpr can contain both kinds of methods
2273 // and each predicate is true if the MethodGroupExpr contains
2274 // at least one of that kind of method.
2278 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2279 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2280 return EmptyExpression.Null;
2284 // Pass the buck to MemberAccess and Invocation.
2286 left = EmptyExpression.Null;
2288 left = ec.GetThis (loc);
2291 left = new TypeExpression (ec.ContainerType, loc);
2294 e = me.ResolveMemberAccess (ec, left, loc, null);
2298 me = e as MemberExpr;
2302 if (Arguments != null) {
2303 MethodGroupExpr mg = me as MethodGroupExpr;
2307 return mg.ResolveGeneric (ec, Arguments);
2310 if (!me.IsStatic && (me.InstanceExpression != null) &&
2311 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2312 me.InstanceExpression.Type != me.DeclaringType &&
2313 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2314 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2315 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2316 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2320 return (right_side != null)
2321 ? me.DoResolveLValue (ec, right_side)
2322 : me.DoResolve (ec);
2328 public override void Emit (EmitContext ec)
2331 // If this is ever reached, then we failed to
2332 // find the name as a namespace
2335 Error (103, "The name `" + Name +
2336 "' does not exist in the class `" +
2337 ec.DeclContainer.Name + "'");
2340 public override string ToString ()
2345 public override string GetSignatureForError ()
2352 /// Represents a namespace or a type. The name of the class was inspired by
2353 /// section 10.8.1 (Fully Qualified Names).
2355 public abstract class FullNamedExpression : Expression {
2356 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2361 public abstract string FullName {
2367 /// Expression that evaluates to a type
2369 public abstract class TypeExpr : FullNamedExpression {
2370 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2372 TypeExpr t = DoResolveAsTypeStep (ec);
2376 eclass = ExprClass.Type;
2380 override public Expression DoResolve (EmitContext ec)
2382 return ResolveAsTypeTerminal (ec, false);
2385 override public void Emit (EmitContext ec)
2387 throw new Exception ("Should never be called");
2390 public virtual bool CheckAccessLevel (DeclSpace ds)
2392 return ds.CheckAccessLevel (Type);
2395 public virtual bool AsAccessible (DeclSpace ds, int flags)
2397 return ds.AsAccessible (Type, flags);
2400 public virtual bool IsClass {
2401 get { return Type.IsClass; }
2404 public virtual bool IsValueType {
2405 get { return Type.IsValueType; }
2408 public virtual bool IsInterface {
2409 get { return Type.IsInterface; }
2412 public virtual bool IsSealed {
2413 get { return Type.IsSealed; }
2416 public virtual bool CanInheritFrom ()
2418 if (Type == TypeManager.enum_type ||
2419 (Type == TypeManager.value_type && RootContext.StdLib) ||
2420 Type == TypeManager.multicast_delegate_type ||
2421 Type == TypeManager.delegate_type ||
2422 Type == TypeManager.array_type)
2428 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2430 public abstract string Name {
2434 public override bool Equals (object obj)
2436 TypeExpr tobj = obj as TypeExpr;
2440 return Type == tobj.Type;
2443 public override int GetHashCode ()
2445 return Type.GetHashCode ();
2448 public override string ToString ()
2455 /// Fully resolved Expression that already evaluated to a type
2457 public class TypeExpression : TypeExpr {
2458 public TypeExpression (Type t, Location l)
2461 eclass = ExprClass.Type;
2465 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2470 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2475 public override string Name {
2476 get { return Type.ToString (); }
2479 public override string FullName {
2480 get { return Type.FullName; }
2485 /// Used to create types from a fully qualified name. These are just used
2486 /// by the parser to setup the core types. A TypeLookupExpression is always
2487 /// classified as a type.
2489 public sealed class TypeLookupExpression : TypeExpr {
2490 readonly string name;
2492 public TypeLookupExpression (string name)
2495 eclass = ExprClass.Type;
2498 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2500 // It's null for corlib compilation only
2502 return DoResolveAsTypeStep (ec);
2507 static readonly char [] dot_array = { '.' };
2508 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2510 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2512 string lookup_name = name;
2513 int pos = name.IndexOf ('.');
2515 rest = name.Substring (pos + 1);
2516 lookup_name = name.Substring (0, pos);
2519 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2521 if (resolved != null && rest != null) {
2522 // Now handle the rest of the the name.
2523 string [] elements = rest.Split (dot_array);
2525 int count = elements.Length;
2527 while (i < count && resolved != null && resolved is Namespace) {
2528 Namespace ns = resolved as Namespace;
2529 element = elements [i++];
2530 lookup_name += "." + element;
2531 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2534 if (resolved != null && resolved is TypeExpr) {
2535 Type t = ((TypeExpr) resolved).Type;
2537 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2539 lookup_name = t.FullName;
2546 t = TypeManager.GetNestedType (t, elements [i++]);
2551 if (resolved == null) {
2552 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2556 if (!(resolved is TypeExpr)) {
2557 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2561 type = resolved.Type;
2565 public override string Name {
2566 get { return name; }
2569 public override string FullName {
2570 get { return name; }
2575 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2578 public class UnboundTypeExpression : TypeExpr
2582 public UnboundTypeExpression (MemberName name, Location l)
2588 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2591 if (name.Left != null) {
2592 Expression lexpr = name.Left.GetTypeExpression ();
2593 expr = new MemberAccess (lexpr, name.Basename);
2595 expr = new SimpleName (name.Basename, loc);
2598 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2603 return new TypeExpression (type, loc);
2606 public override string Name {
2607 get { return name.FullName; }
2610 public override string FullName {
2611 get { return name.FullName; }
2615 public class TypeAliasExpression : TypeExpr {
2616 FullNamedExpression alias;
2621 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2627 eclass = ExprClass.Type;
2629 name = alias.FullName + "<" + args.ToString () + ">";
2631 name = alias.FullName;
2634 public override string Name {
2635 get { return alias.FullName; }
2638 public override string FullName {
2639 get { return name; }
2642 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2644 texpr = alias.ResolveAsTypeTerminal (ec, false);
2648 Type type = texpr.Type;
2649 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2652 if (num_args == 0) {
2653 Report.Error (308, loc,
2654 "The non-generic type `{0}' cannot " +
2655 "be used with type arguments.",
2656 TypeManager.CSharpName (type));
2660 ConstructedType ctype = new ConstructedType (type, args, loc);
2661 return ctype.ResolveAsTypeTerminal (ec, false);
2662 } else if (num_args > 0) {
2663 Report.Error (305, loc,
2664 "Using the generic type `{0}' " +
2665 "requires {1} type arguments",
2666 TypeManager.CSharpName (type), num_args.ToString ());
2673 public override bool CheckAccessLevel (DeclSpace ds)
2675 return texpr.CheckAccessLevel (ds);
2678 public override bool AsAccessible (DeclSpace ds, int flags)
2680 return texpr.AsAccessible (ds, flags);
2683 public override bool IsClass {
2684 get { return texpr.IsClass; }
2687 public override bool IsValueType {
2688 get { return texpr.IsValueType; }
2691 public override bool IsInterface {
2692 get { return texpr.IsInterface; }
2695 public override bool IsSealed {
2696 get { return texpr.IsSealed; }
2701 /// This class denotes an expression which evaluates to a member
2702 /// of a struct or a class.
2704 public abstract class MemberExpr : Expression
2707 /// The name of this member.
2709 public abstract string Name {
2714 /// Whether this is an instance member.
2716 public abstract bool IsInstance {
2721 /// Whether this is a static member.
2723 public abstract bool IsStatic {
2728 /// The type which declares this member.
2730 public abstract Type DeclaringType {
2735 /// The instance expression associated with this member, if it's a
2736 /// non-static member.
2738 public Expression InstanceExpression;
2740 public static void error176 (Location loc, string name)
2742 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2743 "with an instance reference, qualify it with a type name instead", name);
2746 // TODO: possible optimalization
2747 // Cache resolved constant result in FieldBuilder <-> expression map
2748 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2749 SimpleName original)
2753 // original == null || original.Resolve (...) ==> left
2756 if (left is TypeExpr) {
2758 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2766 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2769 error176 (loc, GetSignatureForError ());
2773 InstanceExpression = left;
2778 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2783 if (InstanceExpression == EmptyExpression.Null) {
2784 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2788 if (InstanceExpression.Type.IsValueType) {
2789 if (InstanceExpression is IMemoryLocation) {
2790 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2792 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2793 InstanceExpression.Emit (ec);
2795 t.AddressOf (ec, AddressOp.Store);
2798 InstanceExpression.Emit (ec);
2800 if (prepare_for_load)
2801 ec.ig.Emit (OpCodes.Dup);
2806 /// MethodGroup Expression.
2808 /// This is a fully resolved expression that evaluates to a type
2810 public class MethodGroupExpr : MemberExpr {
2811 public MethodBase [] Methods;
2812 bool has_type_arguments = false;
2813 bool identical_type_name = false;
2816 public MethodGroupExpr (MemberInfo [] mi, Location l)
2818 Methods = new MethodBase [mi.Length];
2819 mi.CopyTo (Methods, 0);
2820 eclass = ExprClass.MethodGroup;
2821 type = TypeManager.object_type;
2825 public MethodGroupExpr (ArrayList list, Location l)
2827 Methods = new MethodBase [list.Count];
2830 list.CopyTo (Methods, 0);
2832 foreach (MemberInfo m in list){
2833 if (!(m is MethodBase)){
2834 Console.WriteLine ("Name " + m.Name);
2835 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2842 eclass = ExprClass.MethodGroup;
2843 type = TypeManager.object_type;
2846 public override Type DeclaringType {
2849 // We assume that the top-level type is in the end
2851 return Methods [Methods.Length - 1].DeclaringType;
2852 //return Methods [0].DeclaringType;
2856 public bool HasTypeArguments {
2858 return has_type_arguments;
2862 has_type_arguments = value;
2866 public bool IdenticalTypeName {
2868 return identical_type_name;
2872 identical_type_name = value;
2876 public bool IsBase {
2885 public override string GetSignatureForError ()
2887 return TypeManager.CSharpSignature (Methods [0]);
2890 public override string Name {
2892 return Methods [0].Name;
2896 public override bool IsInstance {
2898 foreach (MethodBase mb in Methods)
2906 public override bool IsStatic {
2908 foreach (MethodBase mb in Methods)
2916 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2917 SimpleName original)
2919 if (!(left is TypeExpr) &&
2920 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2921 IdenticalTypeName = true;
2923 return base.ResolveMemberAccess (ec, left, loc, original);
2926 override public Expression DoResolve (EmitContext ec)
2929 InstanceExpression = null;
2931 if (InstanceExpression != null) {
2932 InstanceExpression = InstanceExpression.DoResolve (ec);
2933 if (InstanceExpression == null)
2940 public void ReportUsageError ()
2942 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2943 Name + "()' is referenced without parentheses");
2946 override public void Emit (EmitContext ec)
2948 ReportUsageError ();
2951 bool RemoveMethods (bool keep_static)
2953 ArrayList smethods = new ArrayList ();
2955 foreach (MethodBase mb in Methods){
2956 if (mb.IsStatic == keep_static)
2960 if (smethods.Count == 0)
2963 Methods = new MethodBase [smethods.Count];
2964 smethods.CopyTo (Methods, 0);
2970 /// Removes any instance methods from the MethodGroup, returns
2971 /// false if the resulting set is empty.
2973 public bool RemoveInstanceMethods ()
2975 return RemoveMethods (true);
2979 /// Removes any static methods from the MethodGroup, returns
2980 /// false if the resulting set is empty.
2982 public bool RemoveStaticMethods ()
2984 return RemoveMethods (false);
2987 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2990 if (args.Resolve (ec) == false)
2993 Type[] atypes = args.Arguments;
2995 int first_count = 0;
2996 MethodInfo first = null;
2998 ArrayList list = new ArrayList ();
2999 foreach (MethodBase mb in Methods) {
3000 MethodInfo mi = mb as MethodInfo;
3001 if ((mi == null) || !mi.IsGenericMethod)
3004 Type[] gen_params = mi.GetGenericArguments ();
3006 if (first == null) {
3008 first_count = gen_params.Length;
3011 if (gen_params.Length != atypes.Length)
3014 list.Add (mi.MakeGenericMethod (atypes));
3017 if (list.Count > 0) {
3018 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3019 new_mg.InstanceExpression = InstanceExpression;
3020 new_mg.HasTypeArguments = true;
3021 new_mg.IsBase = IsBase;
3027 305, loc, "Using the generic method `{0}' " +
3028 "requires {1} type arguments", Name,
3029 first_count.ToString ());
3032 308, loc, "The non-generic method `{0}' " +
3033 "cannot be used with type arguments", Name);
3037 throw new NotImplementedException ();
3043 /// Fully resolved expression that evaluates to a Field
3045 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3046 public readonly FieldInfo FieldInfo;
3047 VariableInfo variable_info;
3049 LocalTemporary temp;
3051 bool in_initializer;
3053 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3056 this.in_initializer = in_initializer;
3059 public FieldExpr (FieldInfo fi, Location l)
3062 eclass = ExprClass.Variable;
3063 type = TypeManager.TypeToCoreType (fi.FieldType);
3067 public override string Name {
3069 return FieldInfo.Name;
3073 public override bool IsInstance {
3075 return !FieldInfo.IsStatic;
3079 public override bool IsStatic {
3081 return FieldInfo.IsStatic;
3085 public override Type DeclaringType {
3087 return FieldInfo.DeclaringType;
3091 public override string GetSignatureForError ()
3093 return TypeManager.GetFullNameSignature (FieldInfo);
3096 public VariableInfo VariableInfo {
3098 return variable_info;
3102 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3103 SimpleName original)
3105 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3107 Type t = fi.FieldType;
3109 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3110 IConstant ic = TypeManager.GetConstant (fi);
3113 ic = new ExternalConstant (fi);
3115 ic = ExternalConstant.CreateDecimal (fi);
3117 return base.ResolveMemberAccess (ec, left, loc, original);
3120 TypeManager.RegisterConstant (fi, ic);
3123 bool left_is_type = left is TypeExpr;
3124 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3125 Report.SymbolRelatedToPreviousError (FieldInfo);
3126 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3130 if (ic.ResolveValue ()) {
3131 if (!ec.IsInObsoleteScope)
3132 ic.CheckObsoleteness (loc);
3138 if (t.IsPointer && !ec.InUnsafe) {
3143 return base.ResolveMemberAccess (ec, left, loc, original);
3146 override public Expression DoResolve (EmitContext ec)
3148 return DoResolve (ec, false, false);
3151 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3153 if (!FieldInfo.IsStatic){
3154 if (InstanceExpression == null){
3156 // This can happen when referencing an instance field using
3157 // a fully qualified type expression: TypeName.InstanceField = xxx
3159 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3163 // Resolve the field's instance expression while flow analysis is turned
3164 // off: when accessing a field "a.b", we must check whether the field
3165 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3167 if (lvalue_instance) {
3168 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3169 Expression right_side =
3170 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3171 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3174 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3175 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3178 if (InstanceExpression == null)
3181 InstanceExpression.CheckMarshalByRefAccess ();
3184 if (!in_initializer && !ec.IsFieldInitializer) {
3185 ObsoleteAttribute oa;
3186 FieldBase f = TypeManager.GetField (FieldInfo);
3188 if (!ec.IsInObsoleteScope)
3189 f.CheckObsoleteness (loc);
3191 // To be sure that type is external because we do not register generated fields
3192 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3193 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3195 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3199 AnonymousContainer am = ec.CurrentAnonymousMethod;
3201 if (!FieldInfo.IsStatic){
3202 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3203 Report.Error (1673, loc,
3204 "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",
3211 // If the instance expression is a local variable or parameter.
3212 IVariable var = InstanceExpression as IVariable;
3213 if ((var == null) || (var.VariableInfo == null))
3216 VariableInfo vi = var.VariableInfo;
3217 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3220 variable_info = vi.GetSubStruct (FieldInfo.Name);
3224 static readonly int [] codes = {
3225 191, // instance, write access
3226 192, // instance, out access
3227 198, // static, write access
3228 199, // static, out access
3229 1648, // member of value instance, write access
3230 1649, // member of value instance, out access
3231 1650, // member of value static, write access
3232 1651 // member of value static, out access
3235 static readonly string [] msgs = {
3236 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3237 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3238 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3239 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3240 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3241 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3242 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3243 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3246 // The return value is always null. Returning a value simplifies calling code.
3247 Expression Report_AssignToReadonly (Expression right_side)
3250 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3254 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3256 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3261 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3263 IVariable var = InstanceExpression as IVariable;
3264 if ((var != null) && (var.VariableInfo != null))
3265 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3267 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3268 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3270 Expression e = DoResolve (ec, lvalue_instance, out_access);
3275 FieldBase fb = TypeManager.GetField (FieldInfo);
3279 if (FieldInfo.IsInitOnly) {
3280 // InitOnly fields can only be assigned in constructors or initializers
3281 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3282 return Report_AssignToReadonly (right_side);
3284 if (ec.IsConstructor) {
3285 Type ctype = ec.TypeContainer.CurrentType;
3287 ctype = ec.ContainerType;
3289 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3290 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3291 return Report_AssignToReadonly (right_side);
3292 // static InitOnly fields cannot be assigned-to in an instance constructor
3293 if (IsStatic && !ec.IsStatic)
3294 return Report_AssignToReadonly (right_side);
3295 // instance constructors can't modify InitOnly fields of other instances of the same type
3296 if (!IsStatic && !(InstanceExpression is This))
3297 return Report_AssignToReadonly (right_side);
3301 if (right_side == EmptyExpression.OutAccess &&
3302 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3303 Report.SymbolRelatedToPreviousError (DeclaringType);
3304 Report.Warning (197, 1, loc,
3305 "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
3306 GetSignatureForError ());
3312 public override void CheckMarshalByRefAccess ()
3314 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3315 Report.SymbolRelatedToPreviousError (DeclaringType);
3316 Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3317 GetSignatureForError ());
3321 public bool VerifyFixed ()
3323 IVariable variable = InstanceExpression as IVariable;
3324 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3325 // We defer the InstanceExpression check after the variable check to avoid a
3326 // separate null check on InstanceExpression.
3327 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3330 public override int GetHashCode ()
3332 return FieldInfo.GetHashCode ();
3335 public override bool Equals (object obj)
3337 FieldExpr fe = obj as FieldExpr;
3341 if (FieldInfo != fe.FieldInfo)
3344 if (InstanceExpression == null || fe.InstanceExpression == null)
3347 return InstanceExpression.Equals (fe.InstanceExpression);
3350 public void Emit (EmitContext ec, bool leave_copy)
3352 ILGenerator ig = ec.ig;
3353 bool is_volatile = false;
3355 FieldBase f = TypeManager.GetField (FieldInfo);
3357 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3360 f.SetMemberIsUsed ();
3363 if (FieldInfo.IsStatic){
3365 ig.Emit (OpCodes.Volatile);
3367 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3370 EmitInstance (ec, false);
3373 ig.Emit (OpCodes.Volatile);
3375 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3378 ig.Emit (OpCodes.Ldflda, FieldInfo);
3379 ig.Emit (OpCodes.Ldflda, ff.Element);
3382 ig.Emit (OpCodes.Ldfld, FieldInfo);
3387 ec.ig.Emit (OpCodes.Dup);
3388 if (!FieldInfo.IsStatic) {
3389 temp = new LocalTemporary (this.Type);
3395 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3397 FieldAttributes fa = FieldInfo.Attributes;
3398 bool is_static = (fa & FieldAttributes.Static) != 0;
3399 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3400 ILGenerator ig = ec.ig;
3401 prepared = prepare_for_load;
3403 if (is_readonly && !ec.IsConstructor){
3404 Report_AssignToReadonly (source);
3408 EmitInstance (ec, prepare_for_load);
3412 ec.ig.Emit (OpCodes.Dup);
3413 if (!FieldInfo.IsStatic) {
3414 temp = new LocalTemporary (this.Type);
3419 FieldBase f = TypeManager.GetField (FieldInfo);
3421 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3422 ig.Emit (OpCodes.Volatile);
3428 ig.Emit (OpCodes.Stsfld, FieldInfo);
3430 ig.Emit (OpCodes.Stfld, FieldInfo);
3438 public override void Emit (EmitContext ec)
3443 public void AddressOf (EmitContext ec, AddressOp mode)
3445 ILGenerator ig = ec.ig;
3447 FieldBase f = TypeManager.GetField (FieldInfo);
3449 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3450 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3451 f.GetSignatureForError ());
3455 if ((mode & AddressOp.Store) != 0)
3457 if ((mode & AddressOp.Load) != 0)
3458 f.SetMemberIsUsed ();
3462 // Handle initonly fields specially: make a copy and then
3463 // get the address of the copy.
3466 if (FieldInfo.IsInitOnly){
3468 if (ec.IsConstructor){
3469 if (FieldInfo.IsStatic){
3481 local = ig.DeclareLocal (type);
3482 ig.Emit (OpCodes.Stloc, local);
3483 ig.Emit (OpCodes.Ldloca, local);
3488 if (FieldInfo.IsStatic){
3489 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3492 EmitInstance (ec, false);
3493 ig.Emit (OpCodes.Ldflda, FieldInfo);
3499 // A FieldExpr whose address can not be taken
3501 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3502 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3506 public new void AddressOf (EmitContext ec, AddressOp mode)
3508 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3513 /// Expression that evaluates to a Property. The Assign class
3514 /// might set the `Value' expression if we are in an assignment.
3516 /// This is not an LValue because we need to re-write the expression, we
3517 /// can not take data from the stack and store it.
3519 public class PropertyExpr : MemberExpr, IAssignMethod {
3520 public readonly PropertyInfo PropertyInfo;
3523 // This is set externally by the `BaseAccess' class
3526 MethodInfo getter, setter;
3531 LocalTemporary temp;
3534 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3536 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3539 eclass = ExprClass.PropertyAccess;
3543 type = TypeManager.TypeToCoreType (pi.PropertyType);
3545 ResolveAccessors (containerType);
3548 public override string Name {
3550 return PropertyInfo.Name;
3554 public override bool IsInstance {
3560 public override bool IsStatic {
3566 public override Type DeclaringType {
3568 return PropertyInfo.DeclaringType;
3572 public override string GetSignatureForError ()
3574 return TypeManager.GetFullNameSignature (PropertyInfo);
3577 void FindAccessors (Type invocation_type)
3579 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3580 BindingFlags.Static | BindingFlags.Instance |
3581 BindingFlags.DeclaredOnly;
3583 Type current = PropertyInfo.DeclaringType;
3584 for (; current != null; current = current.BaseType) {
3585 MemberInfo[] group = TypeManager.MemberLookup (
3586 invocation_type, invocation_type, current,
3587 MemberTypes.Property, flags, PropertyInfo.Name, null);
3592 if (group.Length != 1)
3593 // Oooops, can this ever happen ?
3596 PropertyInfo pi = (PropertyInfo) group [0];
3599 getter = pi.GetGetMethod (true);
3602 setter = pi.GetSetMethod (true);
3604 MethodInfo accessor = getter != null ? getter : setter;
3606 if (!accessor.IsVirtual)
3612 // We also perform the permission checking here, as the PropertyInfo does not
3613 // hold the information for the accessibility of its setter/getter
3615 // TODO: can use TypeManager.GetProperty to boost performance
3616 void ResolveAccessors (Type containerType)
3618 FindAccessors (containerType);
3620 if (getter != null) {
3621 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3622 IMethodData md = TypeManager.GetMethod (the_getter);
3624 md.SetMemberIsUsed ();
3626 AccessorTable [getter] = PropertyInfo;
3627 is_static = getter.IsStatic;
3630 if (setter != null) {
3631 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3632 IMethodData md = TypeManager.GetMethod (the_setter);
3634 md.SetMemberIsUsed ();
3636 AccessorTable [setter] = PropertyInfo;
3637 is_static = setter.IsStatic;
3641 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3644 InstanceExpression = null;
3648 if (InstanceExpression == null) {
3649 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3653 if (lvalue_instance)
3654 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3656 InstanceExpression = InstanceExpression.DoResolve (ec);
3657 if (InstanceExpression == null)
3660 InstanceExpression.CheckMarshalByRefAccess ();
3662 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3663 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3664 TypeManager.IsFamilyAccessible (ec.ContainerType, PropertyInfo.DeclaringType) &&
3665 !TypeManager.IsFamilyAccessible (InstanceExpression.Type, ec.ContainerType)) {
3666 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3673 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3675 // TODO: correctly we should compare arguments but it will lead to bigger changes
3676 if (mi is MethodBuilder) {
3677 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3681 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3683 ParameterData iparams = TypeManager.GetParameterData (mi);
3684 sig.Append (getter ? "get_" : "set_");
3686 sig.Append (iparams.GetSignatureForError ());
3688 Report.SymbolRelatedToPreviousError (mi);
3689 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3690 Name, sig.ToString ());
3693 override public Expression DoResolve (EmitContext ec)
3698 if (getter != null){
3699 if (TypeManager.GetParameterData (getter).Count != 0){
3700 Error_PropertyNotFound (getter, true);
3705 if (getter == null){
3707 // The following condition happens if the PropertyExpr was
3708 // created, but is invalid (ie, the property is inaccessible),
3709 // and we did not want to embed the knowledge about this in
3710 // the caller routine. This only avoids double error reporting.
3715 if (InstanceExpression != EmptyExpression.Null) {
3716 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3717 TypeManager.GetFullNameSignature (PropertyInfo));
3722 bool must_do_cs1540_check = false;
3723 if (getter != null &&
3724 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3725 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3726 if (pm != null && pm.HasCustomAccessModifier) {
3727 Report.SymbolRelatedToPreviousError (pm);
3728 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3729 TypeManager.CSharpSignature (getter));
3732 Report.SymbolRelatedToPreviousError (getter);
3733 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3738 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3742 // Only base will allow this invocation to happen.
3744 if (IsBase && getter.IsAbstract) {
3745 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3749 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3759 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3761 if (right_side == EmptyExpression.OutAccess) {
3762 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3763 GetSignatureForError ());
3767 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3768 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3769 GetSignatureForError ());
3773 if (setter == null){
3775 // The following condition happens if the PropertyExpr was
3776 // created, but is invalid (ie, the property is inaccessible),
3777 // and we did not want to embed the knowledge about this in
3778 // the caller routine. This only avoids double error reporting.
3782 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3783 GetSignatureForError ());
3787 if (TypeManager.GetParameterData (setter).Count != 1){
3788 Error_PropertyNotFound (setter, false);
3792 bool must_do_cs1540_check;
3793 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3794 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3795 if (pm != null && pm.HasCustomAccessModifier) {
3796 Report.SymbolRelatedToPreviousError (pm);
3797 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3798 TypeManager.CSharpSignature (setter));
3801 Report.SymbolRelatedToPreviousError (setter);
3802 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3807 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3811 // Only base will allow this invocation to happen.
3813 if (IsBase && setter.IsAbstract){
3814 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3821 public override void Emit (EmitContext ec)
3826 public void Emit (EmitContext ec, bool leave_copy)
3829 // Special case: length of single dimension array property is turned into ldlen
3831 if ((getter == TypeManager.system_int_array_get_length) ||
3832 (getter == TypeManager.int_array_get_length)){
3833 Type iet = InstanceExpression.Type;
3836 // System.Array.Length can be called, but the Type does not
3837 // support invoking GetArrayRank, so test for that case first
3839 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3841 EmitInstance (ec, false);
3842 ec.ig.Emit (OpCodes.Ldlen);
3843 ec.ig.Emit (OpCodes.Conv_I4);
3848 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3851 ec.ig.Emit (OpCodes.Dup);
3853 temp = new LocalTemporary (this.Type);
3860 // Implements the IAssignMethod interface for assignments
3862 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3864 Expression my_source = source;
3866 prepared = prepare_for_load;
3871 ec.ig.Emit (OpCodes.Dup);
3873 temp = new LocalTemporary (this.Type);
3877 } else if (leave_copy) {
3880 temp = new LocalTemporary (this.Type);
3886 ArrayList args = new ArrayList (1);
3887 args.Add (new Argument (my_source, Argument.AType.Expression));
3889 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3899 /// Fully resolved expression that evaluates to an Event
3901 public class EventExpr : MemberExpr {
3902 public readonly EventInfo EventInfo;
3905 MethodInfo add_accessor, remove_accessor;
3907 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3909 public EventExpr (EventInfo ei, Location loc)
3913 eclass = ExprClass.EventAccess;
3915 add_accessor = TypeManager.GetAddMethod (ei);
3916 remove_accessor = TypeManager.GetRemoveMethod (ei);
3917 if (add_accessor != null)
3918 AccessorTable [add_accessor] = ei;
3919 if (remove_accessor != null)
3920 AccessorTable [remove_accessor] = ei;
3922 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3925 if (EventInfo is MyEventBuilder){
3926 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3927 type = eb.EventType;
3930 type = EventInfo.EventHandlerType;
3933 public override string Name {
3935 return EventInfo.Name;
3939 public override bool IsInstance {
3945 public override bool IsStatic {
3951 public override Type DeclaringType {
3953 return EventInfo.DeclaringType;
3957 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3958 SimpleName original)
3961 // If the event is local to this class, we transform ourselves into a FieldExpr
3964 if (EventInfo.DeclaringType == ec.ContainerType ||
3965 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3966 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3969 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3972 Report.Error (-200, loc, "Internal error!!");
3976 InstanceExpression = null;
3978 return ml.ResolveMemberAccess (ec, left, loc, original);
3982 return base.ResolveMemberAccess (ec, left, loc, original);
3986 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3989 InstanceExpression = null;
3993 if (InstanceExpression == null) {
3994 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3998 InstanceExpression = InstanceExpression.DoResolve (ec);
3999 if (InstanceExpression == null)
4003 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4004 // However, in the Event case, we reported a CS0122 instead.
4006 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4007 InstanceExpression.Type != ec.ContainerType &&
4008 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4009 Report.SymbolRelatedToPreviousError (EventInfo);
4010 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4017 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4019 return DoResolve (ec);
4022 public override Expression DoResolve (EmitContext ec)
4024 bool must_do_cs1540_check;
4025 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4026 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4027 Report.SymbolRelatedToPreviousError (EventInfo);
4028 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4032 if (!InstanceResolve (ec, must_do_cs1540_check))
4038 public override void Emit (EmitContext ec)
4040 if (InstanceExpression is This)
4041 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4043 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4044 "(except on the defining type)", Name);
4047 public override string GetSignatureForError ()
4049 return TypeManager.CSharpSignature (EventInfo);
4052 public void EmitAddOrRemove (EmitContext ec, Expression source)
4054 BinaryDelegate source_del = (BinaryDelegate) source;
4055 Expression handler = source_del.Right;
4057 Argument arg = new Argument (handler, Argument.AType.Expression);
4058 ArrayList args = new ArrayList ();
4062 if (source_del.IsAddition)
4063 Invocation.EmitCall (
4064 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4066 Invocation.EmitCall (
4067 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4071 public class TemporaryVariable : Expression, IMemoryLocation
4076 public TemporaryVariable (Type type, Location loc)
4080 eclass = ExprClass.Value;
4083 public override Expression DoResolve (EmitContext ec)
4088 TypeExpr te = new TypeExpression (type, loc);
4089 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4090 if (!li.Resolve (ec))
4093 if (ec.MustCaptureVariable (li)) {
4094 ScopeInfo scope = li.Block.CreateScopeInfo ();
4095 var = scope.AddLocal (li);
4102 public Variable Variable {
4103 get { return var != null ? var : li.Variable; }
4106 public override void Emit (EmitContext ec)
4108 Variable.EmitInstance (ec);
4112 public void EmitLoadAddress (EmitContext ec)
4114 Variable.EmitInstance (ec);
4115 Variable.EmitAddressOf (ec);
4118 public void Store (EmitContext ec, Expression right_side)
4120 Variable.EmitInstance (ec);
4121 right_side.Emit (ec);
4122 Variable.EmitAssign (ec);
4125 public void EmitThis (EmitContext ec)
4127 Variable.EmitInstance (ec);
4130 public void EmitStore (EmitContext ec)
4132 Variable.EmitAssign (ec);
4135 public void AddressOf (EmitContext ec, AddressOp mode)
4137 EmitLoadAddress (ec);