2009-07-30 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / ecore.cs
blob20871c22ebb6f43f401a997b7b6b31c4f86b176a
1 //
2 // ecore.cs: Core of the Expression representation for the intermediate tree.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text;
21 /// <remarks>
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
25 /// nothing).
26 /// </remarks>
27 public enum ExprClass : byte {
28 Invalid,
30 Value,
31 Variable,
32 Namespace,
33 Type,
34 TypeParameter,
35 MethodGroup,
36 PropertyAccess,
37 EventAccess,
38 IndexerAccess,
39 Nothing,
42 /// <remarks>
43 /// This is used to tell Resolve in which types of expressions we're
44 /// interested.
45 /// </remarks>
46 [Flags]
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 VariableOrValue = 1,
51 // Returns a type expression.
52 Type = 1 << 1,
54 // Returns a method group.
55 MethodGroup = 1 << 2,
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
77 // address.
78 [Flags]
79 public enum AddressOp {
80 Store = 1,
81 Load = 2,
82 LoadStore = 3
85 /// <summary>
86 /// This interface is implemented by variables
87 /// </summary>
88 public interface IMemoryLocation {
89 /// <summary>
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
92 ///
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
96 ///
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
99 /// </summary>
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
109 string Name { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
117 // fixed
119 public interface IFixedExpression
121 bool IsFixed { get; }
124 /// <remarks>
125 /// Base class for expressions
126 /// </remarks>
127 public abstract class Expression {
128 public ExprClass eclass;
129 protected Type type;
130 protected Location loc;
132 public Type Type {
133 get { return type; }
134 set { type = value; }
137 public virtual Location Location {
138 get { return loc; }
141 /// <summary>
142 /// Utility wrapper routine for Error, just to beautify the code
143 /// </summary>
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
157 value = null;
158 return false;
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
173 return true;
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
184 return true;
185 } else {
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
187 return false;
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
193 return false;
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
198 return true;
201 public virtual bool IsNull {
202 get {
203 return false;
207 /// <summary>
208 /// Performs semantic analysis on the Expression
209 /// </summary>
211 /// <remarks>
212 /// The Resolve method is invoked to perform the semantic analysis
213 /// on the node.
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
218 ///
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
221 /// value.
222 ///
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
226 ///
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
232 /// expression).
233 /// </remarks>
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
238 return null;
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
247 if (!silent) {
248 Expression e = this;
249 EmitContext ec = rc as EmitContext;
250 if (ec != null)
251 e = e.Resolve (ec);
252 if (e != null)
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
255 return null;
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
270 // reference
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
275 if (te == null)
276 return null;
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 GenericTypeExpr ct = te as GenericTypeExpr;
286 if (ct != null) {
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
291 te.loc = loc;
292 return te;
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
299 return te;
302 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
304 int errors = Report.Errors;
306 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
308 if (fne == null)
309 return null;
311 TypeExpr te = fne as TypeExpr;
312 if (te == null) {
313 if (!silent && errors == Report.Errors)
314 fne.Error_UnexpectedKind (null, "type", loc);
315 return null;
318 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
319 Report.SymbolRelatedToPreviousError (te.Type);
320 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
321 return null;
324 te.loc = loc;
325 return te;
328 public static void ErrorIsInaccesible (Location loc, string name)
330 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
333 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
335 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager.GetFullNameSignature (m),
338 TypeManager.CSharpName (qualifier),
339 TypeManager.CSharpName (container));
343 public static void Error_InvalidExpressionStatement (Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc);
354 protected void Error_CannotAssign (string to, string roContext)
356 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
357 to, roContext);
360 public static void Error_VoidInvalidInTheContext (Location loc)
362 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
367 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
370 protected void Error_ValueCannotBeConvertedCore (EmitContext ec, Location loc, Type target, bool expl)
372 // The error was already reported as CS1660
373 if (type == InternalType.AnonymousMethod)
374 return;
376 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
377 #if GMCS_SOURCE
378 string sig1 = type.DeclaringMethod == null ?
379 TypeManager.CSharpName (type.DeclaringType) :
380 TypeManager.CSharpSignature (type.DeclaringMethod);
381 string sig2 = target.DeclaringMethod == null ?
382 TypeManager.CSharpName (target.DeclaringType) :
383 TypeManager.CSharpSignature (target.DeclaringMethod);
384 Report.ExtraInformation (loc,
385 String.Format (
386 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
387 Type.Name, sig1, sig2));
388 #endif
389 } else if (Type.FullName == target.FullName){
390 Report.ExtraInformation (loc,
391 String.Format (
392 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
393 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
396 if (expl) {
397 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
398 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
399 return;
402 Report.DisableReporting ();
403 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
404 Report.EnableReporting ();
406 if (expl_exists) {
407 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
408 "An explicit conversion exists (are you missing a cast?)",
409 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
410 return;
413 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
414 TypeManager.CSharpName (type),
415 TypeManager.CSharpName (target));
418 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
420 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
423 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
425 Error_TypeDoesNotContainDefinition (loc, type, name);
428 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
430 Report.SymbolRelatedToPreviousError (type);
431 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
432 TypeManager.CSharpName (type), name);
435 protected static void Error_ValueAssignment (Location loc)
437 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
440 ResolveFlags ExprClassToResolveFlags
442 get {
443 switch (eclass) {
444 case ExprClass.Type:
445 case ExprClass.Namespace:
446 return ResolveFlags.Type;
448 case ExprClass.MethodGroup:
449 return ResolveFlags.MethodGroup;
451 case ExprClass.TypeParameter:
452 return ResolveFlags.TypeParameter;
454 case ExprClass.Value:
455 case ExprClass.Variable:
456 case ExprClass.PropertyAccess:
457 case ExprClass.EventAccess:
458 case ExprClass.IndexerAccess:
459 return ResolveFlags.VariableOrValue;
461 default:
462 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
467 /// <summary>
468 /// Resolves an expression and performs semantic analysis on it.
469 /// </summary>
471 /// <remarks>
472 /// Currently Resolve wraps DoResolve to perform sanity
473 /// checking and assertion checking on what we expect from Resolve.
474 /// </remarks>
475 public Expression Resolve (EmitContext ec, ResolveFlags flags)
477 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
478 return ResolveAsTypeStep (ec, false);
480 bool do_flow_analysis = ec.DoFlowAnalysis;
481 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
482 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
483 do_flow_analysis = false;
484 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
485 omit_struct_analysis = true;
487 Expression e;
488 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
489 if (this is SimpleName) {
490 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
491 e = ((SimpleName) this).DoResolve (ec, intermediate);
492 } else {
493 e = DoResolve (ec);
497 if (e == null)
498 return null;
500 if ((flags & e.ExprClassToResolveFlags) == 0) {
501 e.Error_UnexpectedKind (flags, loc);
502 return null;
505 if (e.type == null && !(e is Namespace)) {
506 throw new Exception (
507 "Expression " + e.GetType () +
508 " did not set its type after Resolve\n" +
509 "called from: " + this.GetType ());
512 return e;
515 /// <summary>
516 /// Resolves an expression and performs semantic analysis on it.
517 /// </summary>
518 public Expression Resolve (EmitContext ec)
520 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
522 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
523 ((MethodGroupExpr) e).ReportUsageError ();
524 return null;
526 return e;
529 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
531 Expression e = Resolve (ec);
532 if (e == null)
533 return null;
535 Constant c = e as Constant;
536 if (c != null)
537 return c;
539 if (type != null && TypeManager.IsReferenceType (type))
540 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
541 else
542 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
544 return null;
547 /// <summary>
548 /// Resolves an expression for LValue assignment
549 /// </summary>
551 /// <remarks>
552 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
553 /// checking and assertion checking on what we expect from Resolve
554 /// </remarks>
555 public Expression ResolveLValue (EmitContext ec, Expression right_side)
557 int errors = Report.Errors;
558 bool out_access = right_side == EmptyExpression.OutAccess;
560 Expression e = DoResolveLValue (ec, right_side);
562 if (e != null && out_access && !(e is IMemoryLocation)) {
563 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
564 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
566 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
567 // e.GetType () + " " + e.GetSignatureForError ());
568 e = null;
571 if (e == null) {
572 if (errors == Report.Errors) {
573 if (out_access)
574 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
575 else
576 Error_ValueAssignment (loc);
578 return null;
581 if (e.eclass == ExprClass.Invalid)
582 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
584 if ((e.type == null) && !(e is GenericTypeExpr))
585 throw new Exception ("Expression " + e + " did not set its type after Resolve");
587 return e;
590 /// <summary>
591 /// Emits the code for the expression
592 /// </summary>
594 /// <remarks>
595 /// The Emit method is invoked to generate the code
596 /// for the expression.
597 /// </remarks>
598 public abstract void Emit (EmitContext ec);
600 // Emit code to branch to @target if this expression is equivalent to @on_true.
601 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
602 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
603 // including the use of conditional branches. Note also that a branch MUST be emitted
604 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
606 Emit (ec);
607 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
610 // Emit this expression for its side effects, not for its value.
611 // The default implementation is to emit the value, and then throw it away.
612 // Subclasses can provide more efficient implementations, but those MUST be equivalent
613 public virtual void EmitSideEffect (EmitContext ec)
615 Emit (ec);
616 ec.ig.Emit (OpCodes.Pop);
619 /// <summary>
620 /// Protected constructor. Only derivate types should
621 /// be able to be created
622 /// </summary>
624 protected Expression ()
626 eclass = ExprClass.Invalid;
627 type = null;
630 /// <summary>
631 /// Returns a fully formed expression after a MemberLookup
632 /// </summary>
633 ///
634 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
636 if (mi is EventInfo)
637 return new EventExpr ((EventInfo) mi, loc);
638 else if (mi is FieldInfo) {
639 FieldInfo fi = (FieldInfo) mi;
640 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
641 return new ConstantExpr (fi, loc);
642 return new FieldExpr (fi, loc);
643 } else if (mi is PropertyInfo)
644 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
645 else if (mi is Type) {
646 return new TypeExpression ((System.Type) mi, loc);
649 return null;
652 // TODO: [Obsolete ("Can be removed")]
653 protected static ArrayList almost_matched_members = new ArrayList (4);
656 // FIXME: Probably implement a cache for (t,name,current_access_set)?
658 // This code could use some optimizations, but we need to do some
659 // measurements. For example, we could use a delegate to `flag' when
660 // something can not any longer be a method-group (because it is something
661 // else).
663 // Return values:
664 // If the return value is an Array, then it is an array of
665 // MethodBases
667 // If the return value is an MemberInfo, it is anything, but a Method
669 // null on error.
671 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
672 // the arguments here and have MemberLookup return only the methods that
673 // match the argument count/type, unlike we are doing now (we delay this
674 // decision).
676 // This is so we can catch correctly attempts to invoke instance methods
677 // from a static body (scan for error 120 in ResolveSimpleName).
680 // FIXME: Potential optimization, have a static ArrayList
683 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
684 MemberTypes mt, BindingFlags bf, Location loc)
686 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
690 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
691 // `qualifier_type' or null to lookup members in the current class.
694 public static Expression MemberLookup (Type container_type,
695 Type qualifier_type, Type queried_type,
696 string name, MemberTypes mt,
697 BindingFlags bf, Location loc)
699 almost_matched_members.Clear ();
701 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
702 queried_type, mt, bf, name, almost_matched_members);
704 if (mi == null)
705 return null;
707 if (mi.Length > 1) {
708 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
709 ArrayList methods = new ArrayList (2);
710 ArrayList non_methods = null;
712 foreach (MemberInfo m in mi) {
713 if (m is MethodBase) {
714 methods.Add (m);
715 continue;
718 if (non_methods == null)
719 non_methods = new ArrayList (2);
721 bool is_candidate = true;
722 for (int i = 0; i < non_methods.Count; ++i) {
723 MemberInfo n_m = (MemberInfo) non_methods [i];
724 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
725 non_methods.Remove (n_m);
726 --i;
727 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
728 is_candidate = false;
729 break;
733 if (is_candidate) {
734 non_methods.Add (m);
738 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
739 Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [1]);
740 Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [0]);
741 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
742 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [1]),
743 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [0]));
744 return null;
747 if (methods.Count == 0)
748 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
750 if (non_methods != null && non_methods.Count > 0) {
751 MethodBase method = (MethodBase) methods [0];
752 MemberInfo non_method = (MemberInfo) non_methods [0];
753 if (method.DeclaringType == non_method.DeclaringType) {
754 // Cannot happen with C# code, but is valid in IL
755 Report.SymbolRelatedToPreviousError (method);
756 Report.SymbolRelatedToPreviousError (non_method);
757 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
758 TypeManager.GetFullNameSignature (non_method),
759 TypeManager.CSharpSignature (method));
760 return null;
763 if (is_interface) {
764 Report.SymbolRelatedToPreviousError (method);
765 Report.SymbolRelatedToPreviousError (non_method);
766 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
767 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
771 return new MethodGroupExpr (methods, queried_type, loc);
774 if (mi [0] is MethodBase)
775 return new MethodGroupExpr (mi, queried_type, loc);
777 return ExprClassFromMemberInfo (container_type, mi [0], loc);
780 public const MemberTypes AllMemberTypes =
781 MemberTypes.Constructor |
782 MemberTypes.Event |
783 MemberTypes.Field |
784 MemberTypes.Method |
785 MemberTypes.NestedType |
786 MemberTypes.Property;
788 public const BindingFlags AllBindingFlags =
789 BindingFlags.Public |
790 BindingFlags.Static |
791 BindingFlags.Instance;
793 public static Expression MemberLookup (Type container_type, Type queried_type,
794 string name, Location loc)
796 return MemberLookup (container_type, null, queried_type, name,
797 AllMemberTypes, AllBindingFlags, loc);
800 public static Expression MemberLookup (Type container_type, Type qualifier_type,
801 Type queried_type, string name, Location loc)
803 return MemberLookup (container_type, qualifier_type, queried_type,
804 name, AllMemberTypes, AllBindingFlags, loc);
807 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
808 string name, Location loc)
810 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
811 MemberTypes.Method, AllBindingFlags, loc);
814 /// <summary>
815 /// This is a wrapper for MemberLookup that is not used to "probe", but
816 /// to find a final definition. If the final definition is not found, we
817 /// look for private members and display a useful debugging message if we
818 /// find it.
819 /// </summary>
820 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
821 Type queried_type, string name,
822 MemberTypes mt, BindingFlags bf,
823 Location loc)
825 Expression e;
827 int errors = Report.Errors;
828 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
830 if (e != null || errors != Report.Errors)
831 return e;
833 // No errors were reported by MemberLookup, but there was an error.
834 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
835 name, null, mt, bf);
838 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
839 Type queried_type, string name, string class_name,
840 MemberTypes mt, BindingFlags bf)
842 MemberInfo[] lookup = null;
843 if (queried_type == null) {
844 class_name = "global::";
845 } else {
846 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
847 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
848 name, null);
850 if (lookup != null) {
851 Expression e = Error_MemberLookupFailed (queried_type, lookup);
854 // FIXME: This is still very wrong, it should be done inside
855 // OverloadResolve to do correct arguments matching.
856 // Requires MemberLookup accessiblity check removal
858 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
859 MemberInfo mi = lookup[0];
860 Report.SymbolRelatedToPreviousError (mi);
861 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
862 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
863 // Although a derived class can access protected members of
864 // its base class it cannot do so through an instance of the
865 // base class (CS1540). If the qualifier_type is a base of the
866 // ec.ContainerType and the lookup succeeds with the latter one,
867 // then we are in this situation.
868 Error_CannotAccessProtected (loc, mi, qualifier_type, container_type);
869 } else {
870 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi));
874 return e;
877 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
878 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
879 name, null);
882 if (lookup == null) {
883 if (class_name != null) {
884 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
885 name);
886 } else {
887 Error_TypeDoesNotContainDefinition (queried_type, name);
889 return null;
892 if (TypeManager.MemberLookup (queried_type, null, queried_type,
893 AllMemberTypes, AllBindingFlags |
894 BindingFlags.NonPublic, name, null) == null) {
895 if ((lookup.Length == 1) && (lookup [0] is Type)) {
896 Type t = (Type) lookup [0];
898 Report.Error (305, loc,
899 "Using the generic type `{0}' " +
900 "requires {1} type arguments",
901 TypeManager.CSharpName (t),
902 TypeManager.GetNumberOfTypeArguments (t).ToString ());
903 return null;
907 return Error_MemberLookupFailed (queried_type, lookup);
910 protected virtual Expression Error_MemberLookupFailed (Type type, MemberInfo[] members)
912 for (int i = 0; i < members.Length; ++i) {
913 if (!(members [i] is MethodBase))
914 return null;
917 // By default propagate the closest candidates upwards
918 return new MethodGroupExpr (members, type, loc, true);
921 protected virtual void Error_NegativeArrayIndex (Location loc)
923 throw new NotImplementedException ();
926 protected void Error_PointerInsideExpressionTree ()
928 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
931 /// <summary>
932 /// Returns an expression that can be used to invoke operator true
933 /// on the expression if it exists.
934 /// </summary>
935 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
937 return GetOperatorTrueOrFalse (ec, e, true, loc);
940 /// <summary>
941 /// Returns an expression that can be used to invoke operator false
942 /// on the expression if it exists.
943 /// </summary>
944 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
946 return GetOperatorTrueOrFalse (ec, e, false, loc);
949 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
951 MethodGroupExpr operator_group;
952 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
953 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
954 if (operator_group == null)
955 return null;
957 Arguments arguments = new Arguments (1);
958 arguments.Add (new Argument (e));
959 operator_group = operator_group.OverloadResolve (
960 ec, ref arguments, false, loc);
962 if (operator_group == null)
963 return null;
965 return new UserOperatorCall (operator_group, arguments, null, loc);
968 /// <summary>
969 /// Resolves the expression `e' into a boolean expression: either through
970 /// an implicit conversion, or through an `operator true' invocation
971 /// </summary>
972 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
974 e = e.Resolve (ec);
975 if (e == null)
976 return null;
978 if (e.Type == TypeManager.bool_type)
979 return e;
981 if (TypeManager.IsDynamicType (e.Type)) {
982 Arguments args = new Arguments (1);
983 args.Add (new Argument (e));
984 return new DynamicUnaryConversion ("IsTrue", args, loc);
987 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
989 if (converted != null)
990 return converted;
993 // If no implicit conversion to bool exists, try using `operator true'
995 converted = Expression.GetOperatorTrue (ec, e, loc);
996 if (converted == null){
997 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
998 return null;
1000 return converted;
1003 public virtual string ExprClassName
1005 get {
1006 switch (eclass){
1007 case ExprClass.Invalid:
1008 return "Invalid";
1009 case ExprClass.Value:
1010 return "value";
1011 case ExprClass.Variable:
1012 return "variable";
1013 case ExprClass.Namespace:
1014 return "namespace";
1015 case ExprClass.Type:
1016 return "type";
1017 case ExprClass.MethodGroup:
1018 return "method group";
1019 case ExprClass.PropertyAccess:
1020 return "property access";
1021 case ExprClass.EventAccess:
1022 return "event access";
1023 case ExprClass.IndexerAccess:
1024 return "indexer access";
1025 case ExprClass.Nothing:
1026 return "null";
1027 case ExprClass.TypeParameter:
1028 return "type parameter";
1030 throw new Exception ("Should not happen");
1034 /// <summary>
1035 /// Reports that we were expecting `expr' to be of class `expected'
1036 /// </summary>
1037 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1039 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1042 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1044 string name = GetSignatureForError ();
1045 if (ds != null)
1046 name = ds.GetSignatureForError () + '.' + name;
1048 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1049 name, was, expected);
1052 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1054 string [] valid = new string [4];
1055 int count = 0;
1057 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1058 valid [count++] = "variable";
1059 valid [count++] = "value";
1062 if ((flags & ResolveFlags.Type) != 0)
1063 valid [count++] = "type";
1065 if ((flags & ResolveFlags.MethodGroup) != 0)
1066 valid [count++] = "method group";
1068 if (count == 0)
1069 valid [count++] = "unknown";
1071 StringBuilder sb = new StringBuilder (valid [0]);
1072 for (int i = 1; i < count - 1; i++) {
1073 sb.Append ("', `");
1074 sb.Append (valid [i]);
1076 if (count > 1) {
1077 sb.Append ("' or `");
1078 sb.Append (valid [count - 1]);
1081 Report.Error (119, loc,
1082 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1085 public static void UnsafeError (Location loc)
1087 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1091 // Load the object from the pointer.
1093 public static void LoadFromPtr (ILGenerator ig, Type t)
1095 if (t == TypeManager.int32_type)
1096 ig.Emit (OpCodes.Ldind_I4);
1097 else if (t == TypeManager.uint32_type)
1098 ig.Emit (OpCodes.Ldind_U4);
1099 else if (t == TypeManager.short_type)
1100 ig.Emit (OpCodes.Ldind_I2);
1101 else if (t == TypeManager.ushort_type)
1102 ig.Emit (OpCodes.Ldind_U2);
1103 else if (t == TypeManager.char_type)
1104 ig.Emit (OpCodes.Ldind_U2);
1105 else if (t == TypeManager.byte_type)
1106 ig.Emit (OpCodes.Ldind_U1);
1107 else if (t == TypeManager.sbyte_type)
1108 ig.Emit (OpCodes.Ldind_I1);
1109 else if (t == TypeManager.uint64_type)
1110 ig.Emit (OpCodes.Ldind_I8);
1111 else if (t == TypeManager.int64_type)
1112 ig.Emit (OpCodes.Ldind_I8);
1113 else if (t == TypeManager.float_type)
1114 ig.Emit (OpCodes.Ldind_R4);
1115 else if (t == TypeManager.double_type)
1116 ig.Emit (OpCodes.Ldind_R8);
1117 else if (t == TypeManager.bool_type)
1118 ig.Emit (OpCodes.Ldind_I1);
1119 else if (t == TypeManager.intptr_type)
1120 ig.Emit (OpCodes.Ldind_I);
1121 else if (TypeManager.IsEnumType (t)) {
1122 if (t == TypeManager.enum_type)
1123 ig.Emit (OpCodes.Ldind_Ref);
1124 else
1125 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1126 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1127 ig.Emit (OpCodes.Ldobj, t);
1128 else if (t.IsPointer)
1129 ig.Emit (OpCodes.Ldind_I);
1130 else
1131 ig.Emit (OpCodes.Ldind_Ref);
1135 // The stack contains the pointer and the value of type `type'
1137 public static void StoreFromPtr (ILGenerator ig, Type type)
1139 if (TypeManager.IsEnumType (type))
1140 type = TypeManager.GetEnumUnderlyingType (type);
1141 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1142 ig.Emit (OpCodes.Stind_I4);
1143 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1144 ig.Emit (OpCodes.Stind_I8);
1145 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1146 type == TypeManager.ushort_type)
1147 ig.Emit (OpCodes.Stind_I2);
1148 else if (type == TypeManager.float_type)
1149 ig.Emit (OpCodes.Stind_R4);
1150 else if (type == TypeManager.double_type)
1151 ig.Emit (OpCodes.Stind_R8);
1152 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1153 type == TypeManager.bool_type)
1154 ig.Emit (OpCodes.Stind_I1);
1155 else if (type == TypeManager.intptr_type)
1156 ig.Emit (OpCodes.Stind_I);
1157 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1158 ig.Emit (OpCodes.Stobj, type);
1159 else
1160 ig.Emit (OpCodes.Stind_Ref);
1164 // Returns the size of type `t' if known, otherwise, 0
1166 public static int GetTypeSize (Type t)
1168 t = TypeManager.TypeToCoreType (t);
1169 if (t == TypeManager.int32_type ||
1170 t == TypeManager.uint32_type ||
1171 t == TypeManager.float_type)
1172 return 4;
1173 else if (t == TypeManager.int64_type ||
1174 t == TypeManager.uint64_type ||
1175 t == TypeManager.double_type)
1176 return 8;
1177 else if (t == TypeManager.byte_type ||
1178 t == TypeManager.sbyte_type ||
1179 t == TypeManager.bool_type)
1180 return 1;
1181 else if (t == TypeManager.short_type ||
1182 t == TypeManager.char_type ||
1183 t == TypeManager.ushort_type)
1184 return 2;
1185 else if (t == TypeManager.decimal_type)
1186 return 16;
1187 else
1188 return 0;
1191 protected void Error_CannotCallAbstractBase (string name)
1193 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1196 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1198 Report.SymbolRelatedToPreviousError (type);
1199 if (ec.CurrentInitializerVariable != null) {
1200 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1201 TypeManager.CSharpName (type), GetSignatureForError ());
1202 } else {
1203 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1204 GetSignatureForError ());
1208 public void Error_ExpressionCannotBeGeneric (Location loc)
1210 Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
1211 ExprClassName, GetSignatureForError ());
1215 // Converts `source' to an int, uint, long or ulong.
1217 protected Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1219 if (TypeManager.IsDynamicType (source.type)) {
1220 Arguments args = new Arguments (1);
1221 args.Add (new Argument (source));
1222 return new DynamicConversion (TypeManager.int32_type, false, args, loc).Resolve (ec);
1225 Expression converted;
1227 using (ec.With (EmitContext.Flags.CheckState, true)) {
1228 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1229 if (converted == null)
1230 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1231 if (converted == null)
1232 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1233 if (converted == null)
1234 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1236 if (converted == null) {
1237 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1238 return null;
1243 // Only positive constants are allowed at compile time
1245 Constant c = converted as Constant;
1246 if (c != null) {
1247 if (c.IsNegative) {
1248 Error_NegativeArrayIndex (source.loc);
1250 return c;
1253 return new ArrayIndexCast (converted).Resolve (ec);
1257 // Derived classes implement this method by cloning the fields that
1258 // could become altered during the Resolve stage
1260 // Only expressions that are created for the parser need to implement
1261 // this.
1263 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1265 throw new NotImplementedException (
1266 String.Format (
1267 "CloneTo not implemented for expression {0}", this.GetType ()));
1271 // Clones an expression created by the parser.
1273 // We only support expressions created by the parser so far, not
1274 // expressions that have been resolved (many more classes would need
1275 // to implement CloneTo).
1277 // This infrastructure is here merely for Lambda expressions which
1278 // compile the same code using different type values for the same
1279 // arguments to find the correct overload
1281 public Expression Clone (CloneContext clonectx)
1283 Expression cloned = (Expression) MemberwiseClone ();
1284 CloneTo (clonectx, cloned);
1286 return cloned;
1290 // Implementation of expression to expression tree conversion
1292 public abstract Expression CreateExpressionTree (EmitContext ec);
1294 protected Expression CreateExpressionFactoryCall (string name, Arguments args)
1296 return CreateExpressionFactoryCall (name, null, args, loc);
1299 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, Arguments args)
1301 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1304 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, Arguments args, Location loc)
1306 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1309 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1311 TypeExpr texpr = TypeManager.expression_type_expr;
1312 if (texpr == null) {
1313 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1314 if (t == null)
1315 return null;
1317 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1320 return texpr;
1323 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1325 // TODO: It should probably be type = storey.MutateType (type);
1329 /// <summary>
1330 /// This is just a base class for expressions that can
1331 /// appear on statements (invocations, object creation,
1332 /// assignments, post/pre increment and decrement). The idea
1333 /// being that they would support an extra Emition interface that
1334 /// does not leave a result on the stack.
1335 /// </summary>
1336 public abstract class ExpressionStatement : Expression {
1338 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1340 Expression e = Resolve (ec);
1341 if (e == null)
1342 return null;
1344 ExpressionStatement es = e as ExpressionStatement;
1345 if (es == null)
1346 Error_InvalidExpressionStatement ();
1348 return es;
1351 /// <summary>
1352 /// Requests the expression to be emitted in a `statement'
1353 /// context. This means that no new value is left on the
1354 /// stack after invoking this method (constrasted with
1355 /// Emit that will always leave a value on the stack).
1356 /// </summary>
1357 public abstract void EmitStatement (EmitContext ec);
1359 public override void EmitSideEffect (EmitContext ec)
1361 EmitStatement (ec);
1365 /// <summary>
1366 /// This kind of cast is used to encapsulate the child
1367 /// whose type is child.Type into an expression that is
1368 /// reported to return "return_type". This is used to encapsulate
1369 /// expressions which have compatible types, but need to be dealt
1370 /// at higher levels with.
1372 /// For example, a "byte" expression could be encapsulated in one
1373 /// of these as an "unsigned int". The type for the expression
1374 /// would be "unsigned int".
1376 /// </summary>
1377 public abstract class TypeCast : Expression
1379 protected readonly Expression child;
1381 protected TypeCast (Expression child, Type return_type)
1383 eclass = child.eclass;
1384 loc = child.Location;
1385 type = return_type;
1386 this.child = child;
1389 public override Expression CreateExpressionTree (EmitContext ec)
1391 Arguments args = new Arguments (2);
1392 args.Add (new Argument (child.CreateExpressionTree (ec)));
1393 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1395 if (type.IsPointer || child.Type.IsPointer)
1396 Error_PointerInsideExpressionTree ();
1398 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1401 public override Expression DoResolve (EmitContext ec)
1403 // This should never be invoked, we are born in fully
1404 // initialized state.
1406 return this;
1409 public override void Emit (EmitContext ec)
1411 child.Emit (ec);
1414 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1416 return child.GetAttributableValue (ec, value_type, out value);
1419 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1421 type = storey.MutateType (type);
1422 child.MutateHoistedGenericType (storey);
1425 protected override void CloneTo (CloneContext clonectx, Expression t)
1427 // Nothing to clone
1430 public override bool IsNull {
1431 get { return child.IsNull; }
1435 public class EmptyCast : TypeCast {
1436 EmptyCast (Expression child, Type target_type)
1437 : base (child, target_type)
1441 public static Expression Create (Expression child, Type type)
1443 Constant c = child as Constant;
1444 if (c != null)
1445 return new EmptyConstantCast (c, type);
1447 EmptyCast e = child as EmptyCast;
1448 if (e != null)
1449 return new EmptyCast (e.child, type);
1451 return new EmptyCast (child, type);
1454 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1456 child.EmitBranchable (ec, label, on_true);
1459 public override void EmitSideEffect (EmitContext ec)
1461 child.EmitSideEffect (ec);
1466 // Used for predefined class library user casts (no obsolete check, etc.)
1468 public class OperatorCast : TypeCast {
1469 MethodInfo conversion_operator;
1471 public OperatorCast (Expression child, Type target_type)
1472 : this (child, target_type, false)
1476 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1477 : base (child, target_type)
1479 conversion_operator = GetConversionOperator (find_explicit);
1480 if (conversion_operator == null)
1481 throw new InternalErrorException ("Outer conversion routine is out of sync");
1484 // Returns the implicit operator that converts from
1485 // 'child.Type' to our target type (type)
1486 MethodInfo GetConversionOperator (bool find_explicit)
1488 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1490 MemberInfo [] mi;
1492 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1493 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1495 if (mi == null){
1496 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1497 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1500 foreach (MethodInfo oper in mi) {
1501 AParametersCollection pd = TypeManager.GetParameterData (oper);
1503 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1504 return oper;
1507 return null;
1510 public override void Emit (EmitContext ec)
1512 child.Emit (ec);
1513 ec.ig.Emit (OpCodes.Call, conversion_operator);
1517 /// <summary>
1518 /// This is a numeric cast to a Decimal
1519 /// </summary>
1520 public class CastToDecimal : OperatorCast {
1521 public CastToDecimal (Expression child)
1522 : this (child, false)
1526 public CastToDecimal (Expression child, bool find_explicit)
1527 : base (child, TypeManager.decimal_type, find_explicit)
1532 /// <summary>
1533 /// This is an explicit numeric cast from a Decimal
1534 /// </summary>
1535 public class CastFromDecimal : TypeCast
1537 static IDictionary operators;
1539 public CastFromDecimal (Expression child, Type return_type)
1540 : base (child, return_type)
1542 if (child.Type != TypeManager.decimal_type)
1543 throw new InternalErrorException (
1544 "The expected type is Decimal, instead it is " + child.Type.FullName);
1547 // Returns the explicit operator that converts from an
1548 // express of type System.Decimal to 'type'.
1549 public Expression Resolve ()
1551 if (operators == null) {
1552 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1553 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1554 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1556 operators = new System.Collections.Specialized.HybridDictionary ();
1557 foreach (MethodInfo oper in all_oper) {
1558 AParametersCollection pd = TypeManager.GetParameterData (oper);
1559 if (pd.Types [0] == TypeManager.decimal_type)
1560 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1564 return operators.Contains (type) ? this : null;
1567 public override void Emit (EmitContext ec)
1569 ILGenerator ig = ec.ig;
1570 child.Emit (ec);
1572 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1578 // Constant specialization of EmptyCast.
1579 // We need to special case this since an empty cast of
1580 // a constant is still a constant.
1582 public class EmptyConstantCast : Constant
1584 public readonly Constant child;
1586 public EmptyConstantCast(Constant child, Type type)
1587 : base (child.Location)
1589 eclass = child.eclass;
1590 this.child = child;
1591 this.type = type;
1594 public override string AsString ()
1596 return child.AsString ();
1599 public override object GetValue ()
1601 return child.GetValue ();
1604 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1606 // FIXME: check that 'type' can be converted to 'target_type' first
1607 return child.ConvertExplicitly (in_checked_context, target_type);
1610 public override Expression CreateExpressionTree (EmitContext ec)
1612 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1613 child.CreateExpressionTree (ec),
1614 new TypeOf (new TypeExpression (type, loc), loc));
1616 if (type.IsPointer)
1617 Error_PointerInsideExpressionTree ();
1619 return CreateExpressionFactoryCall ("Convert", args);
1622 public override Constant Increment ()
1624 return child.Increment ();
1627 public override bool IsDefaultValue {
1628 get { return child.IsDefaultValue; }
1631 public override bool IsNegative {
1632 get { return child.IsNegative; }
1635 public override bool IsNull {
1636 get { return child.IsNull; }
1639 public override bool IsZeroInteger {
1640 get { return child.IsZeroInteger; }
1643 public override void Emit (EmitContext ec)
1645 child.Emit (ec);
1648 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1650 child.EmitBranchable (ec, label, on_true);
1652 #if GMCS_SOURCE
1653 // Only to make verifier happy
1654 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1655 ec.ig.Emit (OpCodes.Unbox_Any, type);
1656 #endif
1659 public override void EmitSideEffect (EmitContext ec)
1661 child.EmitSideEffect (ec);
1664 public override Constant ConvertImplicitly (Type target_type)
1666 // FIXME: Do we need to check user conversions?
1667 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1668 return null;
1669 return child.ConvertImplicitly (target_type);
1672 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1674 child.MutateHoistedGenericType (storey);
1679 /// <summary>
1680 /// This class is used to wrap literals which belong inside Enums
1681 /// </summary>
1682 public class EnumConstant : Constant {
1683 public Constant Child;
1685 public EnumConstant (Constant child, Type enum_type):
1686 base (child.Location)
1688 eclass = child.eclass;
1689 this.Child = child;
1690 type = enum_type;
1693 public override Expression DoResolve (EmitContext ec)
1695 // This should never be invoked, we are born in fully
1696 // initialized state.
1698 return this;
1701 public override void Emit (EmitContext ec)
1703 Child.Emit (ec);
1706 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1708 Child.EmitBranchable (ec, label, on_true);
1711 public override void EmitSideEffect (EmitContext ec)
1713 Child.EmitSideEffect (ec);
1716 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1718 value = GetTypedValue ();
1719 return true;
1722 public override string GetSignatureForError()
1724 return TypeManager.CSharpName (Type);
1727 public override object GetValue ()
1729 return Child.GetValue ();
1732 public override object GetTypedValue ()
1734 // FIXME: runtime is not ready to work with just emited enums
1735 if (!RootContext.StdLib) {
1736 return Child.GetValue ();
1739 #if MS_COMPATIBLE
1740 // Small workaround for big problem
1741 // System.Enum.ToObject cannot be called on dynamic types
1742 // EnumBuilder has to be used, but we cannot use EnumBuilder
1743 // because it does not properly support generics
1745 // This works only sometimes
1747 if (type.Module == RootContext.ToplevelTypes.Builder)
1748 return Child.GetValue ();
1749 #endif
1751 return System.Enum.ToObject (type, Child.GetValue ());
1754 public override string AsString ()
1756 return Child.AsString ();
1759 public override Constant Increment()
1761 return new EnumConstant (Child.Increment (), type);
1764 public override bool IsDefaultValue {
1765 get {
1766 return Child.IsDefaultValue;
1770 public override bool IsZeroInteger {
1771 get { return Child.IsZeroInteger; }
1774 public override bool IsNegative {
1775 get {
1776 return Child.IsNegative;
1780 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1782 if (Child.Type == target_type)
1783 return Child;
1785 return Child.ConvertExplicitly (in_checked_context, target_type);
1788 public override Constant ConvertImplicitly (Type type)
1790 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1791 type = TypeManager.DropGenericTypeArguments (type);
1793 if (this_type == type) {
1794 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1795 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1796 return this;
1798 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1799 if (type.UnderlyingSystemType != child_type)
1800 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1801 return this;
1804 if (!Convert.ImplicitStandardConversionExists (this, type)){
1805 return null;
1808 return Child.ConvertImplicitly(type);
1813 /// <summary>
1814 /// This kind of cast is used to encapsulate Value Types in objects.
1816 /// The effect of it is to box the value type emitted by the previous
1817 /// operation.
1818 /// </summary>
1819 public class BoxedCast : TypeCast {
1821 public BoxedCast (Expression expr, Type target_type)
1822 : base (expr, target_type)
1824 eclass = ExprClass.Value;
1827 public override Expression DoResolve (EmitContext ec)
1829 // This should never be invoked, we are born in fully
1830 // initialized state.
1832 return this;
1835 public override void Emit (EmitContext ec)
1837 base.Emit (ec);
1839 ec.ig.Emit (OpCodes.Box, child.Type);
1842 public override void EmitSideEffect (EmitContext ec)
1844 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1845 // so, we need to emit the box+pop instructions in most cases
1846 if (TypeManager.IsStruct (child.Type) &&
1847 (type == TypeManager.object_type || type == TypeManager.value_type))
1848 child.EmitSideEffect (ec);
1849 else
1850 base.EmitSideEffect (ec);
1854 public class UnboxCast : TypeCast {
1855 public UnboxCast (Expression expr, Type return_type)
1856 : base (expr, return_type)
1860 public override Expression DoResolve (EmitContext ec)
1862 // This should never be invoked, we are born in fully
1863 // initialized state.
1865 return this;
1868 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1870 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1871 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1872 return base.DoResolveLValue (ec, right_side);
1875 public override void Emit (EmitContext ec)
1877 base.Emit (ec);
1879 ILGenerator ig = ec.ig;
1881 #if GMCS_SOURCE
1882 ig.Emit (OpCodes.Unbox_Any, type);
1883 #else
1884 ig.Emit (OpCodes.Unbox, type);
1885 LoadFromPtr (ig, type);
1886 #endif
1889 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1891 type = storey.MutateType (type);
1892 base.MutateHoistedGenericType (storey);
1896 /// <summary>
1897 /// This is used to perform explicit numeric conversions.
1899 /// Explicit numeric conversions might trigger exceptions in a checked
1900 /// context, so they should generate the conv.ovf opcodes instead of
1901 /// conv opcodes.
1902 /// </summary>
1903 public class ConvCast : TypeCast {
1904 public enum Mode : byte {
1905 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1906 U1_I1, U1_CH,
1907 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1908 U2_I1, U2_U1, U2_I2, U2_CH,
1909 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1910 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1911 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1912 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1913 CH_I1, CH_U1, CH_I2,
1914 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1915 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1918 Mode mode;
1920 public ConvCast (Expression child, Type return_type, Mode m)
1921 : base (child, return_type)
1923 mode = m;
1926 public override Expression DoResolve (EmitContext ec)
1928 // This should never be invoked, we are born in fully
1929 // initialized state.
1931 return this;
1934 public override string ToString ()
1936 return String.Format ("ConvCast ({0}, {1})", mode, child);
1939 public override void Emit (EmitContext ec)
1941 ILGenerator ig = ec.ig;
1943 base.Emit (ec);
1945 if (ec.CheckState){
1946 switch (mode){
1947 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1948 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1950 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1951 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1954 case Mode.U1_CH: /* nothing */ break;
1956 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1957 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1958 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1959 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1960 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1964 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1965 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.U2_CH: /* nothing */ break;
1968 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1969 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1970 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1971 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1972 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1979 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1980 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1981 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1983 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1984 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1985 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1986 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1988 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1989 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1990 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1993 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1994 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1995 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1996 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1997 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1998 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1999 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2001 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2002 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2003 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2005 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2006 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2007 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2008 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2009 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2010 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2011 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2012 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2013 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2016 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2017 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2018 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2019 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2020 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2021 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2022 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2023 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2024 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2026 } else {
2027 switch (mode){
2028 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2029 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2031 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2032 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2034 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2035 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2037 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2041 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2042 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2044 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2045 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2046 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2047 case Mode.U2_CH: /* nothing */ break;
2049 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2050 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2051 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2052 case Mode.I4_U4: /* nothing */ break;
2053 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2054 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2055 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2058 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2059 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2060 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2061 case Mode.U4_I4: /* nothing */ break;
2062 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2064 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2065 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2066 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2067 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2068 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2069 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2070 case Mode.I8_U8: /* nothing */ break;
2071 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2073 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2074 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2075 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2076 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2077 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2078 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2079 case Mode.U8_I8: /* nothing */ break;
2080 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2082 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2083 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2084 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2086 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2087 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2088 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2089 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2090 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2091 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2092 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2093 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2094 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2097 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2098 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2099 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2100 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2101 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2102 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2103 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2104 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2111 public class OpcodeCast : TypeCast {
2112 readonly OpCode op;
2114 public OpcodeCast (Expression child, Type return_type, OpCode op)
2115 : base (child, return_type)
2117 this.op = op;
2120 public override Expression DoResolve (EmitContext ec)
2122 // This should never be invoked, we are born in fully
2123 // initialized state.
2125 return this;
2128 public override void Emit (EmitContext ec)
2130 base.Emit (ec);
2131 ec.ig.Emit (op);
2134 public Type UnderlyingType {
2135 get { return child.Type; }
2139 /// <summary>
2140 /// This kind of cast is used to encapsulate a child and cast it
2141 /// to the class requested
2142 /// </summary>
2143 public sealed class ClassCast : TypeCast {
2144 readonly bool forced;
2146 public ClassCast (Expression child, Type return_type)
2147 : base (child, return_type)
2151 public ClassCast (Expression child, Type return_type, bool forced)
2152 : base (child, return_type)
2154 this.forced = forced;
2157 public override void Emit (EmitContext ec)
2159 base.Emit (ec);
2161 #if GMCS_SOURCE
2162 bool gen = TypeManager.IsGenericParameter (child.Type);
2163 if (gen)
2164 ec.ig.Emit (OpCodes.Box, child.Type);
2166 if (type.IsGenericParameter) {
2167 ec.ig.Emit (OpCodes.Unbox_Any, type);
2168 return;
2171 if (gen && !forced)
2172 return;
2173 #endif
2175 ec.ig.Emit (OpCodes.Castclass, type);
2180 // Created during resolving pahse when an expression is wrapped or constantified
2181 // and original expression can be used later (e.g. for expression trees)
2183 public class ReducedExpression : Expression
2185 sealed class ReducedConstantExpression : EmptyConstantCast
2187 readonly Expression orig_expr;
2189 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2190 : base (expr, expr.Type)
2192 this.orig_expr = orig_expr;
2195 public override Constant ConvertImplicitly (Type target_type)
2197 Constant c = base.ConvertImplicitly (target_type);
2198 if (c != null)
2199 c = new ReducedConstantExpression (c, orig_expr);
2200 return c;
2203 public override Expression CreateExpressionTree (EmitContext ec)
2205 return orig_expr.CreateExpressionTree (ec);
2208 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2211 // Even if resolved result is a constant original expression was not
2212 // and attribute accepts constants only
2214 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2215 value = null;
2216 return false;
2219 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2221 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2222 if (c != null)
2223 c = new ReducedConstantExpression (c, orig_expr);
2224 return c;
2228 sealed class ReducedExpressionStatement : ExpressionStatement
2230 readonly Expression orig_expr;
2231 readonly ExpressionStatement stm;
2233 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2235 this.orig_expr = orig;
2236 this.stm = stm;
2237 this.loc = orig.Location;
2240 public override Expression CreateExpressionTree (EmitContext ec)
2242 return orig_expr.CreateExpressionTree (ec);
2245 public override Expression DoResolve (EmitContext ec)
2247 eclass = stm.eclass;
2248 type = stm.Type;
2249 return this;
2252 public override void Emit (EmitContext ec)
2254 stm.Emit (ec);
2257 public override void EmitStatement (EmitContext ec)
2259 stm.EmitStatement (ec);
2262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2264 stm.MutateHoistedGenericType (storey);
2268 readonly Expression expr, orig_expr;
2270 private ReducedExpression (Expression expr, Expression orig_expr)
2272 this.expr = expr;
2273 this.orig_expr = orig_expr;
2274 this.loc = orig_expr.Location;
2277 public static Constant Create (Constant expr, Expression original_expr)
2279 return new ReducedConstantExpression (expr, original_expr);
2282 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2284 return new ReducedExpressionStatement (s, orig);
2287 public static Expression Create (Expression expr, Expression original_expr)
2289 Constant c = expr as Constant;
2290 if (c != null)
2291 return Create (c, original_expr);
2293 ExpressionStatement s = expr as ExpressionStatement;
2294 if (s != null)
2295 return Create (s, original_expr);
2297 return new ReducedExpression (expr, original_expr);
2300 public override Expression CreateExpressionTree (EmitContext ec)
2302 return orig_expr.CreateExpressionTree (ec);
2305 public override Expression DoResolve (EmitContext ec)
2307 eclass = expr.eclass;
2308 type = expr.Type;
2309 return this;
2312 public override void Emit (EmitContext ec)
2314 expr.Emit (ec);
2317 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2319 expr.EmitBranchable (ec, target, on_true);
2322 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2324 expr.MutateHoistedGenericType (storey);
2329 // Unresolved type name expressions
2331 public abstract class ATypeNameExpression : FullNamedExpression
2333 public readonly string Name;
2334 protected TypeArguments targs;
2336 protected ATypeNameExpression (string name, Location l)
2338 Name = name;
2339 loc = l;
2342 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2344 Name = name;
2345 this.targs = targs;
2346 loc = l;
2349 public bool HasTypeArguments {
2350 get {
2351 return targs != null;
2355 public override bool Equals (object obj)
2357 ATypeNameExpression atne = obj as ATypeNameExpression;
2358 return atne != null && atne.Name == Name &&
2359 (targs == null || targs.Equals (atne.targs));
2362 public override int GetHashCode ()
2364 return Name.GetHashCode ();
2367 public override string GetSignatureForError ()
2369 if (targs != null) {
2370 return TypeManager.RemoveGenericArity (Name) + "<" +
2371 targs.GetSignatureForError () + ">";
2374 return Name;
2378 /// <summary>
2379 /// SimpleName expressions are formed of a single word and only happen at the beginning
2380 /// of a dotted-name.
2381 /// </summary>
2382 public class SimpleName : ATypeNameExpression {
2383 bool in_transit;
2385 public SimpleName (string name, Location l)
2386 : base (name, l)
2390 public SimpleName (string name, TypeArguments args, Location l)
2391 : base (name, args, l)
2395 public SimpleName (string name, TypeParameter[] type_params, Location l)
2396 : base (name, l)
2398 targs = new TypeArguments ();
2399 foreach (TypeParameter type_param in type_params)
2400 targs.Add (new TypeParameterExpr (type_param, l));
2403 public static string RemoveGenericArity (string name)
2405 int start = 0;
2406 StringBuilder sb = null;
2407 do {
2408 int pos = name.IndexOf ('`', start);
2409 if (pos < 0) {
2410 if (start == 0)
2411 return name;
2413 sb.Append (name.Substring (start));
2414 break;
2417 if (sb == null)
2418 sb = new StringBuilder ();
2419 sb.Append (name.Substring (start, pos-start));
2421 pos++;
2422 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2423 pos++;
2425 start = pos;
2426 } while (start < name.Length);
2428 return sb.ToString ();
2431 public SimpleName GetMethodGroup ()
2433 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2436 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2438 if (ec.IsInFieldInitializer)
2439 Report.Error (236, l,
2440 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2441 name);
2442 else
2443 Report.Error (120, l,
2444 "An object reference is required to access non-static member `{0}'",
2445 name);
2448 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2450 return resolved_to != null && resolved_to.Type != null &&
2451 resolved_to.Type.Name == Name &&
2452 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2455 public override Expression DoResolve (EmitContext ec)
2457 return SimpleNameResolve (ec, null, false);
2460 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2462 return SimpleNameResolve (ec, right_side, false);
2466 public Expression DoResolve (EmitContext ec, bool intermediate)
2468 return SimpleNameResolve (ec, null, intermediate);
2471 static bool IsNestedChild (Type t, Type parent)
2473 while (parent != null) {
2474 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2475 return true;
2477 parent = parent.BaseType;
2480 return false;
2483 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2485 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2486 return null;
2488 DeclSpace ds = ec.DeclContainer;
2489 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2490 ds = ds.Parent;
2492 if (ds == null)
2493 return null;
2495 Type[] gen_params = TypeManager.GetTypeArguments (t);
2497 int arg_count = targs != null ? targs.Count : 0;
2499 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2500 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2501 TypeArguments new_args = new TypeArguments ();
2502 foreach (TypeParameter param in ds.TypeParameters)
2503 new_args.Add (new TypeParameterExpr (param, loc));
2505 if (targs != null)
2506 new_args.Add (targs);
2508 return new GenericTypeExpr (t, new_args, loc);
2512 return null;
2515 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2517 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2518 if (fne != null)
2519 return fne.ResolveAsTypeStep (ec, silent);
2521 int errors = Report.Errors;
2522 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2524 if (fne != null) {
2525 if (fne.Type == null)
2526 return fne;
2528 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2529 if (nested != null)
2530 return nested.ResolveAsTypeStep (ec, false);
2532 if (targs != null) {
2533 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2534 return ct.ResolveAsTypeStep (ec, false);
2537 return fne;
2540 if (!HasTypeArguments && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3)
2541 return new DynamicTypeExpr (loc);
2543 if (silent || errors != Report.Errors)
2544 return null;
2546 Error_TypeOrNamespaceNotFound (ec);
2547 return null;
2550 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2552 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2553 if (mc != null) {
2554 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2555 return;
2558 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2559 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2560 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2561 Type type = a.GetType (fullname);
2562 if (type != null) {
2563 Report.SymbolRelatedToPreviousError (type);
2564 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2565 return;
2569 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2570 if (t != null) {
2571 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2572 return;
2575 if (targs != null) {
2576 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2577 if (retval != null) {
2578 Namespace.Error_TypeArgumentsCannotBeUsed (retval, loc);
2579 return;
2583 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2586 // TODO: I am still not convinced about this. If someone else will need it
2587 // implement this as virtual property in MemberCore hierarchy
2588 public static string GetMemberType (MemberCore mc)
2590 if (mc is Property)
2591 return "property";
2592 if (mc is Indexer)
2593 return "indexer";
2594 if (mc is FieldBase)
2595 return "field";
2596 if (mc is MethodCore)
2597 return "method";
2598 if (mc is EnumMember)
2599 return "enum";
2600 if (mc is Event)
2601 return "event";
2603 return "type";
2606 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2608 if (in_transit)
2609 return null;
2611 in_transit = true;
2612 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2613 in_transit = false;
2615 if (e == null)
2616 return null;
2618 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2619 return e;
2621 return null;
2624 /// <remarks>
2625 /// 7.5.2: Simple Names.
2627 /// Local Variables and Parameters are handled at
2628 /// parse time, so they never occur as SimpleNames.
2630 /// The `intermediate' flag is used by MemberAccess only
2631 /// and it is used to inform us that it is ok for us to
2632 /// avoid the static check, because MemberAccess might end
2633 /// up resolving the Name as a Type name and the access as
2634 /// a static type access.
2636 /// ie: Type Type; .... { Type.GetType (""); }
2638 /// Type is both an instance variable and a Type; Type.GetType
2639 /// is the static method not an instance method of type.
2640 /// </remarks>
2641 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2643 Expression e = null;
2646 // Stage 1: Performed by the parser (binding to locals or parameters).
2648 Block current_block = ec.CurrentBlock;
2649 if (current_block != null){
2650 LocalInfo vi = current_block.GetLocalInfo (Name);
2651 if (vi != null){
2652 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2653 if (right_side != null) {
2654 return var.ResolveLValue (ec, right_side);
2655 } else {
2656 ResolveFlags rf = ResolveFlags.VariableOrValue;
2657 if (intermediate)
2658 rf |= ResolveFlags.DisableFlowAnalysis;
2659 return var.Resolve (ec, rf);
2663 Expression expr = current_block.Toplevel.GetParameterReference (Name, loc);
2664 if (expr != null) {
2665 if (right_side != null)
2666 return expr.ResolveLValue (ec, right_side);
2668 return expr.Resolve (ec);
2673 // Stage 2: Lookup members
2676 Type almost_matched_type = null;
2677 ArrayList almost_matched = null;
2678 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2679 // either RootDeclSpace or GenericMethod
2680 if (lookup_ds.TypeBuilder == null)
2681 continue;
2683 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2684 if (e != null) {
2685 PropertyExpr pe = e as PropertyExpr;
2686 if (pe != null) {
2687 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2689 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2690 // it doesn't know which accessor to check permissions against
2691 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2692 break;
2693 } else if (e is EventExpr) {
2694 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2695 break;
2696 } else if (targs != null && e is TypeExpression) {
2697 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2698 break;
2699 } else {
2700 break;
2702 e = null;
2705 if (almost_matched == null && almost_matched_members.Count > 0) {
2706 almost_matched_type = lookup_ds.TypeBuilder;
2707 almost_matched = (ArrayList) almost_matched_members.Clone ();
2711 if (e == null) {
2712 if (almost_matched == null && almost_matched_members.Count > 0) {
2713 almost_matched_type = ec.ContainerType;
2714 almost_matched = (ArrayList) almost_matched_members.Clone ();
2716 e = ResolveAsTypeStep (ec, true);
2719 if (e == null) {
2720 if (current_block != null) {
2721 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2722 if (ikv != null) {
2723 LocalInfo li = ikv as LocalInfo;
2724 // Supress CS0219 warning
2725 if (li != null)
2726 li.Used = true;
2728 Error_VariableIsUsedBeforeItIsDeclared (Name);
2729 return null;
2733 if (RootContext.EvalMode){
2734 FieldInfo fi = Evaluator.LookupField (Name);
2735 if (fi != null)
2736 return new FieldExpr (fi, loc).Resolve (ec);
2739 if (almost_matched != null)
2740 almost_matched_members = almost_matched;
2741 if (almost_matched_type == null)
2742 almost_matched_type = ec.ContainerType;
2743 return Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2744 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2747 if (e is MemberExpr) {
2748 MemberExpr me = (MemberExpr) e;
2750 Expression left;
2751 if (me.IsInstance) {
2752 if (ec.IsStatic || ec.IsInFieldInitializer) {
2754 // Note that an MemberExpr can be both IsInstance and IsStatic.
2755 // An unresolved MethodGroupExpr can contain both kinds of methods
2756 // and each predicate is true if the MethodGroupExpr contains
2757 // at least one of that kind of method.
2760 if (!me.IsStatic &&
2761 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2762 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2763 return null;
2767 // Pass the buck to MemberAccess and Invocation.
2769 left = EmptyExpression.Null;
2770 } else {
2771 left = ec.GetThis (loc);
2773 } else {
2774 left = new TypeExpression (ec.ContainerType, loc);
2777 me = me.ResolveMemberAccess (ec, left, loc, null);
2778 if (me == null)
2779 return null;
2781 if (targs != null) {
2782 if (!targs.Resolve (ec))
2783 return null;
2785 me.SetTypeArguments (targs);
2788 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2789 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2790 me.InstanceExpression.Type != me.DeclaringType &&
2791 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2792 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2793 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2794 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2795 return null;
2798 return (right_side != null)
2799 ? me.DoResolveLValue (ec, right_side)
2800 : me.DoResolve (ec);
2803 return e;
2807 /// <summary>
2808 /// Represents a namespace or a type. The name of the class was inspired by
2809 /// section 10.8.1 (Fully Qualified Names).
2810 /// </summary>
2811 public abstract class FullNamedExpression : Expression
2813 protected override void CloneTo (CloneContext clonectx, Expression target)
2815 // Do nothing, most unresolved type expressions cannot be
2816 // resolved to different type
2819 public override Expression CreateExpressionTree (EmitContext ec)
2821 throw new NotSupportedException ("ET");
2824 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2826 throw new NotSupportedException ();
2829 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2831 return this;
2834 public override void Emit (EmitContext ec)
2836 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2837 GetSignatureForError ());
2841 /// <summary>
2842 /// Expression that evaluates to a type
2843 /// </summary>
2844 public abstract class TypeExpr : FullNamedExpression {
2845 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2847 TypeExpr t = DoResolveAsTypeStep (ec);
2848 if (t == null)
2849 return null;
2851 eclass = ExprClass.Type;
2852 return t;
2855 override public Expression DoResolve (EmitContext ec)
2857 return ResolveAsTypeTerminal (ec, false);
2860 public virtual bool CheckAccessLevel (DeclSpace ds)
2862 return ds.CheckAccessLevel (Type);
2865 public virtual bool IsClass {
2866 get { return Type.IsClass; }
2869 public virtual bool IsValueType {
2870 get { return TypeManager.IsStruct (Type); }
2873 public virtual bool IsInterface {
2874 get { return Type.IsInterface; }
2877 public virtual bool IsSealed {
2878 get { return Type.IsSealed; }
2881 public virtual bool CanInheritFrom ()
2883 if (Type == TypeManager.enum_type ||
2884 (Type == TypeManager.value_type && RootContext.StdLib) ||
2885 Type == TypeManager.multicast_delegate_type ||
2886 Type == TypeManager.delegate_type ||
2887 Type == TypeManager.array_type)
2888 return false;
2890 return true;
2893 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2895 public override bool Equals (object obj)
2897 TypeExpr tobj = obj as TypeExpr;
2898 if (tobj == null)
2899 return false;
2901 return Type == tobj.Type;
2904 public override int GetHashCode ()
2906 return Type.GetHashCode ();
2909 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2911 type = storey.MutateType (type);
2915 /// <summary>
2916 /// Fully resolved Expression that already evaluated to a type
2917 /// </summary>
2918 public class TypeExpression : TypeExpr {
2919 public TypeExpression (Type t, Location l)
2921 Type = t;
2922 eclass = ExprClass.Type;
2923 loc = l;
2926 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2928 return this;
2931 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2933 return this;
2938 // Used to create types from a fully qualified name. These are just used
2939 // by the parser to setup the core types.
2941 public sealed class TypeLookupExpression : TypeExpr {
2942 readonly string ns_name;
2943 readonly string name;
2945 public TypeLookupExpression (string ns, string name)
2947 this.name = name;
2948 this.ns_name = ns;
2949 eclass = ExprClass.Type;
2952 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2955 // It's null only during mscorlib bootstrap when DefineType
2956 // nees to resolve base type of same type
2958 // For instance struct Char : IComparable<char>
2960 // TODO: it could be removed when Resolve starts to use
2961 // DeclSpace instead of Type
2963 if (type == null) {
2964 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
2965 FullNamedExpression fne = ns.Lookup (null, name, loc);
2966 if (fne != null)
2967 type = fne.Type;
2970 return this;
2973 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2975 return this;
2978 public override string GetSignatureForError ()
2980 if (type == null)
2981 return TypeManager.CSharpName (ns_name + "." + name, null);
2983 return base.GetSignatureForError ();
2987 /// <summary>
2988 /// This class denotes an expression which evaluates to a member
2989 /// of a struct or a class.
2990 /// </summary>
2991 public abstract class MemberExpr : Expression
2993 protected bool is_base;
2995 /// <summary>
2996 /// The name of this member.
2997 /// </summary>
2998 public abstract string Name {
2999 get;
3003 // When base.member is used
3005 public bool IsBase {
3006 get { return is_base; }
3007 set { is_base = value; }
3010 /// <summary>
3011 /// Whether this is an instance member.
3012 /// </summary>
3013 public abstract bool IsInstance {
3014 get;
3017 /// <summary>
3018 /// Whether this is a static member.
3019 /// </summary>
3020 public abstract bool IsStatic {
3021 get;
3024 /// <summary>
3025 /// The type which declares this member.
3026 /// </summary>
3027 public abstract Type DeclaringType {
3028 get;
3031 /// <summary>
3032 /// The instance expression associated with this member, if it's a
3033 /// non-static member.
3034 /// </summary>
3035 public Expression InstanceExpression;
3037 public static void error176 (Location loc, string name)
3039 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3040 "with an instance reference, qualify it with a type name instead", name);
3043 public static void Error_BaseAccessInExpressionTree (Location loc)
3045 Report.Error (831, loc, "An expression tree may not contain a base access");
3048 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3050 if (InstanceExpression != null)
3051 InstanceExpression.MutateHoistedGenericType (storey);
3054 // TODO: possible optimalization
3055 // Cache resolved constant result in FieldBuilder <-> expression map
3056 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3057 SimpleName original)
3060 // Precondition:
3061 // original == null || original.Resolve (...) ==> left
3064 if (left is TypeExpr) {
3065 left = left.ResolveAsBaseTerminal (ec, false);
3066 if (left == null)
3067 return null;
3069 // TODO: Same problem as in class.cs, TypeTerminal does not
3070 // always do all necessary checks
3071 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3072 if (oa != null && !ec.IsInObsoleteScope) {
3073 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3076 GenericTypeExpr ct = left as GenericTypeExpr;
3077 if (ct != null && !ct.CheckConstraints (ec))
3078 return null;
3081 if (!IsStatic) {
3082 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3083 return null;
3086 return this;
3089 if (!IsInstance) {
3090 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3091 return this;
3093 return ResolveExtensionMemberAccess (left);
3096 InstanceExpression = left;
3097 return this;
3100 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3102 error176 (loc, GetSignatureForError ());
3103 return this;
3106 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3108 if (IsStatic)
3109 return;
3111 if (InstanceExpression == EmptyExpression.Null) {
3112 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3113 return;
3116 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3117 if (InstanceExpression is IMemoryLocation) {
3118 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3119 } else {
3120 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3121 InstanceExpression.Emit (ec);
3122 t.Store (ec);
3123 t.AddressOf (ec, AddressOp.Store);
3125 } else
3126 InstanceExpression.Emit (ec);
3128 if (prepare_for_load)
3129 ec.ig.Emit (OpCodes.Dup);
3132 public virtual void SetTypeArguments (TypeArguments ta)
3134 // TODO: need to get correct member type
3135 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3136 GetSignatureForError ());
3140 ///
3141 /// Represents group of extension methods
3142 ///
3143 public class ExtensionMethodGroupExpr : MethodGroupExpr
3145 readonly NamespaceEntry namespace_entry;
3146 public Expression ExtensionExpression;
3147 Argument extension_argument;
3149 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3150 : base (list, extensionType, l)
3152 this.namespace_entry = n;
3155 public override bool IsStatic {
3156 get { return true; }
3159 public bool IsTopLevel {
3160 get { return namespace_entry == null; }
3163 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3165 extension_argument.Expr.MutateHoistedGenericType (storey);
3166 base.MutateHoistedGenericType (storey);
3169 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref Arguments arguments, bool may_fail, Location loc)
3171 if (arguments == null)
3172 arguments = new Arguments (1);
3174 arguments.Insert (0, new Argument (ExtensionExpression));
3175 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3177 // Store resolved argument and restore original arguments
3178 if (mg != null)
3179 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3180 else
3181 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3183 return mg;
3186 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3188 // Use normal resolve rules
3189 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3190 if (mg != null)
3191 return mg;
3193 if (ns == null)
3194 return null;
3196 // Search continues
3197 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3198 if (e == null)
3199 return base.OverloadResolve (ec, ref arguments, false, loc);
3201 e.ExtensionExpression = ExtensionExpression;
3202 e.SetTypeArguments (type_arguments);
3203 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3207 /// <summary>
3208 /// MethodGroupExpr represents a group of method candidates which
3209 /// can be resolved to the best method overload
3210 /// </summary>
3211 public class MethodGroupExpr : MemberExpr
3213 public interface IErrorHandler
3215 bool AmbiguousCall (MethodBase ambiguous);
3216 bool NoExactMatch (EmitContext ec, MethodBase method);
3219 public IErrorHandler CustomErrorHandler;
3220 public MethodBase [] Methods;
3221 MethodBase best_candidate;
3222 // TODO: make private
3223 public TypeArguments type_arguments;
3224 bool identical_type_name;
3225 bool has_inaccessible_candidates_only;
3226 Type delegate_type;
3227 Type queried_type;
3229 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3230 : this (type, l)
3232 Methods = new MethodBase [mi.Length];
3233 mi.CopyTo (Methods, 0);
3236 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3237 : this (mi, type, l)
3239 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3242 public MethodGroupExpr (ArrayList list, Type type, Location l)
3243 : this (type, l)
3245 try {
3246 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3247 } catch {
3248 foreach (MemberInfo m in list){
3249 if (!(m is MethodBase)){
3250 Console.WriteLine ("Name " + m.Name);
3251 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3254 throw;
3260 protected MethodGroupExpr (Type type, Location loc)
3262 this.loc = loc;
3263 eclass = ExprClass.MethodGroup;
3264 this.type = InternalType.MethodGroup;
3265 queried_type = type;
3268 public override Type DeclaringType {
3269 get {
3270 return queried_type;
3274 public Type DelegateType {
3275 set {
3276 delegate_type = value;
3280 public bool IdenticalTypeName {
3281 get {
3282 return identical_type_name;
3286 public override string GetSignatureForError ()
3288 if (best_candidate != null)
3289 return TypeManager.CSharpSignature (best_candidate);
3291 return TypeManager.CSharpSignature (Methods [0]);
3294 public override string Name {
3295 get {
3296 return Methods [0].Name;
3300 public override bool IsInstance {
3301 get {
3302 if (best_candidate != null)
3303 return !best_candidate.IsStatic;
3305 foreach (MethodBase mb in Methods)
3306 if (!mb.IsStatic)
3307 return true;
3309 return false;
3313 public override bool IsStatic {
3314 get {
3315 if (best_candidate != null)
3316 return best_candidate.IsStatic;
3318 foreach (MethodBase mb in Methods)
3319 if (mb.IsStatic)
3320 return true;
3322 return false;
3326 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3328 return (ConstructorInfo)mg.best_candidate;
3331 public static explicit operator MethodInfo (MethodGroupExpr mg)
3333 return (MethodInfo)mg.best_candidate;
3337 // 7.4.3.3 Better conversion from expression
3338 // Returns : 1 if a->p is better,
3339 // 2 if a->q is better,
3340 // 0 if neither is better
3342 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3344 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3345 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3347 // Uwrap delegate from Expression<T>
3349 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3350 p = TypeManager.GetTypeArguments (p) [0];
3352 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3353 q = TypeManager.GetTypeArguments (q) [0];
3356 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3357 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3358 if (p == TypeManager.void_type && q != TypeManager.void_type)
3359 return 2;
3360 if (q == TypeManager.void_type && p != TypeManager.void_type)
3361 return 1;
3362 } else {
3363 if (argument_type == p)
3364 return 1;
3366 if (argument_type == q)
3367 return 2;
3370 return BetterTypeConversion (ec, p, q);
3374 // 7.4.3.4 Better conversion from type
3376 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3378 if (p == null || q == null)
3379 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3381 if (p == TypeManager.int32_type) {
3382 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3383 return 1;
3384 } else if (p == TypeManager.int64_type) {
3385 if (q == TypeManager.uint64_type)
3386 return 1;
3387 } else if (p == TypeManager.sbyte_type) {
3388 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3389 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3390 return 1;
3391 } else if (p == TypeManager.short_type) {
3392 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3393 q == TypeManager.uint64_type)
3394 return 1;
3397 if (q == TypeManager.int32_type) {
3398 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3399 return 2;
3400 } if (q == TypeManager.int64_type) {
3401 if (p == TypeManager.uint64_type)
3402 return 2;
3403 } else if (q == TypeManager.sbyte_type) {
3404 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3405 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3406 return 2;
3407 } if (q == TypeManager.short_type) {
3408 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3409 p == TypeManager.uint64_type)
3410 return 2;
3413 // TODO: this is expensive
3414 Expression p_tmp = new EmptyExpression (p);
3415 Expression q_tmp = new EmptyExpression (q);
3417 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3418 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3420 if (p_to_q && !q_to_p)
3421 return 1;
3423 if (q_to_p && !p_to_q)
3424 return 2;
3426 return 0;
3429 /// <summary>
3430 /// Determines "Better function" between candidate
3431 /// and the current best match
3432 /// </summary>
3433 /// <remarks>
3434 /// Returns a boolean indicating :
3435 /// false if candidate ain't better
3436 /// true if candidate is better than the current best match
3437 /// </remarks>
3438 static bool BetterFunction (EmitContext ec, Arguments args, int argument_count,
3439 MethodBase candidate, bool candidate_params,
3440 MethodBase best, bool best_params)
3442 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3443 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3445 bool better_at_least_one = false;
3446 bool same = true;
3447 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3449 Argument a = args [j];
3451 // Provided default argument value is never better
3452 if (a.IsDefaultArgument && candidate_params == best_params)
3453 return false;
3455 Type ct = candidate_pd.Types [c_idx];
3456 Type bt = best_pd.Types [b_idx];
3458 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3460 ct = TypeManager.GetElementType (ct);
3461 --c_idx;
3464 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3466 bt = TypeManager.GetElementType (bt);
3467 --b_idx;
3470 if (ct.Equals (bt))
3471 continue;
3473 same = false;
3474 int result = BetterExpressionConversion (ec, a, ct, bt);
3476 // for each argument, the conversion to 'ct' should be no worse than
3477 // the conversion to 'bt'.
3478 if (result == 2)
3479 return false;
3481 // for at least one argument, the conversion to 'ct' should be better than
3482 // the conversion to 'bt'.
3483 if (result != 0)
3484 better_at_least_one = true;
3487 if (better_at_least_one)
3488 return true;
3491 // This handles the case
3493 // Add (float f1, float f2, float f3);
3494 // Add (params decimal [] foo);
3496 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3497 // first candidate would've chosen as better.
3499 if (!same)
3500 return false;
3503 // The two methods have equal parameter types. Now apply tie-breaking rules
3505 if (TypeManager.IsGenericMethod (best)) {
3506 if (!TypeManager.IsGenericMethod (candidate))
3507 return true;
3508 } else if (TypeManager.IsGenericMethod (candidate)) {
3509 return false;
3513 // This handles the following cases:
3515 // Trim () is better than Trim (params char[] chars)
3516 // Concat (string s1, string s2, string s3) is better than
3517 // Concat (string s1, params string [] srest)
3518 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3520 if (!candidate_params && best_params)
3521 return true;
3522 if (candidate_params && !best_params)
3523 return false;
3525 int candidate_param_count = candidate_pd.Count;
3526 int best_param_count = best_pd.Count;
3528 if (candidate_param_count != best_param_count)
3529 // can only happen if (candidate_params && best_params)
3530 return candidate_param_count > best_param_count && best_pd.HasParams;
3533 // now, both methods have the same number of parameters, and the parameters have the same types
3534 // Pick the "more specific" signature
3537 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3538 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3540 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3541 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3543 bool specific_at_least_once = false;
3544 for (int j = 0; j < candidate_param_count; ++j)
3546 Type ct = orig_candidate_pd.Types [j];
3547 Type bt = orig_best_pd.Types [j];
3548 if (ct.Equals (bt))
3549 continue;
3550 Type specific = MoreSpecific (ct, bt);
3551 if (specific == bt)
3552 return false;
3553 if (specific == ct)
3554 specific_at_least_once = true;
3557 if (specific_at_least_once)
3558 return true;
3560 // FIXME: handle lifted operators
3561 // ...
3563 return false;
3566 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3568 if (!IsStatic)
3569 return base.ResolveExtensionMemberAccess (left);
3572 // When left side is an expression and at least one candidate method is
3573 // static, it can be extension method
3575 InstanceExpression = left;
3576 return this;
3579 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3580 SimpleName original)
3582 if (!(left is TypeExpr) &&
3583 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3584 identical_type_name = true;
3586 return base.ResolveMemberAccess (ec, left, loc, original);
3589 public override Expression CreateExpressionTree (EmitContext ec)
3591 if (best_candidate == null) {
3592 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3593 return null;
3596 IMethodData md = TypeManager.GetMethod (best_candidate);
3597 if (md != null && md.IsExcluded ())
3598 Report.Error (765, loc,
3599 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3601 return new TypeOfMethod (best_candidate, loc);
3604 override public Expression DoResolve (EmitContext ec)
3606 if (InstanceExpression != null) {
3607 InstanceExpression = InstanceExpression.DoResolve (ec);
3608 if (InstanceExpression == null)
3609 return null;
3612 return this;
3615 public void ReportUsageError ()
3617 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3618 Name + "()' is referenced without parentheses");
3621 override public void Emit (EmitContext ec)
3623 ReportUsageError ();
3626 public void EmitCall (EmitContext ec, Arguments arguments)
3628 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3631 void Error_AmbiguousCall (MethodBase ambiguous)
3633 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ambiguous))
3634 return;
3636 Report.SymbolRelatedToPreviousError (best_candidate);
3637 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3638 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3641 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3642 Argument a, AParametersCollection expected_par, Type paramType)
3644 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3646 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3647 Report.SymbolRelatedToPreviousError (method);
3648 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3649 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3650 TypeManager.CSharpSignature (method));
3651 return;
3653 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3654 TypeManager.CSharpSignature (method));
3655 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3656 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3657 TypeManager.CSharpName (method.DeclaringType));
3658 } else {
3659 Report.SymbolRelatedToPreviousError (method);
3660 if (emg != null) {
3661 Report.Error (1928, loc,
3662 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3663 emg.ExtensionExpression.GetSignatureForError (),
3664 emg.Name, TypeManager.CSharpSignature (method));
3665 } else {
3666 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3667 TypeManager.CSharpSignature (method));
3671 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3673 string index = (idx + 1).ToString ();
3674 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3675 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3676 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3677 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3678 index, Parameter.GetModifierSignature (a.Modifier));
3679 else
3680 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3681 index, Parameter.GetModifierSignature (mod));
3682 } else {
3683 string p1 = a.GetSignatureForError ();
3684 string p2 = TypeManager.CSharpName (paramType);
3686 if (p1 == p2) {
3687 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3688 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3689 Report.SymbolRelatedToPreviousError (paramType);
3692 if (idx == 0 && emg != null) {
3693 Report.Error (1929, loc,
3694 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3695 } else {
3696 Report.Error (1503, loc,
3697 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3702 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3704 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3705 Name, TypeManager.CSharpName (target));
3708 void Error_ArgumentCountWrong (int arg_count)
3710 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3711 Name, arg_count.ToString ());
3714 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3716 return parameters.Count;
3719 public static bool IsAncestralType (Type first_type, Type second_type)
3721 return first_type != second_type &&
3722 (TypeManager.IsSubclassOf (second_type, first_type) ||
3723 TypeManager.ImplementsInterface (second_type, first_type));
3727 /// Determines if the candidate method is applicable (section 14.4.2.1)
3728 /// to the given set of arguments
3729 /// A return value rates candidate method compatibility,
3730 /// 0 = the best, int.MaxValue = the worst
3732 public int IsApplicable (EmitContext ec,
3733 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3735 MethodBase candidate = method;
3737 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3738 int param_count = GetApplicableParametersCount (candidate, pd);
3739 int optional_count = 0;
3741 if (arg_count != param_count) {
3742 for (int i = 0; i < pd.Count; ++i) {
3743 if (pd.FixedParameters [i].HasDefaultValue) {
3744 optional_count = pd.Count - i;
3745 break;
3749 int args_gap = Math.Abs (arg_count - param_count);
3750 if (optional_count != 0) {
3751 if (args_gap > optional_count)
3752 return int.MaxValue - 10000 + args_gap - optional_count;
3754 // Readjust expected number when params used
3755 if (pd.HasParams) {
3756 optional_count--;
3757 if (arg_count < param_count)
3758 param_count--;
3760 } else if (arg_count != param_count) {
3761 if (!pd.HasParams)
3762 return int.MaxValue - 10000 + args_gap;
3763 if (arg_count < param_count - 1)
3764 return int.MaxValue - 10000 + args_gap;
3767 // Initialize expanded form of a method with 1 params parameter
3768 params_expanded_form = param_count == 1 && pd.HasParams;
3770 // Resize to fit optional arguments
3771 if (optional_count != 0) {
3772 Arguments resized;
3773 if (arguments == null) {
3774 resized = new Arguments (optional_count);
3775 } else {
3776 resized = new Arguments (param_count);
3777 resized.AddRange (arguments);
3780 for (int i = arg_count; i < param_count; ++i)
3781 resized.Add (null);
3782 arguments = resized;
3786 if (arg_count > 0) {
3788 // Shuffle named arguments to the right positions if there are any
3790 if (arguments [arg_count - 1] is NamedArgument) {
3791 arg_count = arguments.Count;
3793 for (int i = 0; i < arg_count; ++i) {
3794 bool arg_moved = false;
3795 while (true) {
3796 NamedArgument na = arguments[i] as NamedArgument;
3797 if (na == null)
3798 break;
3800 int index = pd.GetParameterIndexByName (na.Name.Value);
3802 // Named parameter not found or already reordered
3803 if (index <= i)
3804 break;
3806 // When using parameters which should not be available to the user
3807 if (index >= param_count)
3808 break;
3810 if (!arg_moved) {
3811 arguments.MarkReorderedArgument (na);
3812 arg_moved = true;
3815 Argument temp = arguments[index];
3816 arguments[index] = arguments[i];
3817 arguments[i] = temp;
3819 if (temp == null)
3820 break;
3823 } else {
3824 arg_count = arguments.Count;
3826 } else if (arguments != null) {
3827 arg_count = arguments.Count;
3830 #if GMCS_SOURCE
3832 // 1. Handle generic method using type arguments when specified or type inference
3834 if (TypeManager.IsGenericMethod (candidate)) {
3835 if (type_arguments != null) {
3836 Type [] g_args = candidate.GetGenericArguments ();
3837 if (g_args.Length != type_arguments.Count)
3838 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3840 // TODO: Don't create new method, create Parameters only
3841 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3842 candidate = method;
3843 pd = TypeManager.GetParameterData (candidate);
3844 } else {
3845 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3846 if (score != 0)
3847 return score - 20000;
3849 if (TypeManager.IsGenericMethodDefinition (candidate))
3850 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3851 TypeManager.CSharpSignature (candidate));
3853 pd = TypeManager.GetParameterData (candidate);
3855 } else {
3856 if (type_arguments != null)
3857 return int.MaxValue - 15000;
3859 #endif
3862 // 2. Each argument has to be implicitly convertible to method parameter
3864 method = candidate;
3865 Parameter.Modifier p_mod = 0;
3866 Type pt = null;
3867 for (int i = 0; i < arg_count; i++) {
3868 Argument a = arguments [i];
3869 if (a == null) {
3870 if (!pd.FixedParameters [i].HasDefaultValue)
3871 throw new InternalErrorException ();
3873 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3874 if (e == null)
3875 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3877 arguments [i] = new Argument (e, Argument.AType.Default);
3878 continue;
3881 if (p_mod != Parameter.Modifier.PARAMS) {
3882 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3883 pt = pd.Types [i];
3884 } else {
3885 params_expanded_form = true;
3888 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3889 int score = 1;
3890 if (!params_expanded_form)
3891 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3893 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3894 // It can be applicable in expanded form
3895 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3896 if (score == 0)
3897 params_expanded_form = true;
3900 if (score != 0) {
3901 if (params_expanded_form)
3902 ++score;
3903 return (arg_count - i) * 2 + score;
3907 if (arg_count != param_count)
3908 params_expanded_form = true;
3910 return 0;
3913 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3916 // Types have to be identical when ref or out modifer is used
3918 if (arg_mod != 0 || param_mod != 0) {
3919 if (TypeManager.HasElementType (parameter))
3920 parameter = TypeManager.GetElementType (parameter);
3922 Type a_type = argument.Type;
3923 if (TypeManager.HasElementType (a_type))
3924 a_type = TypeManager.GetElementType (a_type);
3926 if (a_type != parameter)
3927 return 2;
3928 } else {
3929 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3930 return 2;
3933 if (arg_mod != param_mod)
3934 return 1;
3936 return 0;
3939 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3941 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3942 return false;
3944 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3945 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3947 if (cand_pd.Count != base_pd.Count)
3948 return false;
3950 for (int j = 0; j < cand_pd.Count; ++j)
3952 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3953 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3954 Type ct = cand_pd.Types [j];
3955 Type bt = base_pd.Types [j];
3957 if (cm != bm || ct != bt)
3958 return false;
3961 return true;
3964 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
3966 if (mg1 == null) {
3967 if (mg2 == null)
3968 return null;
3969 return mg2;
3972 if (mg2 == null)
3973 return mg1;
3975 ArrayList all = new ArrayList (mg1.Methods);
3976 foreach (MethodBase m in mg2.Methods){
3977 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
3978 all.Add (m);
3981 return new MethodGroupExpr (all, null, loc);
3984 static Type MoreSpecific (Type p, Type q)
3986 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3987 return q;
3988 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3989 return p;
3991 if (TypeManager.HasElementType (p))
3993 Type pe = TypeManager.GetElementType (p);
3994 Type qe = TypeManager.GetElementType (q);
3995 Type specific = MoreSpecific (pe, qe);
3996 if (specific == pe)
3997 return p;
3998 if (specific == qe)
3999 return q;
4001 else if (TypeManager.IsGenericType (p))
4003 Type[] pargs = TypeManager.GetTypeArguments (p);
4004 Type[] qargs = TypeManager.GetTypeArguments (q);
4006 bool p_specific_at_least_once = false;
4007 bool q_specific_at_least_once = false;
4009 for (int i = 0; i < pargs.Length; i++)
4011 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4012 if (specific == pargs [i])
4013 p_specific_at_least_once = true;
4014 if (specific == qargs [i])
4015 q_specific_at_least_once = true;
4018 if (p_specific_at_least_once && !q_specific_at_least_once)
4019 return p;
4020 if (!p_specific_at_least_once && q_specific_at_least_once)
4021 return q;
4024 return null;
4027 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4029 base.MutateHoistedGenericType (storey);
4031 MethodInfo mi = best_candidate as MethodInfo;
4032 if (mi != null) {
4033 best_candidate = storey.MutateGenericMethod (mi);
4034 return;
4037 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4040 /// <summary>
4041 /// Find the Applicable Function Members (7.4.2.1)
4043 /// me: Method Group expression with the members to select.
4044 /// it might contain constructors or methods (or anything
4045 /// that maps to a method).
4047 /// Arguments: ArrayList containing resolved Argument objects.
4049 /// loc: The location if we want an error to be reported, or a Null
4050 /// location for "probing" purposes.
4052 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4053 /// that is the best match of me on Arguments.
4055 /// </summary>
4056 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref Arguments Arguments,
4057 bool may_fail, Location loc)
4059 bool method_params = false;
4060 Type applicable_type = null;
4061 ArrayList candidates = new ArrayList (2);
4062 ArrayList candidate_overrides = null;
4065 // Used to keep a map between the candidate
4066 // and whether it is being considered in its
4067 // normal or expanded form
4069 // false is normal form, true is expanded form
4071 Hashtable candidate_to_form = null;
4072 Hashtable candidates_expanded = null;
4073 Arguments candidate_args = Arguments;
4075 int arg_count = Arguments != null ? Arguments.Count : 0;
4077 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4078 if (!may_fail)
4079 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4080 return null;
4083 int nmethods = Methods.Length;
4085 if (!IsBase) {
4087 // Methods marked 'override' don't take part in 'applicable_type'
4088 // computation, nor in the actual overload resolution.
4089 // However, they still need to be emitted instead of a base virtual method.
4090 // So, we salt them away into the 'candidate_overrides' array.
4092 // In case of reflected methods, we replace each overriding method with
4093 // its corresponding base virtual method. This is to improve compatibility
4094 // with non-C# libraries which change the visibility of overrides (#75636)
4096 int j = 0;
4097 for (int i = 0; i < Methods.Length; ++i) {
4098 MethodBase m = Methods [i];
4099 if (TypeManager.IsOverride (m)) {
4100 if (candidate_overrides == null)
4101 candidate_overrides = new ArrayList ();
4102 candidate_overrides.Add (m);
4103 m = TypeManager.TryGetBaseDefinition (m);
4105 if (m != null)
4106 Methods [j++] = m;
4108 nmethods = j;
4112 // Enable message recording, it's used mainly by lambda expressions
4114 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4115 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4118 // First we construct the set of applicable methods
4120 bool is_sorted = true;
4121 int best_candidate_rate = int.MaxValue;
4122 for (int i = 0; i < nmethods; i++) {
4123 Type decl_type = Methods [i].DeclaringType;
4126 // If we have already found an applicable method
4127 // we eliminate all base types (Section 14.5.5.1)
4129 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4130 continue;
4133 // Check if candidate is applicable (section 14.4.2.1)
4135 bool params_expanded_form = false;
4136 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4138 if (candidate_rate < best_candidate_rate) {
4139 best_candidate_rate = candidate_rate;
4140 best_candidate = Methods [i];
4143 if (params_expanded_form) {
4144 if (candidate_to_form == null)
4145 candidate_to_form = new PtrHashtable ();
4146 MethodBase candidate = Methods [i];
4147 candidate_to_form [candidate] = candidate;
4150 if (candidate_args != Arguments) {
4151 if (candidates_expanded == null)
4152 candidates_expanded = new Hashtable (2);
4154 candidates_expanded.Add (Methods [i], candidate_args);
4155 candidate_args = Arguments;
4158 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4159 if (msg_recorder != null)
4160 msg_recorder.EndSession ();
4161 continue;
4164 msg_recorder = null;
4165 candidates.Add (Methods [i]);
4167 if (applicable_type == null)
4168 applicable_type = decl_type;
4169 else if (applicable_type != decl_type) {
4170 is_sorted = false;
4171 if (IsAncestralType (applicable_type, decl_type))
4172 applicable_type = decl_type;
4176 Report.SetMessageRecorder (prev_recorder);
4177 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4178 if (!may_fail)
4179 msg_recorder.PrintMessages ();
4181 return null;
4184 int candidate_top = candidates.Count;
4186 if (applicable_type == null) {
4188 // When we found a top level method which does not match and it's
4189 // not an extension method. We start extension methods lookup from here
4191 if (InstanceExpression != null) {
4192 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4193 if (ex_method_lookup != null) {
4194 ex_method_lookup.ExtensionExpression = InstanceExpression;
4195 ex_method_lookup.SetTypeArguments (type_arguments);
4196 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4200 if (may_fail)
4201 return null;
4204 // Okay so we have failed to find exact match so we
4205 // return error info about the closest match
4207 if (best_candidate != null) {
4208 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4209 return null;
4211 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4212 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4213 if (arg_count == pd.Count || pd.HasParams) {
4214 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4215 if (type_arguments == null) {
4216 Report.Error (411, loc,
4217 "The type arguments for method `{0}' cannot be inferred from " +
4218 "the usage. Try specifying the type arguments explicitly",
4219 TypeManager.CSharpSignature (best_candidate));
4220 return null;
4223 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4224 if (type_arguments.Count != g_args.Length) {
4225 Report.SymbolRelatedToPreviousError (best_candidate);
4226 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4227 TypeManager.CSharpSignature (best_candidate),
4228 g_args.Length.ToString ());
4229 return null;
4231 } else {
4232 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4233 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4234 return null;
4238 if (has_inaccessible_candidates_only) {
4239 if (InstanceExpression != null && type != ec.ContainerType && TypeManager.IsNestedFamilyAccessible (ec.ContainerType, best_candidate.DeclaringType)) {
4240 // Although a derived class can access protected members of
4241 // its base class it cannot do so through an instance of the
4242 // base class (CS1540). If the qualifier_type is a base of the
4243 // ec.ContainerType and the lookup succeeds with the latter one,
4244 // then we are in this situation.
4245 Error_CannotAccessProtected (loc, best_candidate, queried_type, ec.ContainerType);
4246 } else {
4247 Report.SymbolRelatedToPreviousError (best_candidate);
4248 ErrorIsInaccesible (loc, GetSignatureForError ());
4252 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4253 return null;
4255 if (has_inaccessible_candidates_only)
4256 return null;
4258 throw new InternalErrorException ("VerifyArgumentsCompat didn't find any problem with rejected candidate " + best_candidate);
4263 // We failed to find any method with correct argument count
4265 if (Name == ConstructorInfo.ConstructorName) {
4266 Report.SymbolRelatedToPreviousError (queried_type);
4267 Report.Error (1729, loc,
4268 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4269 TypeManager.CSharpName (queried_type), arg_count);
4270 } else {
4271 Error_ArgumentCountWrong (arg_count);
4274 return null;
4277 if (!is_sorted) {
4279 // At this point, applicable_type is _one_ of the most derived types
4280 // in the set of types containing the methods in this MethodGroup.
4281 // Filter the candidates so that they only contain methods from the
4282 // most derived types.
4285 int finalized = 0; // Number of finalized candidates
4287 do {
4288 // Invariant: applicable_type is a most derived type
4290 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4291 // eliminating all it's base types. At the same time, we'll also move
4292 // every unrelated type to the end of the array, and pick the next
4293 // 'applicable_type'.
4295 Type next_applicable_type = null;
4296 int j = finalized; // where to put the next finalized candidate
4297 int k = finalized; // where to put the next undiscarded candidate
4298 for (int i = finalized; i < candidate_top; ++i) {
4299 MethodBase candidate = (MethodBase) candidates [i];
4300 Type decl_type = candidate.DeclaringType;
4302 if (decl_type == applicable_type) {
4303 candidates [k++] = candidates [j];
4304 candidates [j++] = candidates [i];
4305 continue;
4308 if (IsAncestralType (decl_type, applicable_type))
4309 continue;
4311 if (next_applicable_type != null &&
4312 IsAncestralType (decl_type, next_applicable_type))
4313 continue;
4315 candidates [k++] = candidates [i];
4317 if (next_applicable_type == null ||
4318 IsAncestralType (next_applicable_type, decl_type))
4319 next_applicable_type = decl_type;
4322 applicable_type = next_applicable_type;
4323 finalized = j;
4324 candidate_top = k;
4325 } while (applicable_type != null);
4329 // Now we actually find the best method
4332 best_candidate = (MethodBase) candidates [0];
4333 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4336 // TODO: Broken inverse order of candidates logic does not work with optional
4337 // parameters used for method overrides and I am not going to fix it for SRE
4339 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4340 candidate_args = (Arguments) candidates_expanded [best_candidate];
4341 arg_count = candidate_args.Count;
4344 for (int ix = 1; ix < candidate_top; ix++) {
4345 MethodBase candidate = (MethodBase) candidates [ix];
4347 if (candidate == best_candidate)
4348 continue;
4350 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4352 if (BetterFunction (ec, candidate_args, arg_count,
4353 candidate, cand_params,
4354 best_candidate, method_params)) {
4355 best_candidate = candidate;
4356 method_params = cand_params;
4360 // Now check that there are no ambiguities i.e the selected method
4361 // should be better than all the others
4363 MethodBase ambiguous = null;
4364 for (int ix = 1; ix < candidate_top; ix++) {
4365 MethodBase candidate = (MethodBase) candidates [ix];
4367 if (candidate == best_candidate)
4368 continue;
4370 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4371 if (!BetterFunction (ec, candidate_args, arg_count,
4372 best_candidate, method_params,
4373 candidate, cand_params))
4375 if (!may_fail)
4376 Report.SymbolRelatedToPreviousError (candidate);
4377 ambiguous = candidate;
4381 if (ambiguous != null) {
4382 Error_AmbiguousCall (ambiguous);
4383 return this;
4387 // If the method is a virtual function, pick an override closer to the LHS type.
4389 if (!IsBase && best_candidate.IsVirtual) {
4390 if (TypeManager.IsOverride (best_candidate))
4391 throw new InternalErrorException (
4392 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4394 if (candidate_overrides != null) {
4395 Type[] gen_args = null;
4396 bool gen_override = false;
4397 if (TypeManager.IsGenericMethod (best_candidate))
4398 gen_args = TypeManager.GetGenericArguments (best_candidate);
4400 foreach (MethodBase candidate in candidate_overrides) {
4401 if (TypeManager.IsGenericMethod (candidate)) {
4402 if (gen_args == null)
4403 continue;
4405 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4406 continue;
4407 } else {
4408 if (gen_args != null)
4409 continue;
4412 if (IsOverride (candidate, best_candidate)) {
4413 gen_override = true;
4414 best_candidate = candidate;
4418 if (gen_override && gen_args != null) {
4419 #if GMCS_SOURCE
4420 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4421 #endif
4427 // And now check if the arguments are all
4428 // compatible, perform conversions if
4429 // necessary etc. and return if everything is
4430 // all right
4432 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4433 method_params, may_fail, loc))
4434 return null;
4436 if (best_candidate == null)
4437 return null;
4439 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4440 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4441 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4442 return null;
4445 // Check ObsoleteAttribute on the best method
4447 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4448 if (oa != null && !ec.IsInObsoleteScope)
4449 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4451 IMethodData data = TypeManager.GetMethod (the_method);
4452 if (data != null)
4453 data.SetMemberIsUsed ();
4455 Arguments = candidate_args;
4456 return this;
4459 public override void SetTypeArguments (TypeArguments ta)
4461 type_arguments = ta;
4464 public bool VerifyArgumentsCompat (EmitContext ec, ref Arguments arguments,
4465 int arg_count, MethodBase method,
4466 bool chose_params_expanded,
4467 bool may_fail, Location loc)
4469 AParametersCollection pd = TypeManager.GetParameterData (method);
4470 int param_count = GetApplicableParametersCount (method, pd);
4472 int errors = Report.Errors;
4473 Parameter.Modifier p_mod = 0;
4474 Type pt = null;
4475 int a_idx = 0, a_pos = 0;
4476 Argument a = null;
4477 ArrayList params_initializers = null;
4478 bool has_unsafe_arg = false;
4480 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4481 a = arguments [a_idx];
4482 if (p_mod != Parameter.Modifier.PARAMS) {
4483 p_mod = pd.FixedParameters [a_idx].ModFlags;
4484 pt = pd.Types [a_idx];
4485 has_unsafe_arg |= pt.IsPointer;
4487 if (p_mod == Parameter.Modifier.PARAMS) {
4488 if (chose_params_expanded) {
4489 params_initializers = new ArrayList (arg_count - a_idx);
4490 pt = TypeManager.GetElementType (pt);
4496 // Types have to be identical when ref or out modifer is used
4498 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4499 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4500 break;
4502 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4503 break;
4505 continue;
4506 } else {
4507 NamedArgument na = a as NamedArgument;
4508 if (na != null) {
4509 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4510 if (name_index < 0 || name_index >= param_count) {
4511 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4512 Report.SymbolRelatedToPreviousError (DeclaringType);
4513 Report.Error (1746, na.Name.Location,
4514 "The delegate `{0}' does not contain a parameter named `{1}'",
4515 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4516 } else {
4517 Report.SymbolRelatedToPreviousError (best_candidate);
4518 Report.Error (1739, na.Name.Location,
4519 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4520 TypeManager.CSharpSignature (method), na.Name.Value);
4522 } else if (arguments[name_index] != a) {
4523 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4524 Report.SymbolRelatedToPreviousError (DeclaringType);
4525 else
4526 Report.SymbolRelatedToPreviousError (best_candidate);
4528 Report.Error (1744, na.Name.Location,
4529 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4530 na.Name.Value);
4535 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4536 break;
4538 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4539 if (conv == null)
4540 break;
4543 // Convert params arguments to an array initializer
4545 if (params_initializers != null) {
4546 // we choose to use 'a.Expr' rather than 'conv' so that
4547 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4548 params_initializers.Add (a.Expr);
4549 arguments.RemoveAt (a_idx--);
4550 --arg_count;
4551 continue;
4554 // Update the argument with the implicit conversion
4555 a.Expr = conv;
4558 if (a_idx != arg_count) {
4559 if (!may_fail && Report.Errors == errors) {
4560 if (CustomErrorHandler != null)
4561 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4562 else
4563 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4565 return false;
4569 // Fill not provided arguments required by params modifier
4571 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4572 if (arguments == null)
4573 arguments = new Arguments (1);
4575 pt = pd.Types [param_count - 1];
4576 pt = TypeManager.GetElementType (pt);
4577 has_unsafe_arg |= pt.IsPointer;
4578 params_initializers = new ArrayList (0);
4582 // Append an array argument with all params arguments
4584 if (params_initializers != null) {
4585 arguments.Add (new Argument (
4586 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4587 params_initializers, loc).Resolve (ec)));
4588 arg_count++;
4591 if (arg_count < param_count) {
4592 if (!may_fail)
4593 Error_ArgumentCountWrong (arg_count);
4594 return false;
4597 if (has_unsafe_arg && !ec.InUnsafe) {
4598 if (!may_fail)
4599 UnsafeError (loc);
4600 return false;
4603 return true;
4607 public class ConstantExpr : MemberExpr
4609 FieldInfo constant;
4611 public ConstantExpr (FieldInfo constant, Location loc)
4613 this.constant = constant;
4614 this.loc = loc;
4617 public override string Name {
4618 get { throw new NotImplementedException (); }
4621 public override bool IsInstance {
4622 get { return !IsStatic; }
4625 public override bool IsStatic {
4626 get { return constant.IsStatic; }
4629 public override Type DeclaringType {
4630 get { return constant.DeclaringType; }
4633 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4635 constant = TypeManager.GetGenericFieldDefinition (constant);
4637 IConstant ic = TypeManager.GetConstant (constant);
4638 if (ic == null) {
4639 if (constant.IsLiteral) {
4640 ic = new ExternalConstant (constant);
4641 } else {
4642 ic = ExternalConstant.CreateDecimal (constant);
4643 // HACK: decimal field was not resolved as constant
4644 if (ic == null)
4645 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4647 TypeManager.RegisterConstant (constant, ic);
4650 return base.ResolveMemberAccess (ec, left, loc, original);
4653 public override Expression CreateExpressionTree (EmitContext ec)
4655 throw new NotSupportedException ("ET");
4658 public override Expression DoResolve (EmitContext ec)
4660 IConstant ic = TypeManager.GetConstant (constant);
4661 if (ic.ResolveValue ()) {
4662 if (!ec.IsInObsoleteScope)
4663 ic.CheckObsoleteness (loc);
4666 return ic.CreateConstantReference (loc);
4669 public override void Emit (EmitContext ec)
4671 throw new NotSupportedException ();
4674 public override string GetSignatureForError ()
4676 return TypeManager.GetFullNameSignature (constant);
4680 /// <summary>
4681 /// Fully resolved expression that evaluates to a Field
4682 /// </summary>
4683 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4684 public FieldInfo FieldInfo;
4685 readonly Type constructed_generic_type;
4686 VariableInfo variable_info;
4688 LocalTemporary temp;
4689 bool prepared;
4691 protected FieldExpr (Location l)
4693 loc = l;
4696 public FieldExpr (FieldInfo fi, Location l)
4698 FieldInfo = fi;
4699 type = TypeManager.TypeToCoreType (fi.FieldType);
4700 loc = l;
4703 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4704 : this (fi, l)
4706 if (TypeManager.IsGenericTypeDefinition (genericType))
4707 return;
4708 this.constructed_generic_type = genericType;
4711 public override string Name {
4712 get {
4713 return FieldInfo.Name;
4717 public override bool IsInstance {
4718 get {
4719 return !FieldInfo.IsStatic;
4723 public override bool IsStatic {
4724 get {
4725 return FieldInfo.IsStatic;
4729 public override Type DeclaringType {
4730 get {
4731 return FieldInfo.DeclaringType;
4735 public override string GetSignatureForError ()
4737 return TypeManager.GetFullNameSignature (FieldInfo);
4740 public VariableInfo VariableInfo {
4741 get {
4742 return variable_info;
4746 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4747 SimpleName original)
4749 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4750 Type t = fi.FieldType;
4752 if (t.IsPointer && !ec.InUnsafe) {
4753 UnsafeError (loc);
4756 return base.ResolveMemberAccess (ec, left, loc, original);
4759 public void SetHasAddressTaken ()
4761 IVariableReference vr = InstanceExpression as IVariableReference;
4762 if (vr != null)
4763 vr.SetHasAddressTaken ();
4766 public override Expression CreateExpressionTree (EmitContext ec)
4768 Expression instance;
4769 if (InstanceExpression == null) {
4770 instance = new NullLiteral (loc);
4771 } else {
4772 instance = InstanceExpression.CreateExpressionTree (ec);
4775 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4776 instance,
4777 CreateTypeOfExpression ());
4779 return CreateExpressionFactoryCall ("Field", args);
4782 public Expression CreateTypeOfExpression ()
4784 return new TypeOfField (GetConstructedFieldInfo (), loc);
4787 override public Expression DoResolve (EmitContext ec)
4789 return DoResolve (ec, false, false);
4792 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4794 if (!FieldInfo.IsStatic){
4795 if (InstanceExpression == null){
4797 // This can happen when referencing an instance field using
4798 // a fully qualified type expression: TypeName.InstanceField = xxx
4800 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4801 return null;
4804 // Resolve the field's instance expression while flow analysis is turned
4805 // off: when accessing a field "a.b", we must check whether the field
4806 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4808 if (lvalue_instance) {
4809 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4810 Expression right_side =
4811 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4813 if (InstanceExpression != EmptyExpression.Null)
4814 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4816 } else {
4817 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4819 if (InstanceExpression != EmptyExpression.Null)
4820 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4823 if (InstanceExpression == null)
4824 return null;
4826 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4827 InstanceExpression.CheckMarshalByRefAccess (ec);
4831 // TODO: the code above uses some non-standard multi-resolve rules
4832 if (eclass != ExprClass.Invalid)
4833 return this;
4835 if (!ec.IsInObsoleteScope) {
4836 FieldBase f = TypeManager.GetField (FieldInfo);
4837 if (f != null) {
4838 f.CheckObsoleteness (loc);
4839 } else {
4840 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4841 if (oa != null)
4842 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4846 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4847 IVariableReference var = InstanceExpression as IVariableReference;
4849 if (fb != null) {
4850 IFixedExpression fe = InstanceExpression as IFixedExpression;
4851 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4852 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4855 if (InstanceExpression.eclass != ExprClass.Variable) {
4856 Report.SymbolRelatedToPreviousError (FieldInfo);
4857 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4858 TypeManager.GetFullNameSignature (FieldInfo));
4859 } else if (var != null && var.IsHoisted) {
4860 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4863 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4866 eclass = ExprClass.Variable;
4868 // If the instance expression is a local variable or parameter.
4869 if (var == null || var.VariableInfo == null)
4870 return this;
4872 VariableInfo vi = var.VariableInfo;
4873 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4874 return null;
4876 variable_info = vi.GetSubStruct (FieldInfo.Name);
4877 eclass = ExprClass.Variable;
4878 return this;
4881 static readonly int [] codes = {
4882 191, // instance, write access
4883 192, // instance, out access
4884 198, // static, write access
4885 199, // static, out access
4886 1648, // member of value instance, write access
4887 1649, // member of value instance, out access
4888 1650, // member of value static, write access
4889 1651 // member of value static, out access
4892 static readonly string [] msgs = {
4893 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4894 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4895 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4896 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4897 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4898 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4899 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4900 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4903 // The return value is always null. Returning a value simplifies calling code.
4904 Expression Report_AssignToReadonly (Expression right_side)
4906 int i = 0;
4907 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4908 i += 1;
4909 if (IsStatic)
4910 i += 2;
4911 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4912 i += 4;
4913 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4915 return null;
4918 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4920 IVariableReference var = InstanceExpression as IVariableReference;
4921 if (var != null && var.VariableInfo != null)
4922 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4924 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
4925 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4927 Expression e = DoResolve (ec, lvalue_instance, out_access);
4929 if (e == null)
4930 return null;
4932 FieldBase fb = TypeManager.GetField (FieldInfo);
4933 if (fb != null)
4934 fb.SetAssigned ();
4936 if (FieldInfo.IsInitOnly) {
4937 // InitOnly fields can only be assigned in constructors or initializers
4938 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4939 return Report_AssignToReadonly (right_side);
4941 if (ec.IsConstructor) {
4942 Type ctype = ec.TypeContainer.CurrentType;
4943 if (ctype == null)
4944 ctype = ec.ContainerType;
4946 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4947 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4948 return Report_AssignToReadonly (right_side);
4949 // static InitOnly fields cannot be assigned-to in an instance constructor
4950 if (IsStatic && !ec.IsStatic)
4951 return Report_AssignToReadonly (right_side);
4952 // instance constructors can't modify InitOnly fields of other instances of the same type
4953 if (!IsStatic && !(InstanceExpression is This))
4954 return Report_AssignToReadonly (right_side);
4958 if (right_side == EmptyExpression.OutAccess &&
4959 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4960 Report.SymbolRelatedToPreviousError (DeclaringType);
4961 Report.Warning (197, 1, loc,
4962 "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",
4963 GetSignatureForError ());
4966 eclass = ExprClass.Variable;
4967 return this;
4970 bool is_marshal_by_ref ()
4972 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4975 public override void CheckMarshalByRefAccess (EmitContext ec)
4977 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4978 Report.SymbolRelatedToPreviousError (DeclaringType);
4979 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",
4980 GetSignatureForError ());
4984 public override int GetHashCode ()
4986 return FieldInfo.GetHashCode ();
4989 public bool IsFixed {
4990 get {
4992 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4994 IVariableReference variable = InstanceExpression as IVariableReference;
4995 if (variable != null)
4996 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
4998 IFixedExpression fe = InstanceExpression as IFixedExpression;
4999 return fe != null && fe.IsFixed;
5003 public bool IsHoisted {
5004 get {
5005 IVariableReference hv = InstanceExpression as IVariableReference;
5006 return hv != null && hv.IsHoisted;
5010 public override bool Equals (object obj)
5012 FieldExpr fe = obj as FieldExpr;
5013 if (fe == null)
5014 return false;
5016 if (FieldInfo != fe.FieldInfo)
5017 return false;
5019 if (InstanceExpression == null || fe.InstanceExpression == null)
5020 return true;
5022 return InstanceExpression.Equals (fe.InstanceExpression);
5025 public void Emit (EmitContext ec, bool leave_copy)
5027 ILGenerator ig = ec.ig;
5028 bool is_volatile = false;
5030 FieldBase f = TypeManager.GetField (FieldInfo);
5031 if (f != null){
5032 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5033 is_volatile = true;
5035 f.SetMemberIsUsed ();
5038 if (FieldInfo.IsStatic){
5039 if (is_volatile)
5040 ig.Emit (OpCodes.Volatile);
5042 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5043 } else {
5044 if (!prepared)
5045 EmitInstance (ec, false);
5047 // Optimization for build-in types
5048 // TODO: Iterators don't set current container
5049 if (TypeManager.IsStruct (type) && type == ec.DeclContainer.TypeBuilder && ec.CurrentIterator == null) {
5050 LoadFromPtr (ig, type);
5051 } else {
5052 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5053 if (ff != null) {
5054 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5055 ig.Emit (OpCodes.Ldflda, ff.Element);
5056 } else {
5057 if (is_volatile)
5058 ig.Emit (OpCodes.Volatile);
5060 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5065 if (leave_copy) {
5066 ec.ig.Emit (OpCodes.Dup);
5067 if (!FieldInfo.IsStatic) {
5068 temp = new LocalTemporary (this.Type);
5069 temp.Store (ec);
5074 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5076 FieldAttributes fa = FieldInfo.Attributes;
5077 bool is_static = (fa & FieldAttributes.Static) != 0;
5078 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5079 ILGenerator ig = ec.ig;
5081 if (is_readonly && !ec.IsConstructor){
5082 Report_AssignToReadonly (source);
5083 return;
5086 prepared = prepare_for_load;
5087 EmitInstance (ec, prepared);
5089 source.Emit (ec);
5090 if (leave_copy) {
5091 ec.ig.Emit (OpCodes.Dup);
5092 if (!FieldInfo.IsStatic) {
5093 temp = new LocalTemporary (this.Type);
5094 temp.Store (ec);
5098 FieldBase f = TypeManager.GetField (FieldInfo);
5099 if (f != null){
5100 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5101 ig.Emit (OpCodes.Volatile);
5103 f.SetAssigned ();
5106 if (is_static)
5107 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5108 else
5109 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5111 if (temp != null) {
5112 temp.Emit (ec);
5113 temp.Release (ec);
5114 temp = null;
5118 public override void Emit (EmitContext ec)
5120 Emit (ec, false);
5123 public override void EmitSideEffect (EmitContext ec)
5125 FieldBase f = TypeManager.GetField (FieldInfo);
5126 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5128 if (is_volatile || is_marshal_by_ref ())
5129 base.EmitSideEffect (ec);
5132 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5134 Report.Error (844, loc,
5135 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5136 name, GetSignatureForError ());
5139 public void AddressOf (EmitContext ec, AddressOp mode)
5141 ILGenerator ig = ec.ig;
5143 FieldBase f = TypeManager.GetField (FieldInfo);
5144 if (f != null){
5145 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5146 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5147 f.GetSignatureForError ());
5150 if ((mode & AddressOp.Store) != 0)
5151 f.SetAssigned ();
5152 if ((mode & AddressOp.Load) != 0)
5153 f.SetMemberIsUsed ();
5157 // Handle initonly fields specially: make a copy and then
5158 // get the address of the copy.
5160 bool need_copy;
5161 if (FieldInfo.IsInitOnly){
5162 need_copy = true;
5163 if (ec.IsConstructor){
5164 if (FieldInfo.IsStatic){
5165 if (ec.IsStatic)
5166 need_copy = false;
5167 } else
5168 need_copy = false;
5170 } else
5171 need_copy = false;
5173 if (need_copy){
5174 LocalBuilder local;
5175 Emit (ec);
5176 local = ig.DeclareLocal (type);
5177 ig.Emit (OpCodes.Stloc, local);
5178 ig.Emit (OpCodes.Ldloca, local);
5179 return;
5183 if (FieldInfo.IsStatic){
5184 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5185 } else {
5186 if (!prepared)
5187 EmitInstance (ec, false);
5188 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5192 FieldInfo GetConstructedFieldInfo ()
5194 if (constructed_generic_type == null)
5195 return FieldInfo;
5196 #if GMCS_SOURCE
5197 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5198 #else
5199 throw new NotSupportedException ();
5200 #endif
5203 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5205 FieldInfo = storey.MutateField (FieldInfo);
5206 base.MutateHoistedGenericType (storey);
5211 /// <summary>
5212 /// Expression that evaluates to a Property. The Assign class
5213 /// might set the `Value' expression if we are in an assignment.
5215 /// This is not an LValue because we need to re-write the expression, we
5216 /// can not take data from the stack and store it.
5217 /// </summary>
5218 public class PropertyExpr : MemberExpr, IAssignMethod {
5219 public readonly PropertyInfo PropertyInfo;
5220 MethodInfo getter, setter;
5221 bool is_static;
5223 bool resolved;
5225 LocalTemporary temp;
5226 bool prepared;
5228 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5230 PropertyInfo = pi;
5231 eclass = ExprClass.PropertyAccess;
5232 is_static = false;
5233 loc = l;
5235 type = TypeManager.TypeToCoreType (pi.PropertyType);
5237 ResolveAccessors (container_type);
5240 public override string Name {
5241 get {
5242 return PropertyInfo.Name;
5246 public override bool IsInstance {
5247 get {
5248 return !is_static;
5252 public override bool IsStatic {
5253 get {
5254 return is_static;
5258 public override Expression CreateExpressionTree (EmitContext ec)
5260 Arguments args;
5261 if (IsSingleDimensionalArrayLength ()) {
5262 args = new Arguments (1);
5263 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5264 return CreateExpressionFactoryCall ("ArrayLength", args);
5267 if (is_base) {
5268 Error_BaseAccessInExpressionTree (loc);
5269 return null;
5272 args = new Arguments (2);
5273 if (InstanceExpression == null)
5274 args.Add (new Argument (new NullLiteral (loc)));
5275 else
5276 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5277 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5278 return CreateExpressionFactoryCall ("Property", args);
5281 public Expression CreateSetterTypeOfExpression ()
5283 return new TypeOfMethod (setter, loc);
5286 public override Type DeclaringType {
5287 get {
5288 return PropertyInfo.DeclaringType;
5292 public override string GetSignatureForError ()
5294 return TypeManager.GetFullNameSignature (PropertyInfo);
5297 void FindAccessors (Type invocation_type)
5299 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5300 BindingFlags.Static | BindingFlags.Instance |
5301 BindingFlags.DeclaredOnly;
5303 Type current = PropertyInfo.DeclaringType;
5304 for (; current != null; current = current.BaseType) {
5305 MemberInfo[] group = TypeManager.MemberLookup (
5306 invocation_type, invocation_type, current,
5307 MemberTypes.Property, flags, PropertyInfo.Name, null);
5309 if (group == null)
5310 continue;
5312 if (group.Length != 1)
5313 // Oooops, can this ever happen ?
5314 return;
5316 PropertyInfo pi = (PropertyInfo) group [0];
5318 if (getter == null)
5319 getter = pi.GetGetMethod (true);
5321 if (setter == null)
5322 setter = pi.GetSetMethod (true);
5324 MethodInfo accessor = getter != null ? getter : setter;
5326 if (!accessor.IsVirtual)
5327 return;
5332 // We also perform the permission checking here, as the PropertyInfo does not
5333 // hold the information for the accessibility of its setter/getter
5335 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5336 void ResolveAccessors (Type container_type)
5338 FindAccessors (container_type);
5340 if (getter != null) {
5341 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5342 IMethodData md = TypeManager.GetMethod (the_getter);
5343 if (md != null)
5344 md.SetMemberIsUsed ();
5346 is_static = getter.IsStatic;
5349 if (setter != null) {
5350 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5351 IMethodData md = TypeManager.GetMethod (the_setter);
5352 if (md != null)
5353 md.SetMemberIsUsed ();
5355 is_static = setter.IsStatic;
5359 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5361 if (InstanceExpression != null)
5362 InstanceExpression.MutateHoistedGenericType (storey);
5364 type = storey.MutateType (type);
5365 if (getter != null)
5366 getter = storey.MutateGenericMethod (getter);
5367 if (setter != null)
5368 setter = storey.MutateGenericMethod (setter);
5371 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5373 if (is_static) {
5374 InstanceExpression = null;
5375 return true;
5378 if (InstanceExpression == null) {
5379 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5380 return false;
5383 InstanceExpression = InstanceExpression.DoResolve (ec);
5384 if (lvalue_instance && InstanceExpression != null)
5385 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5387 if (InstanceExpression == null)
5388 return false;
5390 InstanceExpression.CheckMarshalByRefAccess (ec);
5392 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5393 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5394 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5395 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5396 Report.SymbolRelatedToPreviousError (PropertyInfo);
5397 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5398 return false;
5401 return true;
5404 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5406 // TODO: correctly we should compare arguments but it will lead to bigger changes
5407 if (mi is MethodBuilder) {
5408 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5409 return;
5412 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5413 sig.Append ('.');
5414 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5415 sig.Append (getter ? "get_" : "set_");
5416 sig.Append (Name);
5417 sig.Append (iparams.GetSignatureForError ());
5419 Report.SymbolRelatedToPreviousError (mi);
5420 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5421 Name, sig.ToString ());
5424 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5426 bool dummy;
5427 MethodInfo accessor = lvalue ? setter : getter;
5428 if (accessor == null && lvalue)
5429 accessor = getter;
5430 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5433 bool IsSingleDimensionalArrayLength ()
5435 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5436 return false;
5438 string t_name = InstanceExpression.Type.Name;
5439 int t_name_len = t_name.Length;
5440 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5443 override public Expression DoResolve (EmitContext ec)
5445 if (resolved)
5446 return this;
5448 if (getter != null){
5449 if (TypeManager.GetParameterData (getter).Count != 0){
5450 Error_PropertyNotFound (getter, true);
5451 return null;
5455 if (getter == null){
5457 // The following condition happens if the PropertyExpr was
5458 // created, but is invalid (ie, the property is inaccessible),
5459 // and we did not want to embed the knowledge about this in
5460 // the caller routine. This only avoids double error reporting.
5462 if (setter == null)
5463 return null;
5465 if (InstanceExpression != EmptyExpression.Null) {
5466 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5467 TypeManager.GetFullNameSignature (PropertyInfo));
5468 return null;
5472 bool must_do_cs1540_check = false;
5473 if (getter != null &&
5474 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5475 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5476 if (pm != null && pm.HasCustomAccessModifier) {
5477 Report.SymbolRelatedToPreviousError (pm);
5478 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5479 TypeManager.CSharpSignature (getter));
5481 else {
5482 Report.SymbolRelatedToPreviousError (getter);
5483 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5485 return null;
5488 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5489 return null;
5492 // Only base will allow this invocation to happen.
5494 if (IsBase && getter.IsAbstract) {
5495 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5498 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5499 UnsafeError (loc);
5502 if (!ec.IsInObsoleteScope) {
5503 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5504 if (pb != null) {
5505 pb.CheckObsoleteness (loc);
5506 } else {
5507 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5508 if (oa != null)
5509 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5513 resolved = true;
5515 return this;
5518 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5520 if (right_side == EmptyExpression.OutAccess) {
5521 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5522 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5523 PropertyInfo.Name);
5524 } else {
5525 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5526 GetSignatureForError ());
5528 return null;
5531 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5532 Error_CannotModifyIntermediateExpressionValue (ec);
5535 if (setter == null){
5537 // The following condition happens if the PropertyExpr was
5538 // created, but is invalid (ie, the property is inaccessible),
5539 // and we did not want to embed the knowledge about this in
5540 // the caller routine. This only avoids double error reporting.
5542 if (getter == null)
5543 return null;
5545 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5546 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5547 PropertyInfo.Name);
5548 } else {
5549 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5550 GetSignatureForError ());
5552 return null;
5555 if (TypeManager.GetParameterData (setter).Count != 1){
5556 Error_PropertyNotFound (setter, false);
5557 return null;
5560 bool must_do_cs1540_check;
5561 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5562 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5563 if (pm != null && pm.HasCustomAccessModifier) {
5564 Report.SymbolRelatedToPreviousError (pm);
5565 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5566 TypeManager.CSharpSignature (setter));
5568 else {
5569 Report.SymbolRelatedToPreviousError (setter);
5570 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5572 return null;
5575 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5576 return null;
5579 // Only base will allow this invocation to happen.
5581 if (IsBase && setter.IsAbstract){
5582 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5585 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5586 UnsafeError (loc);
5589 if (!ec.IsInObsoleteScope) {
5590 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5591 if (pb != null) {
5592 pb.CheckObsoleteness (loc);
5593 } else {
5594 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5595 if (oa != null)
5596 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5600 return this;
5603 public override void Emit (EmitContext ec)
5605 Emit (ec, false);
5608 public void Emit (EmitContext ec, bool leave_copy)
5611 // Special case: length of single dimension array property is turned into ldlen
5613 if (IsSingleDimensionalArrayLength ()) {
5614 if (!prepared)
5615 EmitInstance (ec, false);
5616 ec.ig.Emit (OpCodes.Ldlen);
5617 ec.ig.Emit (OpCodes.Conv_I4);
5618 return;
5621 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5623 if (leave_copy) {
5624 ec.ig.Emit (OpCodes.Dup);
5625 if (!is_static) {
5626 temp = new LocalTemporary (this.Type);
5627 temp.Store (ec);
5633 // Implements the IAssignMethod interface for assignments
5635 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5637 Expression my_source = source;
5639 if (prepare_for_load) {
5640 prepared = true;
5641 source.Emit (ec);
5643 if (leave_copy) {
5644 ec.ig.Emit (OpCodes.Dup);
5645 if (!is_static) {
5646 temp = new LocalTemporary (this.Type);
5647 temp.Store (ec);
5650 } else if (leave_copy) {
5651 source.Emit (ec);
5652 temp = new LocalTemporary (this.Type);
5653 temp.Store (ec);
5654 my_source = temp;
5657 Arguments args = new Arguments (1);
5658 args.Add (new Argument (my_source));
5660 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5662 if (temp != null) {
5663 temp.Emit (ec);
5664 temp.Release (ec);
5669 /// <summary>
5670 /// Fully resolved expression that evaluates to an Event
5671 /// </summary>
5672 public class EventExpr : MemberExpr {
5673 public readonly EventInfo EventInfo;
5675 bool is_static;
5676 MethodInfo add_accessor, remove_accessor;
5678 public EventExpr (EventInfo ei, Location loc)
5680 EventInfo = ei;
5681 this.loc = loc;
5682 eclass = ExprClass.EventAccess;
5684 add_accessor = TypeManager.GetAddMethod (ei);
5685 remove_accessor = TypeManager.GetRemoveMethod (ei);
5686 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5687 is_static = true;
5689 if (EventInfo is MyEventBuilder){
5690 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5691 type = eb.EventType;
5692 eb.SetUsed ();
5693 } else
5694 type = EventInfo.EventHandlerType;
5697 public override string Name {
5698 get {
5699 return EventInfo.Name;
5703 public override bool IsInstance {
5704 get {
5705 return !is_static;
5709 public override bool IsStatic {
5710 get {
5711 return is_static;
5715 public override Type DeclaringType {
5716 get {
5717 return EventInfo.DeclaringType;
5721 public void Error_AssignmentEventOnly ()
5723 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5724 GetSignatureForError ());
5727 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5728 SimpleName original)
5731 // If the event is local to this class, we transform ourselves into a FieldExpr
5734 if (EventInfo.DeclaringType == ec.ContainerType ||
5735 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5736 EventField mi = TypeManager.GetEventField (EventInfo);
5738 if (mi != null) {
5739 if (!ec.IsInObsoleteScope)
5740 mi.CheckObsoleteness (loc);
5742 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5743 Error_AssignmentEventOnly ();
5745 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5747 InstanceExpression = null;
5749 return ml.ResolveMemberAccess (ec, left, loc, original);
5753 if (left is This && !ec.IsInCompoundAssignment)
5754 Error_AssignmentEventOnly ();
5756 return base.ResolveMemberAccess (ec, left, loc, original);
5759 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5761 if (is_static) {
5762 InstanceExpression = null;
5763 return true;
5766 if (InstanceExpression == null) {
5767 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5768 return false;
5771 InstanceExpression = InstanceExpression.DoResolve (ec);
5772 if (InstanceExpression == null)
5773 return false;
5775 if (IsBase && add_accessor.IsAbstract) {
5776 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5777 return false;
5781 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5782 // However, in the Event case, we reported a CS0122 instead.
5784 // TODO: Exact copy from PropertyExpr
5786 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5787 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5788 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5789 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5790 Report.SymbolRelatedToPreviousError (EventInfo);
5791 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5792 return false;
5795 return true;
5798 public bool IsAccessibleFrom (Type invocation_type)
5800 bool dummy;
5801 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5802 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5805 public override Expression CreateExpressionTree (EmitContext ec)
5807 throw new NotSupportedException ("ET");
5810 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5812 // contexts where an LValue is valid have already devolved to FieldExprs
5813 Error_CannotAssign ();
5814 return null;
5817 public override Expression DoResolve (EmitContext ec)
5819 bool must_do_cs1540_check;
5820 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5821 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5822 Report.SymbolRelatedToPreviousError (EventInfo);
5823 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5824 return null;
5827 if (!InstanceResolve (ec, must_do_cs1540_check))
5828 return null;
5830 if (!ec.IsInCompoundAssignment) {
5831 Error_CannotAssign ();
5832 return null;
5835 if (!ec.IsInObsoleteScope) {
5836 EventField ev = TypeManager.GetEventField (EventInfo);
5837 if (ev != null) {
5838 ev.CheckObsoleteness (loc);
5839 } else {
5840 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5841 if (oa != null)
5842 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5846 return this;
5849 public override void Emit (EmitContext ec)
5851 Error_CannotAssign ();
5854 public void Error_CannotAssign ()
5856 Report.Error (70, loc,
5857 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5858 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5861 public override string GetSignatureForError ()
5863 return TypeManager.CSharpSignature (EventInfo);
5866 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5868 Arguments args = new Arguments (1);
5869 args.Add (new Argument (source));
5870 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5874 public class TemporaryVariable : VariableReference
5876 LocalInfo li;
5878 public TemporaryVariable (Type type, Location loc)
5880 this.type = type;
5881 this.loc = loc;
5882 eclass = ExprClass.Variable;
5885 public override Expression CreateExpressionTree (EmitContext ec)
5887 throw new NotSupportedException ("ET");
5890 public override Expression DoResolve (EmitContext ec)
5892 if (li != null)
5893 return this;
5895 TypeExpr te = new TypeExpression (type, loc);
5896 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5897 if (!li.Resolve (ec))
5898 return null;
5901 // Don't capture temporary variables except when using
5902 // iterator redirection
5904 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5905 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5906 storey.CaptureLocalVariable (ec, li);
5909 return this;
5912 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5914 return DoResolve (ec);
5917 public override void Emit (EmitContext ec)
5919 Emit (ec, false);
5922 public void EmitAssign (EmitContext ec, Expression source)
5924 EmitAssign (ec, source, false, false);
5927 public override HoistedVariable GetHoistedVariable (EmitContext ec)
5929 return li.HoistedVariableReference;
5932 public override bool IsFixed {
5933 get { return true; }
5936 public override bool IsRef {
5937 get { return false; }
5940 public override string Name {
5941 get { throw new NotImplementedException (); }
5944 public override void SetHasAddressTaken ()
5946 throw new NotImplementedException ();
5949 protected override ILocalVariable Variable {
5950 get { return li; }
5953 public override VariableInfo VariableInfo {
5954 get { throw new NotImplementedException (); }
5958 ///
5959 /// Handles `var' contextual keyword; var becomes a keyword only
5960 /// if no type called var exists in a variable scope
5961 ///
5962 class VarExpr : SimpleName
5964 // Used for error reporting only
5965 ArrayList initializer;
5967 public VarExpr (Location loc)
5968 : base ("var", loc)
5972 public ArrayList VariableInitializer {
5973 set {
5974 this.initializer = value;
5978 public bool InferType (EmitContext ec, Expression right_side)
5980 if (type != null)
5981 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5983 type = right_side.Type;
5984 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod) {
5985 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5986 right_side.GetSignatureForError ());
5987 return false;
5990 eclass = ExprClass.Variable;
5991 return true;
5994 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5996 if (RootContext.Version < LanguageVersion.V_3)
5997 base.Error_TypeOrNamespaceNotFound (ec);
5998 else
5999 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6002 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
6004 TypeExpr te = base.ResolveAsContextualType (rc, true);
6005 if (te != null)
6006 return te;
6008 if (RootContext.Version < LanguageVersion.V_3)
6009 Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6011 if (initializer == null)
6012 return null;
6014 if (initializer.Count > 1) {
6015 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
6016 Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
6017 initializer = null;
6018 return null;
6021 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
6022 if (variable_initializer == null) {
6023 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
6024 return null;
6027 return null;