cleol
[mcs.git] / mcs / ecore.cs
blobbf2788731d094c8eccd2418b86d9beed06b56405
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 using System;
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
19 using SLE = System.Linq.Expressions;
20 using System.Linq;
22 namespace Mono.CSharp {
24 /// <remarks>
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
28 /// nothing).
29 /// </remarks>
30 public enum ExprClass : byte {
31 Unresolved = 0,
33 Value,
34 Variable,
35 Namespace,
36 Type,
37 TypeParameter,
38 MethodGroup,
39 PropertyAccess,
40 EventAccess,
41 IndexerAccess,
42 Nothing,
45 /// <remarks>
46 /// This is used to tell Resolve in which types of expressions we're
47 /// interested.
48 /// </remarks>
49 [Flags]
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
52 VariableOrValue = 1,
54 // Returns a type expression.
55 Type = 1 << 1,
57 // Returns a method group.
58 MethodGroup = 1 << 2,
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
65 // Set if this is resolving the first part of a MemberAccess.
66 Intermediate = 1 << 11,
70 // This is just as a hint to AddressOf of what will be done with the
71 // address.
72 [Flags]
73 public enum AddressOp {
74 Store = 1,
75 Load = 2,
76 LoadStore = 3
79 /// <summary>
80 /// This interface is implemented by variables
81 /// </summary>
82 public interface IMemoryLocation {
83 /// <summary>
84 /// The AddressOf method should generate code that loads
85 /// the address of the object and leaves it on the stack.
86 ///
87 /// The `mode' argument is used to notify the expression
88 /// of whether this will be used to read from the address or
89 /// write to the address.
90 ///
91 /// This is just a hint that can be used to provide good error
92 /// reporting, and should have no other side effects.
93 /// </summary>
94 void AddressOf (EmitContext ec, AddressOp mode);
98 // An expressions resolved as a direct variable reference
100 public interface IVariableReference : IFixedExpression
102 bool IsHoisted { get; }
103 string Name { get; }
104 VariableInfo VariableInfo { get; }
106 void SetHasAddressTaken ();
110 // Implemented by an expression which could be or is always
111 // fixed
113 public interface IFixedExpression
115 bool IsFixed { get; }
118 /// <remarks>
119 /// Base class for expressions
120 /// </remarks>
121 public abstract class Expression {
122 public ExprClass eclass;
123 protected Type type;
124 protected Location loc;
126 public Type Type {
127 get { return type; }
128 set { type = value; }
131 public virtual Location Location {
132 get { return loc; }
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
140 public virtual string GetSignatureForError ()
142 return TypeManager.CSharpName (type);
145 public static bool IsAccessorAccessible (Type invocation_type, MethodSpec mi, out bool must_do_cs1540_check)
147 var ma = mi.Modifiers & Modifiers.AccessibilityMask;
149 must_do_cs1540_check = false; // by default we do not check for this
151 if (ma == Modifiers.PUBLIC)
152 return true;
155 // If only accessible to the current class or children
157 if (ma == Modifiers.PRIVATE)
158 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
159 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
161 if ((ma & Modifiers.INTERNAL) != 0) {
162 var b = TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly);
163 if (b || ma == Modifiers.INTERNAL)
164 return b;
167 // Family and FamANDAssem require that we derive.
168 // FamORAssem requires that we derive if in different assemblies.
169 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
170 return false;
172 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
173 must_do_cs1540_check = true;
175 return true;
178 public virtual bool IsNull {
179 get {
180 return false;
184 /// <summary>
185 /// Performs semantic analysis on the Expression
186 /// </summary>
188 /// <remarks>
189 /// The Resolve method is invoked to perform the semantic analysis
190 /// on the node.
192 /// The return value is an expression (it can be the
193 /// same expression in some cases) or a new
194 /// expression that better represents this node.
195 ///
196 /// For example, optimizations of Unary (LiteralInt)
197 /// would return a new LiteralInt with a negated
198 /// value.
199 ///
200 /// If there is an error during semantic analysis,
201 /// then an error should be reported (using Report)
202 /// and a null value should be returned.
203 ///
204 /// There are two side effects expected from calling
205 /// Resolve(): the the field variable "eclass" should
206 /// be set to any value of the enumeration
207 /// `ExprClass' and the type variable should be set
208 /// to a valid type (this is the type of the
209 /// expression).
210 /// </remarks>
211 protected abstract Expression DoResolve (ResolveContext rc);
213 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
215 return null;
219 // This is used if the expression should be resolved as a type or namespace name.
220 // the default implementation fails.
222 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
224 if (!silent) {
225 ResolveContext ec = new ResolveContext (rc);
226 Expression e = Resolve (ec);
227 if (e != null)
228 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
231 return null;
235 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
236 // same name exists or as a keyword when no type was found
238 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
240 return ResolveAsTypeTerminal (rc, silent);
244 // This is used to resolve the expression as a type, a null
245 // value will be returned if the expression is not a type
246 // reference
248 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
250 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
251 if (te == null)
252 return null;
254 if (!silent) { // && !(te is TypeParameterExpr)) {
255 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
256 if (obsolete_attr != null && !ec.IsObsolete) {
257 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
261 GenericTypeExpr ct = te as GenericTypeExpr;
262 if (ct != null) {
264 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
265 // There are 2 solutions.
266 // 1, Skip this check completely when we are in override/explicit impl scope
267 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
269 MemberCore gm = ec as GenericMethod;
270 if (gm == null)
271 gm = ec as Method;
272 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
273 te.loc = loc;
274 return te;
277 // TODO: silent flag is ignored
278 ct.CheckConstraints (ec);
281 return te;
284 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
286 int errors = ec.Compiler.Report.Errors;
288 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
290 if (fne == null)
291 return null;
293 TypeExpr te = fne as TypeExpr;
294 if (te == null) {
295 if (!silent && errors == ec.Compiler.Report.Errors)
296 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
297 return null;
300 if (!te.CheckAccessLevel (ec)) {
301 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
302 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
303 return null;
306 te.loc = loc;
307 return te;
310 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
312 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
315 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
317 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
318 + " The qualifier must be of type `{2}' or derived from it",
319 TypeManager.GetFullNameSignature (m),
320 TypeManager.CSharpName (qualifier),
321 TypeManager.CSharpName (container));
325 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
327 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
330 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, Type type, Location loc, string name)
332 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
333 name, TypeManager.CSharpName (type));
336 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
338 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
339 "expressions can be used as a statement");
342 public void Error_InvalidExpressionStatement (BlockContext ec)
344 Error_InvalidExpressionStatement (ec.Report, loc);
347 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
349 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
352 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
354 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
357 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
359 // The error was already reported as CS1660
360 if (type == InternalType.AnonymousMethod)
361 return;
363 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
364 string sig1 = type.DeclaringMethod == null ?
365 TypeManager.CSharpName (type.DeclaringType) :
366 TypeManager.CSharpSignature (type.DeclaringMethod);
367 string sig2 = target.DeclaringMethod == null ?
368 TypeManager.CSharpName (target.DeclaringType) :
369 TypeManager.CSharpSignature (target.DeclaringMethod);
370 ec.Report.ExtraInformation (loc,
371 String.Format (
372 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
373 Type.Name, sig1, sig2));
374 } else if (Type.FullName == target.FullName){
375 ec.Report.ExtraInformation (loc,
376 String.Format (
377 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
378 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
381 if (expl) {
382 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
383 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
384 return;
387 ec.Report.DisableReporting ();
388 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
389 ec.Report.EnableReporting ();
391 if (expl_exists) {
392 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
393 "An explicit conversion exists (are you missing a cast?)",
394 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
395 return;
398 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
399 TypeManager.CSharpName (type),
400 TypeManager.CSharpName (target));
403 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
405 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
408 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
410 // Better message for possible generic expressions
411 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
412 if (this is TypeExpr)
413 report.SymbolRelatedToPreviousError (type);
415 string name = eclass == ExprClass.Type ? ExprClassName : "method";
416 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
417 name, GetSignatureForError ());
418 } else {
419 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
420 ExprClassName, GetSignatureForError ());
424 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
426 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
429 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
431 ec.Report.SymbolRelatedToPreviousError (type);
432 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
433 TypeManager.CSharpName (type), name);
436 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
438 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
441 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 (ResolveContext ec, ResolveFlags flags)
477 if (eclass != ExprClass.Unresolved)
478 return this;
480 Expression e;
481 if (this is SimpleName) {
482 e = ((SimpleName) this).DoResolve (ec, (flags & ResolveFlags.Intermediate) != 0);
483 } else {
484 e = DoResolve (ec);
487 if (e == null)
488 return null;
490 if ((flags & e.ExprClassToResolveFlags) == 0) {
491 e.Error_UnexpectedKind (ec, flags, loc);
492 return null;
495 if (e.type == null)
496 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
498 return e;
501 /// <summary>
502 /// Resolves an expression and performs semantic analysis on it.
503 /// </summary>
504 public Expression Resolve (ResolveContext rc)
506 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
509 /// <summary>
510 /// Resolves an expression for LValue assignment
511 /// </summary>
513 /// <remarks>
514 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
515 /// checking and assertion checking on what we expect from Resolve
516 /// </remarks>
517 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
519 int errors = ec.Report.Errors;
520 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
522 Expression e = DoResolveLValue (ec, right_side);
524 if (e != null && out_access && !(e is IMemoryLocation)) {
525 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
526 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
528 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
529 // e.GetType () + " " + e.GetSignatureForError ());
530 e = null;
533 if (e == null) {
534 if (errors == ec.Report.Errors) {
535 if (out_access)
536 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
537 else
538 Error_ValueAssignment (ec, loc);
540 return null;
543 if (e.eclass == ExprClass.Unresolved)
544 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
546 if ((e.type == null) && !(e is GenericTypeExpr))
547 throw new Exception ("Expression " + e + " did not set its type after Resolve");
549 return e;
552 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
554 Attribute.Error_AttributeArgumentNotValid (rc, loc);
557 /// <summary>
558 /// Emits the code for the expression
559 /// </summary>
561 /// <remarks>
562 /// The Emit method is invoked to generate the code
563 /// for the expression.
564 /// </remarks>
565 public abstract void Emit (EmitContext ec);
568 // Emit code to branch to @target if this expression is equivalent to @on_true.
569 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
570 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
571 // including the use of conditional branches. Note also that a branch MUST be emitted
572 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
574 Emit (ec);
575 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
578 // Emit this expression for its side effects, not for its value.
579 // The default implementation is to emit the value, and then throw it away.
580 // Subclasses can provide more efficient implementations, but those MUST be equivalent
581 public virtual void EmitSideEffect (EmitContext ec)
583 Emit (ec);
584 ec.ig.Emit (OpCodes.Pop);
587 /// <summary>
588 /// Protected constructor. Only derivate types should
589 /// be able to be created
590 /// </summary>
592 protected Expression ()
596 /// <summary>
597 /// Returns a fully formed expression after a MemberLookup
598 /// </summary>
599 ///
600 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
602 if (mi is EventInfo)
603 return new EventExpr (Import.CreateEvent ((EventInfo) mi), loc);
604 else if (mi is FieldInfo) {
605 FieldInfo fi = (FieldInfo) mi;
606 var spec = Import.CreateField (fi);
607 if (spec is ConstSpec)
608 return new ConstantExpr ((ConstSpec) spec, loc);
609 return new FieldExpr (spec, loc);
610 } else if (mi is PropertyInfo)
611 return new PropertyExpr (container_type, Import.CreateProperty ((PropertyInfo) mi), loc);
612 else if (mi is Type) {
613 return new TypeExpression ((System.Type) mi, loc);
616 return null;
619 // TODO: [Obsolete ("Can be removed")]
620 protected static IList<MemberInfo> almost_matched_members = new List<MemberInfo> (4);
623 // FIXME: Probably implement a cache for (t,name,current_access_set)?
625 // This code could use some optimizations, but we need to do some
626 // measurements. For example, we could use a delegate to `flag' when
627 // something can not any longer be a method-group (because it is something
628 // else).
630 // Return values:
631 // If the return value is an Array, then it is an array of
632 // MethodBases
634 // If the return value is an MemberInfo, it is anything, but a Method
636 // null on error.
638 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
639 // the arguments here and have MemberLookup return only the methods that
640 // match the argument count/type, unlike we are doing now (we delay this
641 // decision).
643 // This is so we can catch correctly attempts to invoke instance methods
644 // from a static body (scan for error 120 in ResolveSimpleName).
647 // FIXME: Potential optimization, have a static ArrayList
650 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
651 MemberTypes mt, BindingFlags bf, Location loc)
653 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
657 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
658 // `qualifier_type' or null to lookup members in the current class.
661 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
662 Type qualifier_type, Type queried_type,
663 string name, MemberTypes mt,
664 BindingFlags bf, Location loc)
666 almost_matched_members.Clear ();
668 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
669 queried_type, mt, bf, name, almost_matched_members);
671 if (mi == null)
672 return null;
674 if (mi.Length > 1) {
675 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
676 var methods = new List<MethodSpec> (2);
677 List<MemberInfo> non_methods = null;
679 foreach (var m in mi) {
680 if (m is MethodBase) {
681 methods.Add (Import.CreateMethod ((MethodBase) m));
682 continue;
685 if (non_methods == null)
686 non_methods = new List<MemberInfo> (2);
688 bool is_candidate = true;
689 for (int i = 0; i < non_methods.Count; ++i) {
690 MemberInfo n_m = non_methods [i];
691 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
692 non_methods.Remove (n_m);
693 --i;
694 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
695 is_candidate = false;
696 break;
700 if (is_candidate) {
701 non_methods.Add (m);
705 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
706 ctx.Report.SymbolRelatedToPreviousError (non_methods [1]);
707 ctx.Report.SymbolRelatedToPreviousError (non_methods [0]);
708 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
709 TypeManager.GetFullNameSignature (non_methods [1]),
710 TypeManager.GetFullNameSignature (non_methods [0]));
711 return null;
714 if (methods.Count == 0)
715 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
717 if (non_methods != null && non_methods.Count > 0) {
718 var method = methods [0];
719 MemberInfo non_method = (MemberInfo) non_methods [0];
720 if (method.DeclaringType == non_method.DeclaringType) {
721 // Cannot happen with C# code, but is valid in IL
722 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
723 ctx.Report.SymbolRelatedToPreviousError (non_method);
724 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
725 TypeManager.GetFullNameSignature (non_method),
726 TypeManager.CSharpSignature (method.MetaInfo));
727 return null;
730 if (is_interface) {
731 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
732 ctx.Report.SymbolRelatedToPreviousError (non_method);
733 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
734 TypeManager.CSharpSignature (method.MetaInfo), TypeManager.GetFullNameSignature (non_method));
738 return new MethodGroupExpr (methods, queried_type, loc);
741 if (mi [0] is MethodBase)
742 return new MethodGroupExpr (mi.Select (l => Import.CreateMethod ((MethodBase) l)).ToArray (), queried_type, loc);
744 return ExprClassFromMemberInfo (container_type, mi [0], loc);
747 public const MemberTypes AllMemberTypes =
748 MemberTypes.Constructor |
749 MemberTypes.Event |
750 MemberTypes.Field |
751 MemberTypes.Method |
752 MemberTypes.NestedType |
753 MemberTypes.Property;
755 public const BindingFlags AllBindingFlags =
756 BindingFlags.Public |
757 BindingFlags.Static |
758 BindingFlags.Instance;
760 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
761 string name, Location loc)
763 return MemberLookup (ctx, container_type, null, queried_type, name,
764 AllMemberTypes, AllBindingFlags, loc);
767 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
768 Type queried_type, string name, Location loc)
770 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
771 name, AllMemberTypes, AllBindingFlags, loc);
774 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
775 string name, Location loc)
777 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
778 MemberTypes.Method, AllBindingFlags, loc);
781 /// <summary>
782 /// This is a wrapper for MemberLookup that is not used to "probe", but
783 /// to find a final definition. If the final definition is not found, we
784 /// look for private members and display a useful debugging message if we
785 /// find it.
786 /// </summary>
787 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
788 Type queried_type, string name,
789 MemberTypes mt, BindingFlags bf,
790 Location loc)
792 Expression e;
794 int errors = ec.Report.Errors;
795 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
797 if (e != null || errors != ec.Report.Errors)
798 return e;
800 // No errors were reported by MemberLookup, but there was an error.
801 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
802 name, null, mt, bf);
805 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
806 Type queried_type, string name, string class_name,
807 MemberTypes mt, BindingFlags bf)
809 MemberInfo[] lookup = null;
810 if (queried_type == null) {
811 class_name = "global::";
812 } else {
813 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
814 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
815 name, null);
817 if (lookup != null) {
818 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
821 // FIXME: This is still very wrong, it should be done inside
822 // OverloadResolve to do correct arguments matching.
823 // Requires MemberLookup accessiblity check removal
825 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
826 MemberInfo mi = lookup[0];
827 ec.Report.SymbolRelatedToPreviousError (mi);
828 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
829 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
830 // Although a derived class can access protected members of
831 // its base class it cannot do so through an instance of the
832 // base class (CS1540). If the qualifier_type is a base of the
833 // ec.CurrentType and the lookup succeeds with the latter one,
834 // then we are in this situation.
835 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
836 } else {
837 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
841 return e;
844 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
845 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
846 name, null);
849 if (lookup == null) {
850 if (class_name != null) {
851 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
852 name);
853 } else {
854 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
856 return null;
859 if (TypeManager.MemberLookup (queried_type, null, queried_type,
860 AllMemberTypes, AllBindingFlags |
861 BindingFlags.NonPublic, name, null) == null) {
862 if ((lookup.Length == 1) && (lookup [0] is Type)) {
863 Type t = (Type) lookup [0];
865 ec.Report.Error (305, loc,
866 "Using the generic type `{0}' " +
867 "requires {1} type arguments",
868 TypeManager.CSharpName (t),
869 TypeManager.GetNumberOfTypeArguments (t).ToString ());
870 return null;
874 return Error_MemberLookupFailed (ec, queried_type, lookup);
877 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
879 List<MethodSpec> methods = new List<MethodSpec> ();
880 for (int i = 0; i < members.Length; ++i) {
881 if (!(members [i] is MethodBase))
882 return null;
884 methods.Add (Import.CreateMethod (members[i] as MethodBase));
887 // By default propagate the closest candidates upwards
888 return new MethodGroupExpr (methods.ToArray (), type, loc, true);
891 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
893 throw new NotImplementedException ();
896 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
898 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
901 /// <summary>
902 /// Returns an expression that can be used to invoke operator true
903 /// on the expression if it exists.
904 /// </summary>
905 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
907 return GetOperatorTrueOrFalse (ec, e, true, loc);
910 /// <summary>
911 /// Returns an expression that can be used to invoke operator false
912 /// on the expression if it exists.
913 /// </summary>
914 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
916 return GetOperatorTrueOrFalse (ec, e, false, loc);
919 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
921 MethodGroupExpr operator_group;
922 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
923 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
924 if (operator_group == null)
925 return null;
927 Arguments arguments = new Arguments (1);
928 arguments.Add (new Argument (e));
929 operator_group = operator_group.OverloadResolve (
930 ec, ref arguments, false, loc);
932 if (operator_group == null)
933 return null;
935 return new UserOperatorCall (operator_group, arguments, null, loc);
938 public virtual string ExprClassName
940 get {
941 switch (eclass){
942 case ExprClass.Unresolved:
943 return "Unresolved";
944 case ExprClass.Value:
945 return "value";
946 case ExprClass.Variable:
947 return "variable";
948 case ExprClass.Namespace:
949 return "namespace";
950 case ExprClass.Type:
951 return "type";
952 case ExprClass.MethodGroup:
953 return "method group";
954 case ExprClass.PropertyAccess:
955 return "property access";
956 case ExprClass.EventAccess:
957 return "event access";
958 case ExprClass.IndexerAccess:
959 return "indexer access";
960 case ExprClass.Nothing:
961 return "null";
962 case ExprClass.TypeParameter:
963 return "type parameter";
965 throw new Exception ("Should not happen");
969 /// <summary>
970 /// Reports that we were expecting `expr' to be of class `expected'
971 /// </summary>
972 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
974 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
977 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
979 string name;
980 if (mc != null)
981 name = mc.GetSignatureForError ();
982 else
983 name = GetSignatureForError ();
985 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
986 name, was, expected);
989 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
991 string [] valid = new string [4];
992 int count = 0;
994 if ((flags & ResolveFlags.VariableOrValue) != 0) {
995 valid [count++] = "variable";
996 valid [count++] = "value";
999 if ((flags & ResolveFlags.Type) != 0)
1000 valid [count++] = "type";
1002 if ((flags & ResolveFlags.MethodGroup) != 0)
1003 valid [count++] = "method group";
1005 if (count == 0)
1006 valid [count++] = "unknown";
1008 StringBuilder sb = new StringBuilder (valid [0]);
1009 for (int i = 1; i < count - 1; i++) {
1010 sb.Append ("', `");
1011 sb.Append (valid [i]);
1013 if (count > 1) {
1014 sb.Append ("' or `");
1015 sb.Append (valid [count - 1]);
1018 ec.Report.Error (119, loc,
1019 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1022 public static void UnsafeError (ResolveContext ec, Location loc)
1024 UnsafeError (ec.Report, loc);
1027 public static void UnsafeError (Report Report, Location loc)
1029 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1033 // Load the object from the pointer.
1035 public static void LoadFromPtr (ILGenerator ig, Type t)
1037 if (t == TypeManager.int32_type)
1038 ig.Emit (OpCodes.Ldind_I4);
1039 else if (t == TypeManager.uint32_type)
1040 ig.Emit (OpCodes.Ldind_U4);
1041 else if (t == TypeManager.short_type)
1042 ig.Emit (OpCodes.Ldind_I2);
1043 else if (t == TypeManager.ushort_type)
1044 ig.Emit (OpCodes.Ldind_U2);
1045 else if (t == TypeManager.char_type)
1046 ig.Emit (OpCodes.Ldind_U2);
1047 else if (t == TypeManager.byte_type)
1048 ig.Emit (OpCodes.Ldind_U1);
1049 else if (t == TypeManager.sbyte_type)
1050 ig.Emit (OpCodes.Ldind_I1);
1051 else if (t == TypeManager.uint64_type)
1052 ig.Emit (OpCodes.Ldind_I8);
1053 else if (t == TypeManager.int64_type)
1054 ig.Emit (OpCodes.Ldind_I8);
1055 else if (t == TypeManager.float_type)
1056 ig.Emit (OpCodes.Ldind_R4);
1057 else if (t == TypeManager.double_type)
1058 ig.Emit (OpCodes.Ldind_R8);
1059 else if (t == TypeManager.bool_type)
1060 ig.Emit (OpCodes.Ldind_I1);
1061 else if (t == TypeManager.intptr_type)
1062 ig.Emit (OpCodes.Ldind_I);
1063 else if (TypeManager.IsEnumType (t)) {
1064 if (t == TypeManager.enum_type)
1065 ig.Emit (OpCodes.Ldind_Ref);
1066 else
1067 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1068 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1069 ig.Emit (OpCodes.Ldobj, t);
1070 else if (t.IsPointer)
1071 ig.Emit (OpCodes.Ldind_I);
1072 else
1073 ig.Emit (OpCodes.Ldind_Ref);
1077 // The stack contains the pointer and the value of type `type'
1079 public static void StoreFromPtr (ILGenerator ig, Type type)
1081 if (TypeManager.IsEnumType (type))
1082 type = TypeManager.GetEnumUnderlyingType (type);
1083 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1084 ig.Emit (OpCodes.Stind_I4);
1085 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1086 ig.Emit (OpCodes.Stind_I8);
1087 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1088 type == TypeManager.ushort_type)
1089 ig.Emit (OpCodes.Stind_I2);
1090 else if (type == TypeManager.float_type)
1091 ig.Emit (OpCodes.Stind_R4);
1092 else if (type == TypeManager.double_type)
1093 ig.Emit (OpCodes.Stind_R8);
1094 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1095 type == TypeManager.bool_type)
1096 ig.Emit (OpCodes.Stind_I1);
1097 else if (type == TypeManager.intptr_type)
1098 ig.Emit (OpCodes.Stind_I);
1099 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1100 ig.Emit (OpCodes.Stobj, type);
1101 else
1102 ig.Emit (OpCodes.Stind_Ref);
1106 // Returns the size of type `t' if known, otherwise, 0
1108 public static int GetTypeSize (Type t)
1110 t = TypeManager.TypeToCoreType (t);
1111 if (t == TypeManager.int32_type ||
1112 t == TypeManager.uint32_type ||
1113 t == TypeManager.float_type)
1114 return 4;
1115 else if (t == TypeManager.int64_type ||
1116 t == TypeManager.uint64_type ||
1117 t == TypeManager.double_type)
1118 return 8;
1119 else if (t == TypeManager.byte_type ||
1120 t == TypeManager.sbyte_type ||
1121 t == TypeManager.bool_type)
1122 return 1;
1123 else if (t == TypeManager.short_type ||
1124 t == TypeManager.char_type ||
1125 t == TypeManager.ushort_type)
1126 return 2;
1127 else if (t == TypeManager.decimal_type)
1128 return 16;
1129 else
1130 return 0;
1133 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1135 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1138 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1140 ec.Report.SymbolRelatedToPreviousError (type);
1141 if (ec.CurrentInitializerVariable != null) {
1142 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1143 TypeManager.CSharpName (type), GetSignatureForError ());
1144 } else {
1145 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1146 GetSignatureForError ());
1151 // Converts `source' to an int, uint, long or ulong.
1153 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1155 if (TypeManager.IsDynamicType (source.type)) {
1156 Arguments args = new Arguments (1);
1157 args.Add (new Argument (source));
1158 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1161 Expression converted;
1163 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1164 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1165 if (converted == null)
1166 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1167 if (converted == null)
1168 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1169 if (converted == null)
1170 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1172 if (converted == null) {
1173 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1174 return null;
1179 // Only positive constants are allowed at compile time
1181 Constant c = converted as Constant;
1182 if (c != null && c.IsNegative)
1183 Error_NegativeArrayIndex (ec, source.loc);
1185 // No conversion needed to array index
1186 if (converted.Type == TypeManager.int32_type)
1187 return converted;
1189 return new ArrayIndexCast (converted).Resolve (ec);
1193 // Derived classes implement this method by cloning the fields that
1194 // could become altered during the Resolve stage
1196 // Only expressions that are created for the parser need to implement
1197 // this.
1199 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1201 throw new NotImplementedException (
1202 String.Format (
1203 "CloneTo not implemented for expression {0}", this.GetType ()));
1207 // Clones an expression created by the parser.
1209 // We only support expressions created by the parser so far, not
1210 // expressions that have been resolved (many more classes would need
1211 // to implement CloneTo).
1213 // This infrastructure is here merely for Lambda expressions which
1214 // compile the same code using different type values for the same
1215 // arguments to find the correct overload
1217 public Expression Clone (CloneContext clonectx)
1219 Expression cloned = (Expression) MemberwiseClone ();
1220 CloneTo (clonectx, cloned);
1222 return cloned;
1226 // Implementation of expression to expression tree conversion
1228 public abstract Expression CreateExpressionTree (ResolveContext ec);
1230 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1232 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1235 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1237 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1240 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1242 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1245 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1247 TypeExpr texpr = TypeManager.expression_type_expr;
1248 if (texpr == null) {
1249 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
1250 if (t == null)
1251 return null;
1253 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1256 return texpr;
1260 // Implemented by all expressions which support conversion from
1261 // compiler expression to invokable runtime expression. Used by
1262 // dynamic C# binder.
1264 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1266 throw new NotImplementedException ("MakeExpression for " + GetType ());
1269 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1271 // TODO: It should probably be type = storey.MutateType (type);
1275 /// <summary>
1276 /// This is just a base class for expressions that can
1277 /// appear on statements (invocations, object creation,
1278 /// assignments, post/pre increment and decrement). The idea
1279 /// being that they would support an extra Emition interface that
1280 /// does not leave a result on the stack.
1281 /// </summary>
1282 public abstract class ExpressionStatement : Expression {
1284 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1286 Expression e = Resolve (ec);
1287 if (e == null)
1288 return null;
1290 ExpressionStatement es = e as ExpressionStatement;
1291 if (es == null)
1292 Error_InvalidExpressionStatement (ec);
1294 return es;
1297 /// <summary>
1298 /// Requests the expression to be emitted in a `statement'
1299 /// context. This means that no new value is left on the
1300 /// stack after invoking this method (constrasted with
1301 /// Emit that will always leave a value on the stack).
1302 /// </summary>
1303 public abstract void EmitStatement (EmitContext ec);
1305 public override void EmitSideEffect (EmitContext ec)
1307 EmitStatement (ec);
1311 /// <summary>
1312 /// This kind of cast is used to encapsulate the child
1313 /// whose type is child.Type into an expression that is
1314 /// reported to return "return_type". This is used to encapsulate
1315 /// expressions which have compatible types, but need to be dealt
1316 /// at higher levels with.
1318 /// For example, a "byte" expression could be encapsulated in one
1319 /// of these as an "unsigned int". The type for the expression
1320 /// would be "unsigned int".
1322 /// </summary>
1323 public abstract class TypeCast : Expression
1325 protected readonly Expression child;
1327 protected TypeCast (Expression child, Type return_type)
1329 eclass = child.eclass;
1330 loc = child.Location;
1331 type = return_type;
1332 this.child = child;
1335 public Expression Child {
1336 get {
1337 return child;
1341 public override Expression CreateExpressionTree (ResolveContext ec)
1343 Arguments args = new Arguments (2);
1344 args.Add (new Argument (child.CreateExpressionTree (ec)));
1345 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1347 if (type.IsPointer || child.Type.IsPointer)
1348 Error_PointerInsideExpressionTree (ec);
1350 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1353 protected override Expression DoResolve (ResolveContext ec)
1355 // This should never be invoked, we are born in fully
1356 // initialized state.
1358 return this;
1361 public override void Emit (EmitContext ec)
1363 child.Emit (ec);
1366 public override SLE.Expression MakeExpression (BuilderContext ctx)
1368 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1369 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1370 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1373 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1375 type = storey.MutateType (type);
1376 child.MutateHoistedGenericType (storey);
1379 protected override void CloneTo (CloneContext clonectx, Expression t)
1381 // Nothing to clone
1384 public override bool IsNull {
1385 get { return child.IsNull; }
1389 public class EmptyCast : TypeCast {
1390 EmptyCast (Expression child, Type target_type)
1391 : base (child, target_type)
1395 public static Expression Create (Expression child, Type type)
1397 Constant c = child as Constant;
1398 if (c != null)
1399 return new EmptyConstantCast (c, type);
1401 EmptyCast e = child as EmptyCast;
1402 if (e != null)
1403 return new EmptyCast (e.child, type);
1405 return new EmptyCast (child, type);
1408 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1410 child.EmitBranchable (ec, label, on_true);
1413 public override void EmitSideEffect (EmitContext ec)
1415 child.EmitSideEffect (ec);
1420 // Used for predefined class library user casts (no obsolete check, etc.)
1422 public class OperatorCast : TypeCast {
1423 MethodInfo conversion_operator;
1425 public OperatorCast (Expression child, Type target_type)
1426 : this (child, target_type, false)
1430 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1431 : base (child, target_type)
1433 conversion_operator = GetConversionOperator (find_explicit);
1434 if (conversion_operator == null)
1435 throw new InternalErrorException ("Outer conversion routine is out of sync");
1438 // Returns the implicit operator that converts from
1439 // 'child.Type' to our target type (type)
1440 MethodInfo GetConversionOperator (bool find_explicit)
1442 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1444 MemberInfo [] mi;
1446 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1447 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1449 if (mi == null){
1450 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1451 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1454 foreach (MethodInfo oper in mi) {
1455 AParametersCollection pd = TypeManager.GetParameterData (oper);
1457 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1458 return oper;
1461 return null;
1464 public override void Emit (EmitContext ec)
1466 child.Emit (ec);
1467 ec.ig.Emit (OpCodes.Call, conversion_operator);
1471 /// <summary>
1472 /// This is a numeric cast to a Decimal
1473 /// </summary>
1474 public class CastToDecimal : OperatorCast {
1475 public CastToDecimal (Expression child)
1476 : this (child, false)
1480 public CastToDecimal (Expression child, bool find_explicit)
1481 : base (child, TypeManager.decimal_type, find_explicit)
1486 /// <summary>
1487 /// This is an explicit numeric cast from a Decimal
1488 /// </summary>
1489 public class CastFromDecimal : TypeCast
1491 static Dictionary<Type, MethodInfo> operators;
1493 public CastFromDecimal (Expression child, Type return_type)
1494 : base (child, return_type)
1496 if (child.Type != TypeManager.decimal_type)
1497 throw new InternalErrorException (
1498 "The expected type is Decimal, instead it is " + child.Type.FullName);
1501 // Returns the explicit operator that converts from an
1502 // express of type System.Decimal to 'type'.
1503 public Expression Resolve ()
1505 if (operators == null) {
1506 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1507 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1508 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1510 operators = new Dictionary<Type, MethodInfo> (ReferenceEquality<Type>.Default);
1511 foreach (MethodInfo oper in all_oper) {
1512 AParametersCollection pd = TypeManager.GetParameterData (oper);
1513 if (pd.Types [0] == TypeManager.decimal_type)
1514 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1518 return operators.ContainsKey (type) ? this : null;
1521 public override void Emit (EmitContext ec)
1523 ILGenerator ig = ec.ig;
1524 child.Emit (ec);
1526 ig.Emit (OpCodes.Call, operators [type]);
1532 // Constant specialization of EmptyCast.
1533 // We need to special case this since an empty cast of
1534 // a constant is still a constant.
1536 public class EmptyConstantCast : Constant
1538 public Constant child;
1540 public EmptyConstantCast (Constant child, Type type)
1541 : base (child.Location)
1543 if (child == null)
1544 throw new ArgumentNullException ("child");
1546 this.child = child;
1547 this.eclass = child.eclass;
1548 this.type = type;
1551 public override string AsString ()
1553 return child.AsString ();
1556 public override object GetValue ()
1558 return child.GetValue ();
1561 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1563 if (child.Type == target_type)
1564 return child;
1566 // FIXME: check that 'type' can be converted to 'target_type' first
1567 return child.ConvertExplicitly (in_checked_context, target_type);
1570 public override Expression CreateExpressionTree (ResolveContext ec)
1572 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1573 child.CreateExpressionTree (ec),
1574 new TypeOf (new TypeExpression (type, loc), loc));
1576 if (type.IsPointer)
1577 Error_PointerInsideExpressionTree (ec);
1579 return CreateExpressionFactoryCall (ec, "Convert", args);
1582 public override bool IsDefaultValue {
1583 get { return child.IsDefaultValue; }
1586 public override bool IsNegative {
1587 get { return child.IsNegative; }
1590 public override bool IsNull {
1591 get { return child.IsNull; }
1594 public override bool IsOneInteger {
1595 get { return child.IsOneInteger; }
1598 public override bool IsZeroInteger {
1599 get { return child.IsZeroInteger; }
1602 protected override Expression DoResolve (ResolveContext rc)
1604 return this;
1607 public override void Emit (EmitContext ec)
1609 child.Emit (ec);
1612 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1614 child.EmitBranchable (ec, label, on_true);
1616 // Only to make verifier happy
1617 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1618 ec.ig.Emit (OpCodes.Unbox_Any, type);
1621 public override void EmitSideEffect (EmitContext ec)
1623 child.EmitSideEffect (ec);
1626 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
1628 // FIXME: Do we need to check user conversions?
1629 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1630 return null;
1631 return child.ConvertImplicitly (rc, target_type);
1634 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1636 child.MutateHoistedGenericType (storey);
1640 /// <summary>
1641 /// This class is used to wrap literals which belong inside Enums
1642 /// </summary>
1643 public class EnumConstant : Constant
1645 public Constant Child;
1647 public EnumConstant (Constant child, Type enum_type)
1648 : base (child.Location)
1650 this.Child = child;
1651 this.type = enum_type;
1654 protected EnumConstant (Location loc)
1655 : base (loc)
1659 protected override Expression DoResolve (ResolveContext rc)
1661 Child = Child.Resolve (rc);
1662 this.eclass = ExprClass.Value;
1663 return this;
1666 public override void Emit (EmitContext ec)
1668 Child.Emit (ec);
1671 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
1673 Child.EncodeAttributeValue (rc, enc, Child.Type);
1676 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1678 Child.EmitBranchable (ec, label, on_true);
1681 public override void EmitSideEffect (EmitContext ec)
1683 Child.EmitSideEffect (ec);
1686 public override string GetSignatureForError()
1688 return TypeManager.CSharpName (Type);
1691 public override object GetValue ()
1693 return Child.GetValue ();
1696 public override object GetTypedValue ()
1698 // FIXME: runtime is not ready to work with just emited enums
1699 if (!RootContext.StdLib) {
1700 return Child.GetValue ();
1703 #if MS_COMPATIBLE
1704 // Small workaround for big problem
1705 // System.Enum.ToObject cannot be called on dynamic types
1706 // EnumBuilder has to be used, but we cannot use EnumBuilder
1707 // because it does not properly support generics
1709 // This works only sometimes
1711 if (TypeManager.IsBeingCompiled (type))
1712 return Child.GetValue ();
1713 #endif
1715 return System.Enum.ToObject (type, Child.GetValue ());
1718 public override string AsString ()
1720 return Child.AsString ();
1723 public EnumConstant Increment()
1725 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1728 public override bool IsDefaultValue {
1729 get {
1730 return Child.IsDefaultValue;
1734 public override bool IsZeroInteger {
1735 get { return Child.IsZeroInteger; }
1738 public override bool IsNegative {
1739 get {
1740 return Child.IsNegative;
1744 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1746 if (Child.Type == target_type)
1747 return Child;
1749 return Child.ConvertExplicitly (in_checked_context, target_type);
1752 public override Constant ConvertImplicitly (ResolveContext rc, Type type)
1754 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1755 type = TypeManager.DropGenericTypeArguments (type);
1757 if (this_type == type) {
1758 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1759 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1760 return this;
1762 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1763 if (type.UnderlyingSystemType != child_type)
1764 Child = Child.ConvertImplicitly (rc, type.UnderlyingSystemType);
1765 return this;
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1769 return null;
1772 return Child.ConvertImplicitly (rc, type);
1776 /// <summary>
1777 /// This kind of cast is used to encapsulate Value Types in objects.
1779 /// The effect of it is to box the value type emitted by the previous
1780 /// operation.
1781 /// </summary>
1782 public class BoxedCast : TypeCast {
1784 public BoxedCast (Expression expr, Type target_type)
1785 : base (expr, target_type)
1787 eclass = ExprClass.Value;
1790 protected override Expression DoResolve (ResolveContext ec)
1792 // This should never be invoked, we are born in fully
1793 // initialized state.
1795 return this;
1798 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, Type targetType)
1800 enc.Encode (child.Type);
1801 child.EncodeAttributeValue (rc, enc, child.Type);
1804 public override void Emit (EmitContext ec)
1806 base.Emit (ec);
1808 ec.ig.Emit (OpCodes.Box, child.Type);
1811 public override void EmitSideEffect (EmitContext ec)
1813 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1814 // so, we need to emit the box+pop instructions in most cases
1815 if (TypeManager.IsStruct (child.Type) &&
1816 (type == TypeManager.object_type || type == TypeManager.value_type))
1817 child.EmitSideEffect (ec);
1818 else
1819 base.EmitSideEffect (ec);
1823 public class UnboxCast : TypeCast {
1824 public UnboxCast (Expression expr, Type return_type)
1825 : base (expr, return_type)
1829 protected override Expression DoResolve (ResolveContext ec)
1831 // This should never be invoked, we are born in fully
1832 // initialized state.
1834 return this;
1837 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1839 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1840 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1841 return base.DoResolveLValue (ec, right_side);
1844 public override void Emit (EmitContext ec)
1846 base.Emit (ec);
1848 ILGenerator ig = ec.ig;
1849 ig.Emit (OpCodes.Unbox_Any, type);
1852 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1854 type = storey.MutateType (type);
1855 base.MutateHoistedGenericType (storey);
1859 /// <summary>
1860 /// This is used to perform explicit numeric conversions.
1862 /// Explicit numeric conversions might trigger exceptions in a checked
1863 /// context, so they should generate the conv.ovf opcodes instead of
1864 /// conv opcodes.
1865 /// </summary>
1866 public class ConvCast : TypeCast {
1867 public enum Mode : byte {
1868 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1869 U1_I1, U1_CH,
1870 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1871 U2_I1, U2_U1, U2_I2, U2_CH,
1872 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1873 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1874 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1875 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1876 CH_I1, CH_U1, CH_I2,
1877 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1878 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1879 I_I8,
1882 Mode mode;
1884 public ConvCast (Expression child, Type return_type, Mode m)
1885 : base (child, return_type)
1887 mode = m;
1890 protected override Expression DoResolve (ResolveContext ec)
1892 // This should never be invoked, we are born in fully
1893 // initialized state.
1895 return this;
1898 public override string ToString ()
1900 return String.Format ("ConvCast ({0}, {1})", mode, child);
1903 public override void Emit (EmitContext ec)
1905 ILGenerator ig = ec.ig;
1907 base.Emit (ec);
1909 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1910 switch (mode){
1911 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1912 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1913 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1914 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1915 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1917 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1918 case Mode.U1_CH: /* nothing */ break;
1920 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1921 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1922 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1923 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1924 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1925 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1927 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1928 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1929 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1930 case Mode.U2_CH: /* nothing */ break;
1932 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1933 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1934 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1935 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1936 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1937 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1938 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1941 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1942 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1943 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1944 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1945 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1947 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1948 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1949 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1950 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1951 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1952 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1953 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1955 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1957 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1961 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1962 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1963 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1964 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1965 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1967 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1969 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1971 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1972 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1973 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1974 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1975 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1976 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1977 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1978 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1979 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1982 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1983 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1984 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1986 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1987 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1988 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1989 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1992 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1994 } else {
1995 switch (mode){
1996 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1997 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1998 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1999 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2000 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2002 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2003 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2006 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2007 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2008 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2009 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2010 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2015 case Mode.U2_CH: /* nothing */ break;
2017 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2018 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2019 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2020 case Mode.I4_U4: /* nothing */ break;
2021 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2022 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2023 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2025 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2026 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2028 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.U4_I4: /* nothing */ break;
2030 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2037 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2038 case Mode.I8_U8: /* nothing */ break;
2039 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2040 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2042 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2046 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2047 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2048 case Mode.U8_I8: /* nothing */ break;
2049 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2050 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2052 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2053 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2054 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2056 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2057 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2058 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2059 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2060 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2061 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2062 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2063 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2064 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2067 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2068 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2069 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2071 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2072 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2073 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2074 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2077 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2083 public class OpcodeCast : TypeCast {
2084 readonly OpCode op;
2086 public OpcodeCast (Expression child, Type return_type, OpCode op)
2087 : base (child, return_type)
2089 this.op = op;
2092 protected override Expression DoResolve (ResolveContext ec)
2094 // This should never be invoked, we are born in fully
2095 // initialized state.
2097 return this;
2100 public override void Emit (EmitContext ec)
2102 base.Emit (ec);
2103 ec.ig.Emit (op);
2106 public Type UnderlyingType {
2107 get { return child.Type; }
2111 /// <summary>
2112 /// This kind of cast is used to encapsulate a child and cast it
2113 /// to the class requested
2114 /// </summary>
2115 public sealed class ClassCast : TypeCast {
2116 readonly bool forced;
2118 public ClassCast (Expression child, Type return_type)
2119 : base (child, return_type)
2123 public ClassCast (Expression child, Type return_type, bool forced)
2124 : base (child, return_type)
2126 this.forced = forced;
2129 public override void Emit (EmitContext ec)
2131 base.Emit (ec);
2133 bool gen = TypeManager.IsGenericParameter (child.Type);
2134 if (gen)
2135 ec.ig.Emit (OpCodes.Box, child.Type);
2137 if (type.IsGenericParameter) {
2138 ec.ig.Emit (OpCodes.Unbox_Any, type);
2139 return;
2142 if (gen && !forced)
2143 return;
2145 ec.ig.Emit (OpCodes.Castclass, type);
2150 // Created during resolving pahse when an expression is wrapped or constantified
2151 // and original expression can be used later (e.g. for expression trees)
2153 public class ReducedExpression : Expression
2155 sealed class ReducedConstantExpression : EmptyConstantCast
2157 readonly Expression orig_expr;
2159 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2160 : base (expr, expr.Type)
2162 this.orig_expr = orig_expr;
2165 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
2167 Constant c = base.ConvertImplicitly (rc, target_type);
2168 if (c != null)
2169 c = new ReducedConstantExpression (c, orig_expr);
2171 return c;
2174 public override Expression CreateExpressionTree (ResolveContext ec)
2176 return orig_expr.CreateExpressionTree (ec);
2179 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2181 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2182 if (c != null)
2183 c = new ReducedConstantExpression (c, orig_expr);
2184 return c;
2188 sealed class ReducedExpressionStatement : ExpressionStatement
2190 readonly Expression orig_expr;
2191 readonly ExpressionStatement stm;
2193 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2195 this.orig_expr = orig;
2196 this.stm = stm;
2197 this.loc = orig.Location;
2200 public override Expression CreateExpressionTree (ResolveContext ec)
2202 return orig_expr.CreateExpressionTree (ec);
2205 protected override Expression DoResolve (ResolveContext ec)
2207 eclass = stm.eclass;
2208 type = stm.Type;
2209 return this;
2212 public override void Emit (EmitContext ec)
2214 stm.Emit (ec);
2217 public override void EmitStatement (EmitContext ec)
2219 stm.EmitStatement (ec);
2222 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2224 stm.MutateHoistedGenericType (storey);
2228 readonly Expression expr, orig_expr;
2230 private ReducedExpression (Expression expr, Expression orig_expr)
2232 this.expr = expr;
2233 this.eclass = expr.eclass;
2234 this.type = expr.Type;
2235 this.orig_expr = orig_expr;
2236 this.loc = orig_expr.Location;
2240 // Creates fully resolved expression switcher
2242 public static Constant Create (Constant expr, Expression original_expr)
2244 if (expr.eclass == ExprClass.Unresolved)
2245 throw new ArgumentException ("Unresolved expression");
2247 return new ReducedConstantExpression (expr, original_expr);
2250 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2252 return new ReducedExpressionStatement (s, orig);
2256 // Creates unresolved reduce expression. The original expression has to be
2257 // already resolved
2259 public static Expression Create (Expression expr, Expression original_expr)
2261 Constant c = expr as Constant;
2262 if (c != null)
2263 return Create (c, original_expr);
2265 ExpressionStatement s = expr as ExpressionStatement;
2266 if (s != null)
2267 return Create (s, original_expr);
2269 if (expr.eclass == ExprClass.Unresolved)
2270 throw new ArgumentException ("Unresolved expression");
2272 return new ReducedExpression (expr, original_expr);
2275 public override Expression CreateExpressionTree (ResolveContext ec)
2277 return orig_expr.CreateExpressionTree (ec);
2280 protected override Expression DoResolve (ResolveContext ec)
2282 return this;
2285 public override void Emit (EmitContext ec)
2287 expr.Emit (ec);
2290 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2292 expr.EmitBranchable (ec, target, on_true);
2295 public override SLE.Expression MakeExpression (BuilderContext ctx)
2297 return orig_expr.MakeExpression (ctx);
2300 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2302 expr.MutateHoistedGenericType (storey);
2307 // Standard composite pattern
2309 public abstract class CompositeExpression : Expression
2311 Expression expr;
2313 protected CompositeExpression (Expression expr)
2315 this.expr = expr;
2316 this.loc = expr.Location;
2319 public override Expression CreateExpressionTree (ResolveContext ec)
2321 return expr.CreateExpressionTree (ec);
2324 public Expression Child {
2325 get { return expr; }
2328 protected override Expression DoResolve (ResolveContext ec)
2330 expr = expr.Resolve (ec);
2331 if (expr != null) {
2332 type = expr.Type;
2333 eclass = expr.eclass;
2336 return this;
2339 public override void Emit (EmitContext ec)
2341 expr.Emit (ec);
2344 public override bool IsNull {
2345 get { return expr.IsNull; }
2350 // Base of expressions used only to narrow resolve flow
2352 public abstract class ShimExpression : Expression
2354 protected Expression expr;
2356 protected ShimExpression (Expression expr)
2358 this.expr = expr;
2361 protected override void CloneTo (CloneContext clonectx, Expression t)
2363 if (expr == null)
2364 return;
2366 ShimExpression target = (ShimExpression) t;
2367 target.expr = expr.Clone (clonectx);
2370 public override Expression CreateExpressionTree (ResolveContext ec)
2372 throw new NotSupportedException ("ET");
2375 public override void Emit (EmitContext ec)
2377 throw new InternalErrorException ("Missing Resolve call");
2380 public Expression Expr {
2381 get { return expr; }
2384 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2386 throw new InternalErrorException ("Missing Resolve call");
2391 // Unresolved type name expressions
2393 public abstract class ATypeNameExpression : FullNamedExpression
2395 string name;
2396 protected TypeArguments targs;
2398 protected ATypeNameExpression (string name, Location l)
2400 this.name = name;
2401 loc = l;
2404 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2406 this.name = name;
2407 this.targs = targs;
2408 loc = l;
2411 public bool HasTypeArguments {
2412 get {
2413 return targs != null;
2417 public override bool Equals (object obj)
2419 ATypeNameExpression atne = obj as ATypeNameExpression;
2420 return atne != null && atne.Name == Name &&
2421 (targs == null || targs.Equals (atne.targs));
2424 public override int GetHashCode ()
2426 return Name.GetHashCode ();
2429 public override string GetSignatureForError ()
2431 if (targs != null) {
2432 return TypeManager.RemoveGenericArity (Name) + "<" +
2433 targs.GetSignatureForError () + ">";
2436 return Name;
2439 public string Name {
2440 get {
2441 return name;
2443 set {
2444 name = value;
2448 public TypeArguments TypeArguments {
2449 get {
2450 return targs;
2455 /// <summary>
2456 /// SimpleName expressions are formed of a single word and only happen at the beginning
2457 /// of a dotted-name.
2458 /// </summary>
2459 public class SimpleName : ATypeNameExpression
2461 public SimpleName (string name, Location l)
2462 : base (name, l)
2466 public SimpleName (string name, TypeArguments args, Location l)
2467 : base (name, args, l)
2471 public SimpleName (string name, TypeParameter[] type_params, Location l)
2472 : base (name, l)
2474 targs = new TypeArguments ();
2475 foreach (TypeParameter type_param in type_params)
2476 targs.Add (new TypeParameterExpr (type_param, l));
2479 public static string RemoveGenericArity (string name)
2481 int start = 0;
2482 StringBuilder sb = null;
2483 do {
2484 int pos = name.IndexOf ('`', start);
2485 if (pos < 0) {
2486 if (start == 0)
2487 return name;
2489 sb.Append (name.Substring (start));
2490 break;
2493 if (sb == null)
2494 sb = new StringBuilder ();
2495 sb.Append (name.Substring (start, pos-start));
2497 pos++;
2498 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2499 pos++;
2501 start = pos;
2502 } while (start < name.Length);
2504 return sb.ToString ();
2507 public SimpleName GetMethodGroup ()
2509 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2512 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2514 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2515 ec.Report.Error (236, l,
2516 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2517 name);
2518 else
2519 ec.Report.Error (120, l,
2520 "An object reference is required to access non-static member `{0}'",
2521 name);
2524 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2526 return resolved_to != null && resolved_to.Type != null &&
2527 resolved_to.Type.Name == Name &&
2528 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2531 protected override Expression DoResolve (ResolveContext ec)
2533 return SimpleNameResolve (ec, null, false);
2536 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2538 return SimpleNameResolve (ec, right_side, false);
2541 public Expression DoResolve (ResolveContext ec, bool intermediate)
2543 return SimpleNameResolve (ec, null, intermediate);
2546 static bool IsNestedChild (Type t, Type parent)
2548 while (parent != null) {
2549 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2550 return true;
2552 parent = parent.BaseType;
2555 return false;
2558 FullNamedExpression ResolveNested (Type t)
2560 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2561 return null;
2563 Type ds = t;
2564 while (ds != null && !IsNestedChild (t, ds))
2565 ds = ds.DeclaringType;
2567 if (ds == null)
2568 return null;
2570 Type[] gen_params = TypeManager.GetTypeArguments (t);
2572 int arg_count = targs != null ? targs.Count : 0;
2574 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2575 Type[] gargs = TypeManager.GetTypeArguments (ds);
2576 if (arg_count + gargs.Length == gen_params.Length) {
2577 TypeArguments new_args = new TypeArguments ();
2578 foreach (Type param in gargs)
2579 new_args.Add (new TypeExpression (param, loc));
2581 if (targs != null)
2582 new_args.Add (targs);
2584 return new GenericTypeExpr (t, new_args, loc);
2588 return null;
2591 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2593 int errors = ec.Compiler.Report.Errors;
2594 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2596 if (fne != null) {
2597 if (fne.Type == null)
2598 return fne;
2600 FullNamedExpression nested = ResolveNested (fne.Type);
2601 if (nested != null)
2602 return nested.ResolveAsTypeStep (ec, false);
2604 if (targs != null) {
2605 if (TypeManager.IsGenericType (fne.Type)) {
2606 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2607 return ct.ResolveAsTypeStep (ec, false);
2610 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2613 return fne;
2616 if (!HasTypeArguments && Name == "dynamic" &&
2617 RootContext.Version > LanguageVersion.V_3 &&
2618 RootContext.MetadataCompatibilityVersion > MetadataVersion.v2) {
2620 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2621 ec.Compiler.Report.Error (1980, Location,
2622 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2623 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2626 return new DynamicTypeExpr (loc);
2629 if (silent || errors != ec.Compiler.Report.Errors)
2630 return null;
2632 Error_TypeOrNamespaceNotFound (ec);
2633 return null;
2636 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2638 if (ec.CurrentType != null) {
2639 if (ec.CurrentTypeDefinition != null) {
2640 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2641 if (mc != null) {
2642 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2643 return;
2647 string ns = ec.CurrentType.Namespace;
2648 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2649 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2650 Type type = a.GetType (fullname);
2651 if (type != null) {
2652 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2653 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2654 return;
2658 if (ec.CurrentTypeDefinition != null) {
2659 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2660 if (t != null) {
2661 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2662 return;
2667 if (targs != null) {
2668 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2669 if (retval != null) {
2670 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2671 return;
2675 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2678 // TODO: I am still not convinced about this. If someone else will need it
2679 // implement this as virtual property in MemberCore hierarchy
2680 public static string GetMemberType (MemberCore mc)
2682 if (mc is Property)
2683 return "property";
2684 if (mc is Indexer)
2685 return "indexer";
2686 if (mc is FieldBase)
2687 return "field";
2688 if (mc is MethodCore)
2689 return "method";
2690 if (mc is EnumMember)
2691 return "enum";
2692 if (mc is Event)
2693 return "event";
2695 return "type";
2698 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2700 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2702 if (e == null)
2703 return null;
2705 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2706 return e;
2708 return null;
2711 /// <remarks>
2712 /// 7.5.2: Simple Names.
2714 /// Local Variables and Parameters are handled at
2715 /// parse time, so they never occur as SimpleNames.
2717 /// The `intermediate' flag is used by MemberAccess only
2718 /// and it is used to inform us that it is ok for us to
2719 /// avoid the static check, because MemberAccess might end
2720 /// up resolving the Name as a Type name and the access as
2721 /// a static type access.
2723 /// ie: Type Type; .... { Type.GetType (""); }
2725 /// Type is both an instance variable and a Type; Type.GetType
2726 /// is the static method not an instance method of type.
2727 /// </remarks>
2728 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2730 Expression e = null;
2733 // Stage 1: Performed by the parser (binding to locals or parameters).
2735 Block current_block = ec.CurrentBlock;
2736 if (current_block != null){
2737 LocalInfo vi = current_block.GetLocalInfo (Name);
2738 if (vi != null){
2739 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2741 if (right_side != null) {
2742 e = e.ResolveLValue (ec, right_side);
2743 } else {
2744 if (intermediate) {
2745 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
2746 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2748 } else {
2749 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2753 if (targs != null && e != null)
2754 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2756 return e;
2759 e = current_block.Toplevel.GetParameterReference (Name, loc);
2760 if (e != null) {
2761 if (right_side != null)
2762 e = e.ResolveLValue (ec, right_side);
2763 else
2764 e = e.Resolve (ec);
2766 if (targs != null && e != null)
2767 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2769 return e;
2774 // Stage 2: Lookup members
2777 Type almost_matched_type = null;
2778 IList<MemberInfo> almost_matched = null;
2779 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2780 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2781 if (e != null) {
2782 PropertyExpr pe = e as PropertyExpr;
2783 if (pe != null) {
2784 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2786 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2787 // it doesn't know which accessor to check permissions against
2788 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2789 break;
2790 } else if (e is EventExpr) {
2791 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2792 break;
2793 } else if (targs != null && e is TypeExpression) {
2794 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2795 break;
2796 } else {
2797 break;
2799 e = null;
2802 if (almost_matched == null && almost_matched_members.Count > 0) {
2803 almost_matched_type = lookup_ds;
2804 almost_matched = new List<MemberInfo>(almost_matched_members);
2808 if (e == null) {
2809 if (almost_matched == null && almost_matched_members.Count > 0) {
2810 almost_matched_type = ec.CurrentType;
2811 almost_matched = new List<MemberInfo> (almost_matched_members);
2813 e = ResolveAsTypeStep (ec, true);
2816 if (e == null) {
2817 if (current_block != null) {
2818 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2819 if (ikv != null) {
2820 LocalInfo li = ikv as LocalInfo;
2821 // Supress CS0219 warning
2822 if (li != null)
2823 li.Used = true;
2825 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2826 return null;
2830 if (RootContext.EvalMode){
2831 FieldInfo fi = Evaluator.LookupField (Name);
2832 if (fi != null)
2833 return new FieldExpr (Import.CreateField (fi), loc).Resolve (ec);
2836 if (almost_matched != null)
2837 almost_matched_members = almost_matched;
2838 if (almost_matched_type == null)
2839 almost_matched_type = ec.CurrentType;
2841 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2842 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2843 type_name, AllMemberTypes, AllBindingFlags);
2846 if (e is MemberExpr) {
2847 MemberExpr me = (MemberExpr) e;
2849 Expression left;
2850 if (me.IsInstance) {
2851 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2853 // Note that an MemberExpr can be both IsInstance and IsStatic.
2854 // An unresolved MethodGroupExpr can contain both kinds of methods
2855 // and each predicate is true if the MethodGroupExpr contains
2856 // at least one of that kind of method.
2859 if (!me.IsStatic &&
2860 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2861 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2862 return null;
2866 // Pass the buck to MemberAccess and Invocation.
2868 left = EmptyExpression.Null;
2869 } else {
2870 left = ec.GetThis (loc);
2872 } else {
2873 left = new TypeExpression (ec.CurrentType, loc);
2876 me = me.ResolveMemberAccess (ec, left, loc, null);
2877 if (me == null)
2878 return null;
2880 if (targs != null) {
2881 if (!targs.Resolve (ec))
2882 return null;
2884 me.SetTypeArguments (ec, targs);
2887 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2888 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2889 me.InstanceExpression.Type != me.DeclaringType &&
2890 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2891 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2892 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2893 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2894 return null;
2897 return (right_side != null)
2898 ? me.DoResolveLValue (ec, right_side)
2899 : me.Resolve (ec);
2902 return e;
2906 /// <summary>
2907 /// Represents a namespace or a type. The name of the class was inspired by
2908 /// section 10.8.1 (Fully Qualified Names).
2909 /// </summary>
2910 public abstract class FullNamedExpression : Expression
2912 protected override void CloneTo (CloneContext clonectx, Expression target)
2914 // Do nothing, most unresolved type expressions cannot be
2915 // resolved to different type
2918 public override Expression CreateExpressionTree (ResolveContext ec)
2920 throw new NotSupportedException ("ET");
2923 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2925 throw new NotSupportedException ();
2928 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2930 return this;
2933 public override void Emit (EmitContext ec)
2935 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2936 GetSignatureForError ());
2940 /// <summary>
2941 /// Expression that evaluates to a type
2942 /// </summary>
2943 public abstract class TypeExpr : FullNamedExpression {
2944 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2946 TypeExpr t = DoResolveAsTypeStep (ec);
2947 if (t == null)
2948 return null;
2950 eclass = ExprClass.Type;
2951 return t;
2954 protected override Expression DoResolve (ResolveContext ec)
2956 return ResolveAsTypeTerminal (ec, false);
2959 public virtual bool CheckAccessLevel (IMemberContext mc)
2961 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2964 public virtual bool IsClass {
2965 get { return Type.IsClass; }
2968 public virtual bool IsValueType {
2969 get { return TypeManager.IsStruct (Type); }
2972 public virtual bool IsInterface {
2973 get { return Type.IsInterface; }
2976 public virtual bool IsSealed {
2977 get { return Type.IsSealed; }
2980 public virtual bool CanInheritFrom ()
2982 if (Type == TypeManager.enum_type ||
2983 (Type == TypeManager.value_type && RootContext.StdLib) ||
2984 Type == TypeManager.multicast_delegate_type ||
2985 Type == TypeManager.delegate_type ||
2986 Type == TypeManager.array_type)
2987 return false;
2989 return true;
2992 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2994 public override bool Equals (object obj)
2996 TypeExpr tobj = obj as TypeExpr;
2997 if (tobj == null)
2998 return false;
3000 return Type == tobj.Type;
3003 public override int GetHashCode ()
3005 return Type.GetHashCode ();
3008 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3010 type = storey.MutateType (type);
3014 /// <summary>
3015 /// Fully resolved Expression that already evaluated to a type
3016 /// </summary>
3017 public class TypeExpression : TypeExpr {
3018 public TypeExpression (Type t, Location l)
3020 Type = t;
3021 eclass = ExprClass.Type;
3022 loc = l;
3025 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3027 return this;
3030 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3032 return this;
3037 // Used to create types from a fully qualified name. These are just used
3038 // by the parser to setup the core types.
3040 public sealed class TypeLookupExpression : TypeExpr {
3041 readonly string ns_name;
3042 readonly string name;
3044 public TypeLookupExpression (string ns, string name)
3046 this.name = name;
3047 this.ns_name = ns;
3048 eclass = ExprClass.Type;
3051 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3054 // It's null only during mscorlib bootstrap when DefineType
3055 // nees to resolve base type of same type
3057 // For instance struct Char : IComparable<char>
3059 // TODO: it could be removed when Resolve starts to use
3060 // DeclSpace instead of Type
3062 if (type == null) {
3063 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3064 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3065 if (fne != null)
3066 type = fne.Type;
3069 return this;
3072 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3074 return this;
3077 public override string GetSignatureForError ()
3079 if (type == null)
3080 return TypeManager.CSharpName (ns_name + "." + name, null);
3082 return base.GetSignatureForError ();
3086 /// <summary>
3087 /// This class denotes an expression which evaluates to a member
3088 /// of a struct or a class.
3089 /// </summary>
3090 public abstract class MemberExpr : Expression
3092 protected bool is_base;
3094 /// <summary>
3095 /// The name of this member.
3096 /// </summary>
3097 public abstract string Name {
3098 get;
3102 // When base.member is used
3104 public bool IsBase {
3105 get { return is_base; }
3106 set { is_base = value; }
3109 /// <summary>
3110 /// Whether this is an instance member.
3111 /// </summary>
3112 public abstract bool IsInstance {
3113 get;
3116 /// <summary>
3117 /// Whether this is a static member.
3118 /// </summary>
3119 public abstract bool IsStatic {
3120 get;
3123 /// <summary>
3124 /// The type which declares this member.
3125 /// </summary>
3126 public abstract Type DeclaringType {
3127 get;
3130 /// <summary>
3131 /// The instance expression associated with this member, if it's a
3132 /// non-static member.
3133 /// </summary>
3134 public Expression InstanceExpression;
3136 public static void error176 (ResolveContext ec, Location loc, string name)
3138 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3139 "with an instance reference, qualify it with a type name instead", name);
3142 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3144 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3147 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3149 if (InstanceExpression != null)
3150 InstanceExpression.MutateHoistedGenericType (storey);
3153 // TODO: possible optimalization
3154 // Cache resolved constant result in FieldBuilder <-> expression map
3155 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3156 SimpleName original)
3159 // Precondition:
3160 // original == null || original.Resolve (...) ==> left
3163 if (left is TypeExpr) {
3164 left = left.ResolveAsBaseTerminal (ec, false);
3165 if (left == null)
3166 return null;
3168 // TODO: Same problem as in class.cs, TypeTerminal does not
3169 // always do all necessary checks
3170 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3171 if (oa != null && !ec.IsObsolete) {
3172 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3175 GenericTypeExpr ct = left as GenericTypeExpr;
3176 if (ct != null && !ct.CheckConstraints (ec))
3177 return null;
3180 if (!IsStatic) {
3181 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3182 return null;
3185 return this;
3188 if (!IsInstance) {
3189 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3190 return this;
3192 return ResolveExtensionMemberAccess (ec, left);
3195 InstanceExpression = left;
3196 return this;
3199 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3201 error176 (ec, loc, GetSignatureForError ());
3202 return this;
3205 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3207 if (IsStatic)
3208 return;
3210 if (InstanceExpression == EmptyExpression.Null) {
3211 // FIXME: This should not be here at all
3212 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3213 return;
3216 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3217 if (InstanceExpression is IMemoryLocation) {
3218 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3219 } else {
3220 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3221 InstanceExpression.Emit (ec);
3222 t.Store (ec);
3223 t.AddressOf (ec, AddressOp.Store);
3225 } else
3226 InstanceExpression.Emit (ec);
3228 if (prepare_for_load)
3229 ec.ig.Emit (OpCodes.Dup);
3232 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3234 // TODO: need to get correct member type
3235 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3236 GetSignatureForError ());
3240 ///
3241 /// Represents group of extension methods
3242 ///
3243 public class ExtensionMethodGroupExpr : MethodGroupExpr
3245 readonly NamespaceEntry namespace_entry;
3246 public Expression ExtensionExpression;
3247 Argument extension_argument;
3249 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, Type extensionType, Location l)
3250 : base (list, extensionType, l)
3252 this.namespace_entry = n;
3255 public override bool IsStatic {
3256 get { return true; }
3259 public bool IsTopLevel {
3260 get { return namespace_entry == null; }
3263 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3265 extension_argument.Expr.MutateHoistedGenericType (storey);
3266 base.MutateHoistedGenericType (storey);
3269 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3271 if (arguments == null)
3272 arguments = new Arguments (1);
3274 arguments.Insert (0, new Argument (ExtensionExpression));
3275 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3277 // Store resolved argument and restore original arguments
3278 if (mg != null)
3279 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3280 else
3281 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3283 return mg;
3286 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3288 // Use normal resolve rules
3289 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3290 if (mg != null)
3291 return mg;
3293 if (ns == null)
3294 return null;
3296 // Search continues
3297 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3298 if (e == null)
3299 return base.OverloadResolve (ec, ref arguments, false, loc);
3301 e.ExtensionExpression = ExtensionExpression;
3302 e.SetTypeArguments (ec, type_arguments);
3303 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3307 /// <summary>
3308 /// MethodGroupExpr represents a group of method candidates which
3309 /// can be resolved to the best method overload
3310 /// </summary>
3311 public class MethodGroupExpr : MemberExpr
3313 public interface IErrorHandler
3315 bool AmbiguousCall (ResolveContext ec, MethodSpec ambiguous);
3316 bool NoExactMatch (ResolveContext ec, MethodSpec method);
3319 public IErrorHandler CustomErrorHandler;
3320 public MethodSpec [] Methods;
3321 MethodSpec best_candidate;
3322 // TODO: make private
3323 public TypeArguments type_arguments;
3324 bool identical_type_name;
3325 bool has_inaccessible_candidates_only;
3326 Type delegate_type;
3327 Type queried_type;
3329 public MethodGroupExpr (MethodSpec [] mi, Type type, Location l)
3330 : this (type, l)
3332 Methods = new MethodSpec[mi.Length];
3333 mi.CopyTo (Methods, 0);
3336 public MethodGroupExpr (MethodSpec[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3337 : this (mi, type, l)
3339 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3342 public MethodGroupExpr (List<MethodSpec> list, Type type, Location l)
3343 : this (type, l)
3345 try {
3346 Methods = list.ToArray ();
3347 } catch {
3348 //foreach (MemberInfo m in list){
3349 // if (!(m is MethodBase)){
3350 // Console.WriteLine ("Name " + m.Name);
3351 // Console.WriteLine ("Found a: " + m.GetType ().FullName);
3352 // }
3354 throw;
3360 protected MethodGroupExpr (Type type, Location loc)
3362 this.loc = loc;
3363 eclass = ExprClass.MethodGroup;
3364 this.type = InternalType.MethodGroup;
3365 queried_type = type;
3368 public override Type DeclaringType {
3369 get {
3370 return queried_type;
3374 public MethodSpec BestCandidate {
3375 get {
3376 return best_candidate;
3380 public Type DelegateType {
3381 set {
3382 delegate_type = value;
3386 public bool IdenticalTypeName {
3387 get {
3388 return identical_type_name;
3392 public override string GetSignatureForError ()
3394 if (best_candidate != null)
3395 return TypeManager.CSharpSignature (best_candidate.MetaInfo);
3397 return TypeManager.CSharpSignature (Methods [0].MetaInfo);
3400 public override string Name {
3401 get {
3402 return Methods [0].Name;
3406 public override bool IsInstance {
3407 get {
3408 if (best_candidate != null)
3409 return !best_candidate.IsStatic;
3411 foreach (var mb in Methods)
3412 if (!mb.IsStatic)
3413 return true;
3415 return false;
3419 public override bool IsStatic {
3420 get {
3421 if (best_candidate != null)
3422 return best_candidate.IsStatic;
3424 foreach (var mb in Methods)
3425 if (mb.IsStatic)
3426 return true;
3428 return false;
3432 public static explicit operator MethodSpec (MethodGroupExpr mg)
3434 return mg.best_candidate;
3438 // 7.4.3.3 Better conversion from expression
3439 // Returns : 1 if a->p is better,
3440 // 2 if a->q is better,
3441 // 0 if neither is better
3443 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3445 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3446 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3448 // Uwrap delegate from Expression<T>
3450 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3451 p = TypeManager.GetTypeArguments (p) [0];
3453 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3454 q = TypeManager.GetTypeArguments (q) [0];
3457 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3458 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3459 if (p == TypeManager.void_type && q != TypeManager.void_type)
3460 return 2;
3461 if (q == TypeManager.void_type && p != TypeManager.void_type)
3462 return 1;
3463 } else {
3464 if (argument_type == p)
3465 return 1;
3467 if (argument_type == q)
3468 return 2;
3471 return BetterTypeConversion (ec, p, q);
3475 // 7.4.3.4 Better conversion from type
3477 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3479 if (p == null || q == null)
3480 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3482 if (p == TypeManager.int32_type) {
3483 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3484 return 1;
3485 } else if (p == TypeManager.int64_type) {
3486 if (q == TypeManager.uint64_type)
3487 return 1;
3488 } else if (p == TypeManager.sbyte_type) {
3489 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3490 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3491 return 1;
3492 } else if (p == TypeManager.short_type) {
3493 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3494 q == TypeManager.uint64_type)
3495 return 1;
3496 } else if (p == InternalType.Dynamic) {
3497 if (q == TypeManager.object_type)
3498 return 2;
3501 if (q == TypeManager.int32_type) {
3502 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3503 return 2;
3504 } if (q == TypeManager.int64_type) {
3505 if (p == TypeManager.uint64_type)
3506 return 2;
3507 } else if (q == TypeManager.sbyte_type) {
3508 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3509 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3510 return 2;
3511 } if (q == TypeManager.short_type) {
3512 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3513 p == TypeManager.uint64_type)
3514 return 2;
3515 } else if (q == InternalType.Dynamic) {
3516 if (p == TypeManager.object_type)
3517 return 1;
3520 // TODO: this is expensive
3521 Expression p_tmp = new EmptyExpression (p);
3522 Expression q_tmp = new EmptyExpression (q);
3524 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3525 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3527 if (p_to_q && !q_to_p)
3528 return 1;
3530 if (q_to_p && !p_to_q)
3531 return 2;
3533 return 0;
3536 /// <summary>
3537 /// Determines "Better function" between candidate
3538 /// and the current best match
3539 /// </summary>
3540 /// <remarks>
3541 /// Returns a boolean indicating :
3542 /// false if candidate ain't better
3543 /// true if candidate is better than the current best match
3544 /// </remarks>
3545 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3546 MethodSpec candidate, bool candidate_params,
3547 MethodSpec best, bool best_params)
3549 AParametersCollection candidate_pd = candidate.Parameters;
3550 AParametersCollection best_pd = best.Parameters;
3552 bool better_at_least_one = false;
3553 bool same = true;
3554 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3556 Argument a = args [j];
3558 // Provided default argument value is never better
3559 if (a.IsDefaultArgument && candidate_params == best_params)
3560 return false;
3562 Type ct = candidate_pd.Types [c_idx];
3563 Type bt = best_pd.Types [b_idx];
3565 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3567 ct = TypeManager.GetElementType (ct);
3568 --c_idx;
3571 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3573 bt = TypeManager.GetElementType (bt);
3574 --b_idx;
3577 if (TypeManager.IsEqual (ct, bt))
3578 continue;
3580 same = false;
3581 int result = BetterExpressionConversion (ec, a, ct, bt);
3583 // for each argument, the conversion to 'ct' should be no worse than
3584 // the conversion to 'bt'.
3585 if (result == 2)
3586 return false;
3588 // for at least one argument, the conversion to 'ct' should be better than
3589 // the conversion to 'bt'.
3590 if (result != 0)
3591 better_at_least_one = true;
3594 if (better_at_least_one)
3595 return true;
3598 // This handles the case
3600 // Add (float f1, float f2, float f3);
3601 // Add (params decimal [] foo);
3603 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3604 // first candidate would've chosen as better.
3606 if (!same)
3607 return false;
3610 // The two methods have equal parameter types. Now apply tie-breaking rules
3612 if (best.IsGenericMethod) {
3613 if (!candidate.IsGenericMethod)
3614 return true;
3615 } else if (candidate.IsGenericMethod) {
3616 return false;
3620 // This handles the following cases:
3622 // Trim () is better than Trim (params char[] chars)
3623 // Concat (string s1, string s2, string s3) is better than
3624 // Concat (string s1, params string [] srest)
3625 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3627 if (!candidate_params && best_params)
3628 return true;
3629 if (candidate_params && !best_params)
3630 return false;
3632 int candidate_param_count = candidate_pd.Count;
3633 int best_param_count = best_pd.Count;
3635 if (candidate_param_count != best_param_count)
3636 // can only happen if (candidate_params && best_params)
3637 return candidate_param_count > best_param_count && best_pd.HasParams;
3640 // now, both methods have the same number of parameters, and the parameters have the same types
3641 // Pick the "more specific" signature
3644 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3645 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3647 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3648 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3650 bool specific_at_least_once = false;
3651 for (int j = 0; j < candidate_param_count; ++j)
3653 Type ct = orig_candidate_pd.Types [j];
3654 Type bt = orig_best_pd.Types [j];
3655 if (ct.Equals (bt))
3656 continue;
3657 Type specific = MoreSpecific (ct, bt);
3658 if (specific == bt)
3659 return false;
3660 if (specific == ct)
3661 specific_at_least_once = true;
3664 if (specific_at_least_once)
3665 return true;
3667 // FIXME: handle lifted operators
3668 // ...
3670 return false;
3673 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3675 if (!IsStatic)
3676 return base.ResolveExtensionMemberAccess (ec, left);
3679 // When left side is an expression and at least one candidate method is
3680 // static, it can be extension method
3682 InstanceExpression = left;
3683 return this;
3686 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3687 SimpleName original)
3689 if (!(left is TypeExpr) &&
3690 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3691 identical_type_name = true;
3693 return base.ResolveMemberAccess (ec, left, loc, original);
3696 public override Expression CreateExpressionTree (ResolveContext ec)
3698 if (best_candidate == null) {
3699 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3700 return null;
3703 IMethodData md = TypeManager.GetMethod (best_candidate.MetaInfo);
3704 if (md != null && md.IsExcluded ())
3705 ec.Report.Error (765, loc,
3706 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3708 return new TypeOfMethod (best_candidate, loc);
3711 protected override Expression DoResolve (ResolveContext ec)
3713 this.eclass = ExprClass.MethodGroup;
3715 if (InstanceExpression != null) {
3716 InstanceExpression = InstanceExpression.Resolve (ec);
3717 if (InstanceExpression == null)
3718 return null;
3721 return this;
3724 public void ReportUsageError (ResolveContext ec)
3726 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3727 Name + "()' is referenced without parentheses");
3730 override public void Emit (EmitContext ec)
3732 throw new NotSupportedException ();
3733 // ReportUsageError ();
3736 public void EmitCall (EmitContext ec, Arguments arguments)
3738 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3741 void Error_AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
3743 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3744 return;
3746 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
3747 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3748 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate.MetaInfo));
3751 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodSpec method,
3752 Argument a, AParametersCollection expected_par, Type paramType)
3754 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3756 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3757 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3758 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3759 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3760 TypeManager.CSharpSignature (method));
3761 return;
3763 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3764 TypeManager.CSharpSignature (method));
3765 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3766 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3767 TypeManager.CSharpName (method.DeclaringType));
3768 } else {
3769 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3770 if (emg != null) {
3771 ec.Report.Error (1928, loc,
3772 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3773 emg.ExtensionExpression.GetSignatureForError (),
3774 emg.Name, TypeManager.CSharpSignature (method));
3775 } else {
3776 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3777 TypeManager.CSharpSignature (method));
3781 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3783 string index = (idx + 1).ToString ();
3784 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3785 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3786 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3787 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3788 index, Parameter.GetModifierSignature (a.Modifier));
3789 else
3790 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3791 index, Parameter.GetModifierSignature (mod));
3792 } else {
3793 string p1 = a.GetSignatureForError ();
3794 string p2 = TypeManager.CSharpName (paramType);
3796 if (p1 == p2) {
3797 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3798 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3799 ec.Report.SymbolRelatedToPreviousError (paramType);
3802 if (idx == 0 && emg != null) {
3803 ec.Report.Error (1929, loc,
3804 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3805 } else {
3806 ec.Report.Error (1503, loc,
3807 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3812 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3814 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3815 Name, TypeManager.CSharpName (target));
3818 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3820 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3821 Name, arg_count.ToString ());
3824 protected virtual int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
3826 return parameters.Count;
3829 public static bool IsAncestralType (Type first_type, Type second_type)
3831 return first_type != second_type &&
3832 (TypeManager.IsSubclassOf (second_type, first_type) ||
3833 TypeManager.ImplementsInterface (second_type, first_type));
3837 /// Determines if the candidate method is applicable (section 14.4.2.1)
3838 /// to the given set of arguments
3839 /// A return value rates candidate method compatibility,
3840 /// 0 = the best, int.MaxValue = the worst
3842 public int IsApplicable (ResolveContext ec,
3843 ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form)
3845 var candidate = method;
3847 AParametersCollection pd = candidate.Parameters;
3848 int param_count = GetApplicableParametersCount (candidate, pd);
3849 int optional_count = 0;
3851 if (arg_count != param_count) {
3852 for (int i = 0; i < pd.Count; ++i) {
3853 if (pd.FixedParameters [i].HasDefaultValue) {
3854 optional_count = pd.Count - i;
3855 break;
3859 int args_gap = System.Math.Abs (arg_count - param_count);
3860 if (optional_count != 0) {
3861 if (args_gap > optional_count)
3862 return int.MaxValue - 10000 + args_gap - optional_count;
3864 // Readjust expected number when params used
3865 if (pd.HasParams) {
3866 optional_count--;
3867 if (arg_count < param_count)
3868 param_count--;
3869 } else if (arg_count > param_count) {
3870 return int.MaxValue - 10000 + args_gap;
3872 } else if (arg_count != param_count) {
3873 if (!pd.HasParams)
3874 return int.MaxValue - 10000 + args_gap;
3875 if (arg_count < param_count - 1)
3876 return int.MaxValue - 10000 + args_gap;
3879 // Initialize expanded form of a method with 1 params parameter
3880 params_expanded_form = param_count == 1 && pd.HasParams;
3882 // Resize to fit optional arguments
3883 if (optional_count != 0) {
3884 Arguments resized;
3885 if (arguments == null) {
3886 resized = new Arguments (optional_count);
3887 } else {
3888 resized = new Arguments (param_count);
3889 resized.AddRange (arguments);
3892 for (int i = arg_count; i < param_count; ++i)
3893 resized.Add (null);
3894 arguments = resized;
3898 if (arg_count > 0) {
3900 // Shuffle named arguments to the right positions if there are any
3902 if (arguments [arg_count - 1] is NamedArgument) {
3903 arg_count = arguments.Count;
3905 for (int i = 0; i < arg_count; ++i) {
3906 bool arg_moved = false;
3907 while (true) {
3908 NamedArgument na = arguments[i] as NamedArgument;
3909 if (na == null)
3910 break;
3912 int index = pd.GetParameterIndexByName (na.Name);
3914 // Named parameter not found or already reordered
3915 if (index <= i)
3916 break;
3918 // When using parameters which should not be available to the user
3919 if (index >= param_count)
3920 break;
3922 if (!arg_moved) {
3923 arguments.MarkReorderedArgument (na);
3924 arg_moved = true;
3927 Argument temp = arguments[index];
3928 arguments[index] = arguments[i];
3929 arguments[i] = temp;
3931 if (temp == null)
3932 break;
3935 } else {
3936 arg_count = arguments.Count;
3938 } else if (arguments != null) {
3939 arg_count = arguments.Count;
3943 // 1. Handle generic method using type arguments when specified or type inference
3945 if (candidate.IsGenericMethod) {
3946 if (type_arguments != null) {
3947 Type [] g_args = candidate.GetGenericArguments ();
3948 if (g_args.Length != type_arguments.Count)
3949 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args.Length);
3951 method = candidate.Inflate (type_arguments.Arguments);
3952 candidate = method;
3953 pd = candidate.Parameters;
3954 } else {
3955 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3956 if (score != 0)
3957 return score - 20000;
3959 if (TypeManager.IsGenericMethodDefinition (candidate.MetaInfo))
3960 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3961 TypeManager.CSharpSignature (candidate.MetaInfo));
3963 pd = candidate.Parameters;
3965 } else {
3966 if (type_arguments != null)
3967 return int.MaxValue - 15000;
3971 // 2. Each argument has to be implicitly convertible to method parameter
3973 method = candidate;
3974 Parameter.Modifier p_mod = 0;
3975 Type pt = null;
3976 for (int i = 0; i < arg_count; i++) {
3977 Argument a = arguments [i];
3978 if (a == null) {
3979 if (!pd.FixedParameters [i].HasDefaultValue)
3980 throw new InternalErrorException ();
3982 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3983 if (e == null)
3984 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3986 arguments [i] = new Argument (e, Argument.AType.Default);
3987 continue;
3990 if (p_mod != Parameter.Modifier.PARAMS) {
3991 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3992 pt = pd.Types [i];
3993 } else {
3994 params_expanded_form = true;
3997 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3998 int score = 1;
3999 if (!params_expanded_form)
4000 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4002 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4003 // It can be applicable in expanded form
4004 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4005 if (score == 0)
4006 params_expanded_form = true;
4009 if (score != 0) {
4010 if (params_expanded_form)
4011 ++score;
4012 return (arg_count - i) * 2 + score;
4016 if (arg_count != param_count)
4017 params_expanded_form = true;
4019 return 0;
4022 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4025 // Types have to be identical when ref or out modifer is used
4027 if (arg_mod != 0 || param_mod != 0) {
4028 if (TypeManager.HasElementType (parameter))
4029 parameter = TypeManager.GetElementType (parameter);
4031 Type a_type = argument.Type;
4032 if (TypeManager.HasElementType (a_type))
4033 a_type = TypeManager.GetElementType (a_type);
4035 if (a_type != parameter) {
4036 if (TypeManager.IsDynamicType (a_type))
4037 return 0;
4039 return 2;
4041 } else {
4042 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4043 if (TypeManager.IsDynamicType (argument.Type))
4044 return 0;
4046 return 2;
4050 if (arg_mod != param_mod)
4051 return 1;
4053 return 0;
4056 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4058 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4059 return false;
4061 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4062 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4064 if (cand_pd.Count != base_pd.Count)
4065 return false;
4067 for (int j = 0; j < cand_pd.Count; ++j)
4069 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4070 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4071 Type ct = cand_pd.Types [j];
4072 Type bt = base_pd.Types [j];
4074 if (cm != bm || ct != bt)
4075 return false;
4078 return true;
4081 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4083 if (mg1 == null) {
4084 if (mg2 == null)
4085 return null;
4086 return mg2;
4089 if (mg2 == null)
4090 return mg1;
4092 var all = new List<MethodSpec> (mg1.Methods);
4093 foreach (var m in mg2.Methods){
4094 if (!TypeManager.ArrayContainsMethod (mg1.Methods.Select (l => l.MetaInfo).ToArray (), m.MetaInfo, false))
4095 all.Add (m);
4098 return new MethodGroupExpr (all, null, loc);
4101 static Type MoreSpecific (Type p, Type q)
4103 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4104 return q;
4105 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4106 return p;
4108 if (TypeManager.HasElementType (p))
4110 Type pe = TypeManager.GetElementType (p);
4111 Type qe = TypeManager.GetElementType (q);
4112 Type specific = MoreSpecific (pe, qe);
4113 if (specific == pe)
4114 return p;
4115 if (specific == qe)
4116 return q;
4118 else if (TypeManager.IsGenericType (p))
4120 Type[] pargs = TypeManager.GetTypeArguments (p);
4121 Type[] qargs = TypeManager.GetTypeArguments (q);
4123 bool p_specific_at_least_once = false;
4124 bool q_specific_at_least_once = false;
4126 for (int i = 0; i < pargs.Length; i++)
4128 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4129 if (specific == pargs [i])
4130 p_specific_at_least_once = true;
4131 if (specific == qargs [i])
4132 q_specific_at_least_once = true;
4135 if (p_specific_at_least_once && !q_specific_at_least_once)
4136 return p;
4137 if (!p_specific_at_least_once && q_specific_at_least_once)
4138 return q;
4141 return null;
4144 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4146 base.MutateHoistedGenericType (storey);
4148 if (best_candidate.IsConstructor) {
4149 storey.MutateConstructor (best_candidate);
4150 } else {
4151 storey.MutateGenericMethod (best_candidate);
4155 /// <summary>
4156 /// Find the Applicable Function Members (7.4.2.1)
4158 /// me: Method Group expression with the members to select.
4159 /// it might contain constructors or methods (or anything
4160 /// that maps to a method).
4162 /// Arguments: ArrayList containing resolved Argument objects.
4164 /// loc: The location if we want an error to be reported, or a Null
4165 /// location for "probing" purposes.
4167 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4168 /// that is the best match of me on Arguments.
4170 /// </summary>
4171 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4172 bool may_fail, Location loc)
4174 bool method_params = false;
4175 Type applicable_type = null;
4176 var candidates = new List<MethodSpec> (2);
4177 List<MethodSpec> candidate_overrides = null;
4180 // Used to keep a map between the candidate
4181 // and whether it is being considered in its
4182 // normal or expanded form
4184 // false is normal form, true is expanded form
4186 Dictionary<MethodSpec, MethodSpec> candidate_to_form = null;
4187 Dictionary<MethodSpec, Arguments> candidates_expanded = null;
4188 Arguments candidate_args = Arguments;
4190 int arg_count = Arguments != null ? Arguments.Count : 0;
4192 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4193 if (!may_fail)
4194 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4195 return null;
4198 int nmethods = Methods.Length;
4200 if (!IsBase) {
4202 // Methods marked 'override' don't take part in 'applicable_type'
4203 // computation, nor in the actual overload resolution.
4204 // However, they still need to be emitted instead of a base virtual method.
4205 // So, we salt them away into the 'candidate_overrides' array.
4207 // In case of reflected methods, we replace each overriding method with
4208 // its corresponding base virtual method. This is to improve compatibility
4209 // with non-C# libraries which change the visibility of overrides (#75636)
4211 int j = 0;
4212 MethodBase mb = null;
4213 for (int i = 0; i < Methods.Length; ++i) {
4214 var m = Methods [i];
4215 mb = m.MetaInfo;
4216 if (TypeManager.IsOverride (m)) {
4217 if (candidate_overrides == null)
4218 candidate_overrides = new List<MethodSpec> ();
4219 candidate_overrides.Add (m);
4220 mb = TypeManager.TryGetBaseDefinition (mb);
4221 if (mb != null && Array.Exists (Methods, l => l.MetaInfo == mb))
4222 continue;
4224 if (mb != null)
4225 Methods [j++] = Import.CreateMethod (mb);
4227 nmethods = j;
4231 // Enable message recording, it's used mainly by lambda expressions
4233 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4234 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4237 // First we construct the set of applicable methods
4239 bool is_sorted = true;
4240 int best_candidate_rate = int.MaxValue;
4241 for (int i = 0; i < nmethods; i++) {
4242 Type decl_type = Methods [i].DeclaringType;
4245 // If we have already found an applicable method
4246 // we eliminate all base types (Section 14.5.5.1)
4248 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4249 continue;
4252 // Check if candidate is applicable (section 14.4.2.1)
4254 bool params_expanded_form = false;
4255 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4257 if (candidate_rate < best_candidate_rate) {
4258 best_candidate_rate = candidate_rate;
4259 best_candidate = Methods [i];
4262 if (params_expanded_form) {
4263 if (candidate_to_form == null)
4264 candidate_to_form = new Dictionary<MethodSpec, MethodSpec> (4, ReferenceEquality<MethodSpec>.Default);
4265 var candidate = Methods [i];
4266 candidate_to_form [candidate] = candidate;
4269 if (candidate_args != Arguments) {
4270 if (candidates_expanded == null)
4271 candidates_expanded = new Dictionary<MethodSpec, Arguments> (4, ReferenceEquality<MethodSpec>.Default);
4273 candidates_expanded.Add (Methods [i], candidate_args);
4274 candidate_args = Arguments;
4277 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4278 if (msg_recorder != null)
4279 msg_recorder.EndSession ();
4280 continue;
4283 msg_recorder = null;
4284 candidates.Add (Methods [i]);
4286 if (applicable_type == null)
4287 applicable_type = decl_type;
4288 else if (applicable_type != decl_type) {
4289 is_sorted = false;
4290 if (IsAncestralType (applicable_type, decl_type))
4291 applicable_type = decl_type;
4295 ec.Report.SetPrinter (prev_recorder);
4296 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4297 if (!may_fail)
4298 msg_recorder.Merge (prev_recorder);
4300 return null;
4303 int candidate_top = candidates.Count;
4305 if (applicable_type == null) {
4307 // When we found a top level method which does not match and it's
4308 // not an extension method. We start extension methods lookup from here
4310 if (InstanceExpression != null) {
4311 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4312 if (ex_method_lookup != null) {
4313 ex_method_lookup.ExtensionExpression = InstanceExpression;
4314 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4315 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4319 if (may_fail)
4320 return null;
4323 // Okay so we have failed to find exact match so we
4324 // return error info about the closest match
4326 if (best_candidate != null) {
4327 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4328 return null;
4330 if (NoExactMatch (ec, ref Arguments, candidate_to_form))
4331 return null;
4335 // We failed to find any method with correct argument count
4337 if (Name == ConstructorInfo.ConstructorName) {
4338 ec.Report.SymbolRelatedToPreviousError (queried_type);
4339 ec.Report.Error (1729, loc,
4340 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4341 TypeManager.CSharpName (queried_type), arg_count);
4342 } else {
4343 Error_ArgumentCountWrong (ec, arg_count);
4346 return null;
4349 if (arg_count != 0 && Arguments.HasDynamic) {
4350 best_candidate = null;
4351 return this;
4354 if (!is_sorted) {
4356 // At this point, applicable_type is _one_ of the most derived types
4357 // in the set of types containing the methods in this MethodGroup.
4358 // Filter the candidates so that they only contain methods from the
4359 // most derived types.
4362 int finalized = 0; // Number of finalized candidates
4364 do {
4365 // Invariant: applicable_type is a most derived type
4367 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4368 // eliminating all it's base types. At the same time, we'll also move
4369 // every unrelated type to the end of the array, and pick the next
4370 // 'applicable_type'.
4372 Type next_applicable_type = null;
4373 int j = finalized; // where to put the next finalized candidate
4374 int k = finalized; // where to put the next undiscarded candidate
4375 for (int i = finalized; i < candidate_top; ++i) {
4376 var candidate = candidates [i];
4377 Type decl_type = candidate.DeclaringType;
4379 if (decl_type == applicable_type) {
4380 candidates [k++] = candidates [j];
4381 candidates [j++] = candidates [i];
4382 continue;
4385 if (IsAncestralType (decl_type, applicable_type))
4386 continue;
4388 if (next_applicable_type != null &&
4389 IsAncestralType (decl_type, next_applicable_type))
4390 continue;
4392 candidates [k++] = candidates [i];
4394 if (next_applicable_type == null ||
4395 IsAncestralType (next_applicable_type, decl_type))
4396 next_applicable_type = decl_type;
4399 applicable_type = next_applicable_type;
4400 finalized = j;
4401 candidate_top = k;
4402 } while (applicable_type != null);
4406 // Now we actually find the best method
4409 best_candidate = candidates [0];
4410 method_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4413 // TODO: Broken inverse order of candidates logic does not work with optional
4414 // parameters used for method overrides and I am not going to fix it for SRE
4416 if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) {
4417 candidate_args = candidates_expanded [best_candidate];
4418 arg_count = candidate_args.Count;
4421 for (int ix = 1; ix < candidate_top; ix++) {
4422 var candidate = candidates [ix];
4424 if (candidate.MetaInfo == best_candidate.MetaInfo)
4425 continue;
4427 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4429 if (BetterFunction (ec, candidate_args, arg_count,
4430 candidate, cand_params,
4431 best_candidate, method_params)) {
4432 best_candidate = candidate;
4433 method_params = cand_params;
4437 // Now check that there are no ambiguities i.e the selected method
4438 // should be better than all the others
4440 MethodSpec ambiguous = null;
4441 for (int ix = 1; ix < candidate_top; ix++) {
4442 var candidate = candidates [ix];
4444 if (candidate.MetaInfo == best_candidate.MetaInfo)
4445 continue;
4447 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4448 if (!BetterFunction (ec, candidate_args, arg_count,
4449 best_candidate, method_params,
4450 candidate, cand_params))
4452 if (!may_fail)
4453 ec.Report.SymbolRelatedToPreviousError (candidate.MetaInfo);
4454 ambiguous = candidate;
4458 if (ambiguous != null) {
4459 Error_AmbiguousCall (ec, ambiguous);
4460 return this;
4464 // If the method is a virtual function, pick an override closer to the LHS type.
4466 if (!IsBase && best_candidate.IsVirtual) {
4467 if (TypeManager.IsOverride (best_candidate))
4468 throw new InternalErrorException (
4469 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4471 if (candidate_overrides != null) {
4472 Type[] gen_args = null;
4473 bool gen_override = false;
4474 if (best_candidate.IsGenericMethod)
4475 gen_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4477 foreach (var candidate in candidate_overrides) {
4478 if (candidate.IsGenericMethod) {
4479 if (gen_args == null)
4480 continue;
4482 if (gen_args.Length != TypeManager.GetGenericArguments (candidate.MetaInfo).Length)
4483 continue;
4484 } else {
4485 if (gen_args != null)
4486 continue;
4489 if (IsOverride (candidate.MetaInfo, best_candidate.MetaInfo)) {
4490 gen_override = true;
4491 best_candidate = candidate;
4495 if (gen_override && gen_args != null) {
4496 best_candidate = best_candidate.Inflate (gen_args);
4502 // And now check if the arguments are all
4503 // compatible, perform conversions if
4504 // necessary etc. and return if everything is
4505 // all right
4507 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4508 method_params, may_fail, loc))
4509 return null;
4511 if (best_candidate == null)
4512 return null;
4514 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4515 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4516 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate.MetaInfo, loc))
4517 return null;
4520 // Check ObsoleteAttribute on the best method
4522 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4523 if (oa != null && !ec.IsObsolete)
4524 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4526 IMethodData data = TypeManager.GetMethod (the_method);
4527 if (data != null)
4528 data.SetIsUsed ();
4530 Arguments = candidate_args;
4531 return this;
4534 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, IDictionary<MethodSpec, MethodSpec> candidate_to_form)
4536 AParametersCollection pd = best_candidate.Parameters;
4537 int arg_count = Arguments == null ? 0 : Arguments.Count;
4539 if (arg_count == pd.Count || pd.HasParams) {
4540 if (TypeManager.IsGenericMethodDefinition (best_candidate.MetaInfo)) {
4541 if (type_arguments == null) {
4542 ec.Report.Error (411, loc,
4543 "The type arguments for method `{0}' cannot be inferred from " +
4544 "the usage. Try specifying the type arguments explicitly",
4545 TypeManager.CSharpSignature (best_candidate.MetaInfo));
4546 return true;
4549 Type[] g_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4550 if (type_arguments.Count != g_args.Length) {
4551 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4552 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4553 TypeManager.CSharpSignature (best_candidate.MetaInfo),
4554 g_args.Length.ToString ());
4555 return true;
4557 } else {
4558 if (type_arguments != null && !best_candidate.IsGenericMethod) {
4559 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4560 return true;
4564 if (has_inaccessible_candidates_only) {
4565 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4566 // Although a derived class can access protected members of
4567 // its base class it cannot do so through an instance of the
4568 // base class (CS1540). If the qualifier_type is a base of the
4569 // ec.CurrentType and the lookup succeeds with the latter one,
4570 // then we are in this situation.
4571 Error_CannotAccessProtected (ec, loc, best_candidate.MetaInfo, queried_type, ec.CurrentType);
4572 } else {
4573 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4574 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4578 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4579 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, false, loc))
4580 return true;
4582 if (has_inaccessible_candidates_only)
4583 return true;
4586 return false;
4589 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4591 type_arguments = ta;
4594 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4595 int arg_count, MethodSpec method,
4596 bool chose_params_expanded,
4597 bool may_fail, Location loc)
4599 AParametersCollection pd = method.Parameters;
4600 int param_count = GetApplicableParametersCount (method, pd);
4602 int errors = ec.Report.Errors;
4603 Parameter.Modifier p_mod = 0;
4604 Type pt = null;
4605 int a_idx = 0, a_pos = 0;
4606 Argument a = null;
4607 ArrayInitializer params_initializers = null;
4608 bool has_unsafe_arg = method.ReturnType.IsPointer;
4610 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4611 a = arguments [a_idx];
4612 if (p_mod != Parameter.Modifier.PARAMS) {
4613 p_mod = pd.FixedParameters [a_idx].ModFlags;
4614 pt = pd.Types [a_idx];
4615 has_unsafe_arg |= pt.IsPointer;
4617 if (p_mod == Parameter.Modifier.PARAMS) {
4618 if (chose_params_expanded) {
4619 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4620 pt = TypeManager.GetElementType (pt);
4626 // Types have to be identical when ref or out modifer is used
4628 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4629 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4630 break;
4632 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4633 break;
4635 continue;
4636 } else {
4637 NamedArgument na = a as NamedArgument;
4638 if (na != null) {
4639 int name_index = pd.GetParameterIndexByName (na.Name);
4640 if (name_index < 0 || name_index >= param_count) {
4641 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4642 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4643 ec.Report.Error (1746, na.Location,
4644 "The delegate `{0}' does not contain a parameter named `{1}'",
4645 TypeManager.CSharpName (DeclaringType), na.Name);
4646 } else {
4647 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4648 ec.Report.Error (1739, na.Location,
4649 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4650 TypeManager.CSharpSignature (method.MetaInfo), na.Name);
4652 } else if (arguments[name_index] != a) {
4653 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4654 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4655 else
4656 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4658 ec.Report.Error (1744, na.Location,
4659 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4660 na.Name);
4665 if (TypeManager.IsDynamicType (a.Expr.Type))
4666 continue;
4668 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4669 break;
4671 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4672 if (conv == null)
4673 break;
4676 // Convert params arguments to an array initializer
4678 if (params_initializers != null) {
4679 // we choose to use 'a.Expr' rather than 'conv' so that
4680 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4681 params_initializers.Add (a.Expr);
4682 arguments.RemoveAt (a_idx--);
4683 --arg_count;
4684 continue;
4687 // Update the argument with the implicit conversion
4688 a.Expr = conv;
4691 if (a_idx != arg_count) {
4692 if (!may_fail && ec.Report.Errors == errors) {
4693 if (CustomErrorHandler != null)
4694 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4695 else
4696 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4698 return false;
4702 // Fill not provided arguments required by params modifier
4704 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4705 if (arguments == null)
4706 arguments = new Arguments (1);
4708 pt = pd.Types [param_count - 1];
4709 pt = TypeManager.GetElementType (pt);
4710 has_unsafe_arg |= pt.IsPointer;
4711 params_initializers = new ArrayInitializer (0, loc);
4715 // Append an array argument with all params arguments
4717 if (params_initializers != null) {
4718 arguments.Add (new Argument (
4719 new ArrayCreation (new TypeExpression (pt, loc), "[]", params_initializers, loc).Resolve (ec)));
4720 arg_count++;
4723 if (arg_count < param_count) {
4724 if (!may_fail)
4725 Error_ArgumentCountWrong (ec, arg_count);
4726 return false;
4729 if (has_unsafe_arg && !ec.IsUnsafe) {
4730 if (!may_fail)
4731 UnsafeError (ec, loc);
4732 return false;
4735 return true;
4739 public class ConstantExpr : MemberExpr
4741 ConstSpec constant;
4743 public ConstantExpr (ConstSpec constant, Location loc)
4745 this.constant = constant;
4746 this.loc = loc;
4749 public override string Name {
4750 get { throw new NotImplementedException (); }
4753 public override bool IsInstance {
4754 get { return !IsStatic; }
4757 public override bool IsStatic {
4758 get { return true; }
4761 public override Type DeclaringType {
4762 get { return constant.DeclaringType; }
4765 public override Expression CreateExpressionTree (ResolveContext ec)
4767 throw new NotSupportedException ("ET");
4770 protected override Expression DoResolve (ResolveContext rc)
4772 constant.MemberDefinition.SetIsUsed ();
4774 if (!rc.IsObsolete) {
4775 var oa = constant.GetObsoleteAttribute ();
4776 if (oa != null)
4777 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (constant.MetaInfo), loc, rc.Report);
4780 // Constants are resolved on-demand
4781 var c = constant.Value.Resolve (rc) as Constant;
4783 // Creates reference expression to the constant value
4784 return Constant.CreateConstant (rc, c.Type, c.GetValue (), loc);
4787 public override void Emit (EmitContext ec)
4789 throw new NotSupportedException ();
4792 public override string GetSignatureForError ()
4794 return TypeManager.GetFullNameSignature (constant.MetaInfo);
4798 /// <summary>
4799 /// Fully resolved expression that evaluates to a Field
4800 /// </summary>
4801 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4802 protected FieldSpec spec;
4803 readonly Type constructed_generic_type;
4804 VariableInfo variable_info;
4806 LocalTemporary temp;
4807 bool prepared;
4809 protected FieldExpr (Location l)
4811 loc = l;
4814 public FieldExpr (FieldSpec spec, Location loc)
4816 this.spec = spec;
4817 this.loc = loc;
4819 type = TypeManager.TypeToCoreType (spec.FieldType);
4822 public FieldExpr (FieldBase fi, Location l)
4823 : this (fi.Spec, l)
4825 loc = l;
4828 public FieldExpr (Field fi, Type genericType, Location l)
4829 : this (fi, l)
4831 if (TypeManager.IsGenericTypeDefinition (genericType))
4832 return;
4833 this.constructed_generic_type = genericType;
4836 public override string Name {
4837 get {
4838 return spec.Name;
4842 public override bool IsInstance {
4843 get {
4844 return !spec.IsStatic;
4848 public override bool IsStatic {
4849 get {
4850 return spec.IsStatic;
4854 public FieldSpec Spec {
4855 get {
4856 return spec;
4860 public override Type DeclaringType {
4861 get {
4862 return spec.MetaInfo.DeclaringType;
4866 public override string GetSignatureForError ()
4868 return TypeManager.GetFullNameSignature (spec.MetaInfo);
4871 public VariableInfo VariableInfo {
4872 get {
4873 return variable_info;
4877 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4878 SimpleName original)
4880 FieldInfo fi = TypeManager.GetGenericFieldDefinition (spec.MetaInfo);
4881 Type t = fi.FieldType;
4883 if (t.IsPointer && !ec.IsUnsafe) {
4884 UnsafeError (ec, loc);
4887 return base.ResolveMemberAccess (ec, left, loc, original);
4890 public void SetHasAddressTaken ()
4892 IVariableReference vr = InstanceExpression as IVariableReference;
4893 if (vr != null)
4894 vr.SetHasAddressTaken ();
4897 public override Expression CreateExpressionTree (ResolveContext ec)
4899 Expression instance;
4900 if (InstanceExpression == null) {
4901 instance = new NullLiteral (loc);
4902 } else {
4903 instance = InstanceExpression.CreateExpressionTree (ec);
4906 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4907 instance,
4908 CreateTypeOfExpression ());
4910 return CreateExpressionFactoryCall (ec, "Field", args);
4913 public Expression CreateTypeOfExpression ()
4915 return new TypeOfField (Import.CreateField (GetConstructedFieldInfo ()), loc);
4918 protected override Expression DoResolve (ResolveContext ec)
4920 return DoResolve (ec, false, false);
4923 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4925 if (!IsStatic){
4926 if (InstanceExpression == null){
4928 // This can happen when referencing an instance field using
4929 // a fully qualified type expression: TypeName.InstanceField = xxx
4931 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4932 return null;
4935 // Resolve the field's instance expression while flow analysis is turned
4936 // off: when accessing a field "a.b", we must check whether the field
4937 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4939 if (lvalue_instance) {
4940 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4941 Expression right_side =
4942 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4944 if (InstanceExpression != EmptyExpression.Null)
4945 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4947 } else {
4948 if (InstanceExpression != EmptyExpression.Null) {
4949 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4950 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4955 if (InstanceExpression == null)
4956 return null;
4958 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4959 InstanceExpression.CheckMarshalByRefAccess (ec);
4963 if (!ec.IsObsolete) {
4964 FieldBase f = TypeManager.GetField (spec.MetaInfo);
4965 if (f != null) {
4966 f.CheckObsoleteness (loc);
4967 } else {
4968 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
4969 if (oa != null)
4970 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (spec.MetaInfo), loc, ec.Report);
4974 var fb = spec as FixedFieldSpec;
4975 IVariableReference var = InstanceExpression as IVariableReference;
4977 if (fb != null) {
4978 IFixedExpression fe = InstanceExpression as IFixedExpression;
4979 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4980 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4983 if (InstanceExpression.eclass != ExprClass.Variable) {
4984 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
4985 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4986 TypeManager.GetFullNameSignature (spec.MetaInfo));
4987 } else if (var != null && var.IsHoisted) {
4988 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4991 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4994 eclass = ExprClass.Variable;
4996 // If the instance expression is a local variable or parameter.
4997 if (var == null || var.VariableInfo == null)
4998 return this;
5000 VariableInfo vi = var.VariableInfo;
5001 if (!vi.IsFieldAssigned (ec, Name, loc))
5002 return null;
5004 variable_info = vi.GetSubStruct (Name);
5005 return this;
5008 static readonly int [] codes = {
5009 191, // instance, write access
5010 192, // instance, out access
5011 198, // static, write access
5012 199, // static, out access
5013 1648, // member of value instance, write access
5014 1649, // member of value instance, out access
5015 1650, // member of value static, write access
5016 1651 // member of value static, out access
5019 static readonly string [] msgs = {
5020 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5021 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5022 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5023 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5024 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5025 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5026 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5027 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5030 // The return value is always null. Returning a value simplifies calling code.
5031 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5033 int i = 0;
5034 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5035 i += 1;
5036 if (IsStatic)
5037 i += 2;
5038 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5039 i += 4;
5040 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5042 return null;
5045 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5047 IVariableReference var = InstanceExpression as IVariableReference;
5048 if (var != null && var.VariableInfo != null)
5049 var.VariableInfo.SetFieldAssigned (ec, Name);
5051 bool lvalue_instance = !spec.IsStatic && TypeManager.IsValueType (spec.MetaInfo.DeclaringType);
5052 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5054 Expression e = DoResolve (ec, lvalue_instance, out_access);
5056 if (e == null)
5057 return null;
5059 FieldBase fb = TypeManager.GetField (spec.MetaInfo);
5060 if (fb != null) {
5061 fb.SetAssigned ();
5063 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5064 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5065 ec.Report.Warning (420, 1, loc,
5066 "`{0}': A volatile field references will not be treated as volatile",
5067 fb.GetSignatureForError ());
5071 if (spec.IsReadOnly) {
5072 // InitOnly fields can only be assigned in constructors or initializers
5073 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5074 return Report_AssignToReadonly (ec, right_side);
5076 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5077 Type ctype = ec.CurrentType;
5079 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5080 if (!TypeManager.IsEqual (ctype, DeclaringType))
5081 return Report_AssignToReadonly (ec, right_side);
5082 // static InitOnly fields cannot be assigned-to in an instance constructor
5083 if (IsStatic && !ec.IsStatic)
5084 return Report_AssignToReadonly (ec, right_side);
5085 // instance constructors can't modify InitOnly fields of other instances of the same type
5086 if (!IsStatic && !(InstanceExpression is This))
5087 return Report_AssignToReadonly (ec, right_side);
5091 if (right_side == EmptyExpression.OutAccess.Instance &&
5092 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5093 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5094 ec.Report.Warning (197, 1, loc,
5095 "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",
5096 GetSignatureForError ());
5099 eclass = ExprClass.Variable;
5100 return this;
5103 bool is_marshal_by_ref ()
5105 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5108 public override void CheckMarshalByRefAccess (ResolveContext ec)
5110 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5111 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5112 ec.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",
5113 GetSignatureForError ());
5117 public override int GetHashCode ()
5119 return spec.GetHashCode ();
5122 public bool IsFixed {
5123 get {
5125 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5127 IVariableReference variable = InstanceExpression as IVariableReference;
5128 if (variable != null)
5129 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5131 IFixedExpression fe = InstanceExpression as IFixedExpression;
5132 return fe != null && fe.IsFixed;
5136 public bool IsHoisted {
5137 get {
5138 IVariableReference hv = InstanceExpression as IVariableReference;
5139 return hv != null && hv.IsHoisted;
5143 public override bool Equals (object obj)
5145 FieldExpr fe = obj as FieldExpr;
5146 if (fe == null)
5147 return false;
5149 if (spec.MetaInfo != fe.spec.MetaInfo)
5150 return false;
5152 if (InstanceExpression == null || fe.InstanceExpression == null)
5153 return true;
5155 return InstanceExpression.Equals (fe.InstanceExpression);
5158 public void Emit (EmitContext ec, bool leave_copy)
5160 ILGenerator ig = ec.ig;
5161 bool is_volatile = false;
5163 var f = TypeManager.GetField (spec.MetaInfo);
5164 if (f != null){
5165 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5166 is_volatile = true;
5168 f.SetIsUsed ();
5171 if (IsStatic){
5172 if (is_volatile)
5173 ig.Emit (OpCodes.Volatile);
5175 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5176 } else {
5177 if (!prepared)
5178 EmitInstance (ec, false);
5180 // Optimization for build-in types
5181 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
5182 LoadFromPtr (ig, type);
5183 } else {
5184 var ff = spec as FixedFieldSpec;
5185 if (ff != null) {
5186 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5187 ig.Emit (OpCodes.Ldflda, ff.Element);
5188 } else {
5189 if (is_volatile)
5190 ig.Emit (OpCodes.Volatile);
5192 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5197 if (leave_copy) {
5198 ec.ig.Emit (OpCodes.Dup);
5199 if (!IsStatic) {
5200 temp = new LocalTemporary (this.Type);
5201 temp.Store (ec);
5206 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5208 //FieldAttributes fa = FieldInfo.Attributes;
5209 //bool is_static = (fa & FieldAttributes.Static) != 0;
5210 ILGenerator ig = ec.ig;
5212 prepared = prepare_for_load;
5213 EmitInstance (ec, prepared);
5215 source.Emit (ec);
5216 if (leave_copy) {
5217 ec.ig.Emit (OpCodes.Dup);
5218 if (!IsStatic) {
5219 temp = new LocalTemporary (this.Type);
5220 temp.Store (ec);
5224 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5225 if (f != null){
5226 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5227 ig.Emit (OpCodes.Volatile);
5229 f.SetAssigned ();
5232 if (IsStatic)
5233 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5234 else
5235 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5237 if (temp != null) {
5238 temp.Emit (ec);
5239 temp.Release (ec);
5240 temp = null;
5244 public override void Emit (EmitContext ec)
5246 Emit (ec, false);
5249 public override void EmitSideEffect (EmitContext ec)
5251 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5252 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5254 if (is_volatile || is_marshal_by_ref ())
5255 base.EmitSideEffect (ec);
5258 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5260 r.Error (844, loc,
5261 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5262 name, GetSignatureForError ());
5265 public void AddressOf (EmitContext ec, AddressOp mode)
5267 ILGenerator ig = ec.ig;
5269 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5270 if (f != null){
5271 if ((mode & AddressOp.Store) != 0)
5272 f.SetAssigned ();
5273 if ((mode & AddressOp.Load) != 0)
5274 f.SetIsUsed ();
5278 // Handle initonly fields specially: make a copy and then
5279 // get the address of the copy.
5281 bool need_copy;
5282 if (spec.IsReadOnly){
5283 need_copy = true;
5284 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5285 if (IsStatic){
5286 if (ec.IsStatic)
5287 need_copy = false;
5288 } else
5289 need_copy = false;
5291 } else
5292 need_copy = false;
5294 if (need_copy){
5295 LocalBuilder local;
5296 Emit (ec);
5297 local = ig.DeclareLocal (type);
5298 ig.Emit (OpCodes.Stloc, local);
5299 ig.Emit (OpCodes.Ldloca, local);
5300 return;
5304 if (IsStatic){
5305 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5306 } else {
5307 if (!prepared)
5308 EmitInstance (ec, false);
5309 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5313 FieldInfo GetConstructedFieldInfo ()
5315 if (constructed_generic_type == null)
5316 return spec.MetaInfo;
5318 return TypeBuilder.GetField (constructed_generic_type, spec.MetaInfo);
5321 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5323 return MakeExpression (ctx);
5326 public override SLE.Expression MakeExpression (BuilderContext ctx)
5328 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.MetaInfo);
5331 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5333 storey.MutateField (spec);
5334 base.MutateHoistedGenericType (storey);
5339 /// <summary>
5340 /// Expression that evaluates to a Property. The Assign class
5341 /// might set the `Value' expression if we are in an assignment.
5343 /// This is not an LValue because we need to re-write the expression, we
5344 /// can not take data from the stack and store it.
5345 /// </summary>
5346 public class PropertyExpr : MemberExpr, IDynamicAssign
5348 PropertySpec spec;
5349 MethodSpec getter, setter;
5350 bool is_static;
5352 TypeArguments targs;
5354 LocalTemporary temp;
5355 bool prepared;
5357 public PropertyExpr (Type container_type, PropertySpec spec, Location l)
5359 this.spec = spec;
5360 loc = l;
5362 type = TypeManager.TypeToCoreType (spec.PropertyType);
5364 ResolveAccessors (container_type);
5367 public override string Name {
5368 get {
5369 return spec.Name;
5373 public override bool IsInstance {
5374 get {
5375 return !is_static;
5379 public override bool IsStatic {
5380 get {
5381 return is_static;
5385 public override Expression CreateExpressionTree (ResolveContext ec)
5387 Arguments args;
5388 if (IsSingleDimensionalArrayLength ()) {
5389 args = new Arguments (1);
5390 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5391 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5394 if (is_base) {
5395 Error_BaseAccessInExpressionTree (ec, loc);
5396 return null;
5399 args = new Arguments (2);
5400 if (InstanceExpression == null)
5401 args.Add (new Argument (new NullLiteral (loc)));
5402 else
5403 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5404 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5405 return CreateExpressionFactoryCall (ec, "Property", args);
5408 public Expression CreateSetterTypeOfExpression ()
5410 return new TypeOfMethod (setter, loc);
5413 public override Type DeclaringType {
5414 get {
5415 return spec.DeclaringType;
5419 public override string GetSignatureForError ()
5421 return TypeManager.GetFullNameSignature (spec.MetaInfo);
5424 void FindAccessors (Type invocation_type)
5426 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5427 BindingFlags.Static | BindingFlags.Instance |
5428 BindingFlags.DeclaredOnly;
5430 Type current = spec.DeclaringType;
5431 for (; current != null; current = current.BaseType) {
5432 MemberInfo[] group = TypeManager.MemberLookup (
5433 invocation_type, invocation_type, current,
5434 MemberTypes.Property, flags, spec.Name, null);
5436 if (group == null)
5437 continue;
5439 if (group.Length != 1)
5440 // Oooops, can this ever happen ?
5441 return;
5443 PropertyInfo pi = (PropertyInfo) group [0];
5445 if (getter == null) {
5446 var m = pi.GetGetMethod (true);
5447 if (m != null)
5448 getter = Import.CreateMethod (m);
5451 if (setter == null) {
5452 var m = pi.GetSetMethod (true);
5453 if (m != null)
5454 setter = Import.CreateMethod (m);
5457 var accessor = getter != null ? getter : setter;
5459 if (!accessor.IsVirtual)
5460 return;
5465 // We also perform the permission checking here, as the PropertyInfo does not
5466 // hold the information for the accessibility of its setter/getter
5468 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5469 void ResolveAccessors (Type container_type)
5471 FindAccessors (container_type);
5473 if (getter != null) {
5474 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5475 IMethodData md = TypeManager.GetMethod (the_getter);
5476 if (md != null)
5477 md.SetIsUsed ();
5479 is_static = getter.IsStatic;
5482 if (setter != null) {
5483 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5484 IMethodData md = TypeManager.GetMethod (the_setter);
5485 if (md != null)
5486 md.SetIsUsed ();
5488 is_static = setter.IsStatic;
5492 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5494 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) setter.MetaInfo);
5497 public override SLE.Expression MakeExpression (BuilderContext ctx)
5499 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) getter.MetaInfo);
5502 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5504 if (InstanceExpression != null)
5505 InstanceExpression.MutateHoistedGenericType (storey);
5507 type = storey.MutateType (type);
5508 if (getter != null)
5509 storey.MutateGenericMethod (getter);
5510 if (setter != null)
5511 storey.MutateGenericMethod (setter);
5514 public PropertyInfo PropertyInfo {
5515 get {
5516 return spec.MetaInfo;
5520 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5522 if (is_static) {
5523 InstanceExpression = null;
5524 return true;
5527 if (InstanceExpression == null) {
5528 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5529 return false;
5532 InstanceExpression = InstanceExpression.Resolve (ec);
5533 if (lvalue_instance && InstanceExpression != null)
5534 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5536 if (InstanceExpression == null)
5537 return false;
5539 InstanceExpression.CheckMarshalByRefAccess (ec);
5541 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5542 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5543 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5544 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5545 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5546 Error_CannotAccessProtected (ec, loc, spec.MetaInfo, InstanceExpression.Type, ec.CurrentType);
5547 return false;
5550 return true;
5553 void Error_PropertyNotFound (ResolveContext ec, MethodSpec mi, bool getter)
5555 // TODO: correctly we should compare arguments but it will lead to bigger changes
5556 if (mi.MetaInfo is MethodBuilder) {
5557 Error_TypeDoesNotContainDefinition (ec, loc, spec.DeclaringType, Name);
5558 return;
5561 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5562 sig.Append ('.');
5563 AParametersCollection iparams = mi.Parameters;
5564 sig.Append (getter ? "get_" : "set_");
5565 sig.Append (Name);
5566 sig.Append (iparams.GetSignatureForError ());
5568 ec.Report.SymbolRelatedToPreviousError (mi.MetaInfo);
5569 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5570 Name, sig.ToString ());
5573 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5575 bool dummy;
5576 var accessor = lvalue ? setter : getter;
5577 if (accessor == null && lvalue)
5578 accessor = getter;
5579 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5582 bool IsSingleDimensionalArrayLength ()
5584 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5585 return false;
5587 string t_name = InstanceExpression.Type.Name;
5588 int t_name_len = t_name.Length;
5589 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5592 protected override Expression DoResolve (ResolveContext ec)
5594 eclass = ExprClass.PropertyAccess;
5596 bool must_do_cs1540_check = false;
5597 ec.Report.DisableReporting ();
5598 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5599 ec.Report.EnableReporting ();
5601 if (!res) {
5602 if (InstanceExpression != null) {
5603 Type expr_type = InstanceExpression.Type;
5604 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5605 if (ex_method_lookup != null) {
5606 ex_method_lookup.ExtensionExpression = InstanceExpression;
5607 ex_method_lookup.SetTypeArguments (ec, targs);
5608 return ex_method_lookup.Resolve (ec);
5612 ResolveGetter (ec, ref must_do_cs1540_check);
5613 return null;
5616 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5617 return null;
5620 // Only base will allow this invocation to happen.
5622 if (IsBase && getter.IsAbstract) {
5623 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5626 if (spec.PropertyType.IsPointer && !ec.IsUnsafe){
5627 UnsafeError (ec, loc);
5630 if (!ec.IsObsolete) {
5631 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5632 if (pb != null) {
5633 pb.CheckObsoleteness (loc);
5634 } else {
5635 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5636 if (oa != null)
5637 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5641 return this;
5644 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5646 eclass = ExprClass.PropertyAccess;
5648 if (right_side == EmptyExpression.OutAccess.Instance) {
5649 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5650 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5651 spec.Name);
5652 } else {
5653 right_side.DoResolveLValue (ec, this);
5655 return null;
5658 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5659 Error_CannotModifyIntermediateExpressionValue (ec);
5662 if (setter == null){
5664 // The following condition happens if the PropertyExpr was
5665 // created, but is invalid (ie, the property is inaccessible),
5666 // and we did not want to embed the knowledge about this in
5667 // the caller routine. This only avoids double error reporting.
5669 if (getter == null)
5670 return null;
5672 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5673 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5674 spec.Name);
5675 } else {
5676 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5677 GetSignatureForError ());
5679 return null;
5682 if (targs != null) {
5683 base.SetTypeArguments (ec, targs);
5684 return null;
5687 if (setter.Parameters.Count != 1){
5688 Error_PropertyNotFound (ec, setter, false);
5689 return null;
5692 bool must_do_cs1540_check;
5693 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5694 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter.MetaInfo) as PropertyBase.PropertyMethod;
5695 if (pm != null && pm.HasCustomAccessModifier) {
5696 ec.Report.SymbolRelatedToPreviousError (pm);
5697 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5698 TypeManager.CSharpSignature (setter));
5700 else {
5701 ec.Report.SymbolRelatedToPreviousError (setter.MetaInfo);
5702 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5704 return null;
5707 if (!InstanceResolve (ec, TypeManager.IsStruct (spec.DeclaringType), must_do_cs1540_check))
5708 return null;
5711 // Only base will allow this invocation to happen.
5713 if (IsBase && setter.IsAbstract){
5714 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5717 if (spec.PropertyType.IsPointer && !ec.IsUnsafe) {
5718 UnsafeError (ec, loc);
5721 if (!ec.IsObsolete) {
5722 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5723 if (pb != null) {
5724 pb.CheckObsoleteness (loc);
5725 } else {
5726 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5727 if (oa != null)
5728 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5732 return this;
5735 public override void Emit (EmitContext ec)
5737 Emit (ec, false);
5740 public void Emit (EmitContext ec, bool leave_copy)
5743 // Special case: length of single dimension array property is turned into ldlen
5745 if (IsSingleDimensionalArrayLength ()) {
5746 if (!prepared)
5747 EmitInstance (ec, false);
5748 ec.ig.Emit (OpCodes.Ldlen);
5749 ec.ig.Emit (OpCodes.Conv_I4);
5750 return;
5753 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5755 if (leave_copy) {
5756 ec.ig.Emit (OpCodes.Dup);
5757 if (!is_static) {
5758 temp = new LocalTemporary (this.Type);
5759 temp.Store (ec);
5765 // Implements the IAssignMethod interface for assignments
5767 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5769 Expression my_source = source;
5771 if (prepare_for_load) {
5772 prepared = true;
5773 source.Emit (ec);
5775 if (leave_copy) {
5776 ec.ig.Emit (OpCodes.Dup);
5777 if (!is_static) {
5778 temp = new LocalTemporary (this.Type);
5779 temp.Store (ec);
5782 } else if (leave_copy) {
5783 source.Emit (ec);
5784 temp = new LocalTemporary (this.Type);
5785 temp.Store (ec);
5786 my_source = temp;
5789 Arguments args = new Arguments (1);
5790 args.Add (new Argument (my_source));
5792 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5794 if (temp != null) {
5795 temp.Emit (ec);
5796 temp.Release (ec);
5800 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5802 if (targs != null) {
5803 base.SetTypeArguments (ec, targs);
5804 return false;
5807 if (getter != null) {
5808 if (!getter.Parameters.IsEmpty) {
5809 Error_PropertyNotFound (ec, getter, true);
5810 return false;
5814 if (getter == null) {
5816 // The following condition happens if the PropertyExpr was
5817 // created, but is invalid (ie, the property is inaccessible),
5818 // and we did not want to embed the knowledge about this in
5819 // the caller routine. This only avoids double error reporting.
5821 if (setter == null)
5822 return false;
5824 if (InstanceExpression != EmptyExpression.Null) {
5825 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5826 TypeManager.GetFullNameSignature (spec.MetaInfo));
5827 return false;
5831 if (getter != null &&
5832 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5833 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter.MetaInfo) as PropertyBase.PropertyMethod;
5834 if (pm != null && pm.HasCustomAccessModifier) {
5835 ec.Report.SymbolRelatedToPreviousError (pm);
5836 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5837 TypeManager.CSharpSignature (getter.MetaInfo));
5838 } else {
5839 ec.Report.SymbolRelatedToPreviousError (getter.MetaInfo);
5840 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter.MetaInfo), ec.Report);
5843 return false;
5846 return true;
5849 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5851 targs = ta;
5855 /// <summary>
5856 /// Fully resolved expression that evaluates to an Event
5857 /// </summary>
5858 public class EventExpr : MemberExpr
5860 readonly EventSpec spec;
5862 public EventExpr (EventSpec spec, Location loc)
5864 this.spec = spec;
5865 this.loc = loc;
5868 public override string Name {
5869 get {
5870 return spec.Name;
5874 public override bool IsInstance {
5875 get {
5876 return !spec.IsStatic;
5880 public override bool IsStatic {
5881 get {
5882 return spec.IsStatic;
5886 public override Type DeclaringType {
5887 get {
5888 return spec.DeclaringType;
5892 public void Error_AssignmentEventOnly (ResolveContext ec)
5894 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5895 GetSignatureForError ());
5898 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5899 SimpleName original)
5902 // If the event is local to this class, we transform ourselves into a FieldExpr
5905 if (spec.DeclaringType == ec.CurrentType ||
5906 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5908 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5909 EventField mi = TypeManager.GetEventField (spec.MetaInfo).MemberDefinition as EventField;
5911 if (mi != null && mi.HasBackingField) {
5912 mi.SetIsUsed ();
5913 if (!ec.IsObsolete)
5914 mi.CheckObsoleteness (loc);
5916 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5917 Error_AssignmentEventOnly (ec);
5919 FieldExpr ml = new FieldExpr (mi.BackingField, loc);
5921 InstanceExpression = null;
5923 return ml.ResolveMemberAccess (ec, left, loc, original);
5927 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5928 Error_AssignmentEventOnly (ec);
5930 return base.ResolveMemberAccess (ec, left, loc, original);
5933 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5935 if (IsStatic) {
5936 InstanceExpression = null;
5937 return true;
5940 if (InstanceExpression == null) {
5941 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5942 return false;
5945 InstanceExpression = InstanceExpression.Resolve (ec);
5946 if (InstanceExpression == null)
5947 return false;
5949 if (IsBase && spec.IsAbstract) {
5950 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(spec.MetaInfo));
5951 return false;
5955 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5956 // However, in the Event case, we reported a CS0122 instead.
5958 // TODO: Exact copy from PropertyExpr
5960 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5961 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5962 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5963 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5964 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5965 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
5966 return false;
5969 return true;
5972 public bool IsAccessibleFrom (Type invocation_type)
5974 bool dummy;
5975 return IsAccessorAccessible (invocation_type, spec.AccessorAdd, out dummy) &&
5976 IsAccessorAccessible (invocation_type, spec.AccessorRemove, out dummy);
5979 public override Expression CreateExpressionTree (ResolveContext ec)
5981 throw new NotSupportedException ("ET");
5984 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5986 // contexts where an LValue is valid have already devolved to FieldExprs
5987 Error_CannotAssign (ec);
5988 return null;
5991 protected override Expression DoResolve (ResolveContext ec)
5993 eclass = ExprClass.EventAccess;
5995 bool must_do_cs1540_check;
5996 if (!(IsAccessorAccessible (ec.CurrentType, spec.AccessorAdd, out must_do_cs1540_check) &&
5997 IsAccessorAccessible (ec.CurrentType, spec.AccessorRemove, out must_do_cs1540_check))) {
5998 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5999 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
6000 return null;
6003 if (!InstanceResolve (ec, must_do_cs1540_check))
6004 return null;
6006 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6007 Error_CannotAssign (ec);
6008 return null;
6011 if (!ec.IsObsolete) {
6012 var oa = spec.GetObsoleteAttribute ();
6013 if (oa != null)
6014 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
6017 spec.MemberDefinition.SetIsUsed ();
6018 type = spec.EventType;
6020 return this;
6023 public override void Emit (EmitContext ec)
6025 throw new NotSupportedException ();
6026 //Error_CannotAssign ();
6029 public void Error_CannotAssign (ResolveContext ec)
6031 ec.Report.Error (70, loc,
6032 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6033 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
6036 public override string GetSignatureForError ()
6038 return TypeManager.CSharpSignature (spec.MetaInfo);
6041 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6043 Arguments args = new Arguments (1);
6044 args.Add (new Argument (source));
6045 Invocation.EmitCall (ec, IsBase, InstanceExpression,
6046 is_add ? spec.AccessorAdd : spec.AccessorRemove,
6047 args, loc);
6051 public class TemporaryVariable : VariableReference
6053 LocalInfo li;
6055 public TemporaryVariable (Type type, Location loc)
6057 this.type = type;
6058 this.loc = loc;
6061 public override Expression CreateExpressionTree (ResolveContext ec)
6063 throw new NotSupportedException ("ET");
6066 protected override Expression DoResolve (ResolveContext ec)
6068 eclass = ExprClass.Variable;
6070 TypeExpr te = new TypeExpression (type, loc);
6071 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6072 if (!li.Resolve (ec))
6073 return null;
6076 // Don't capture temporary variables except when using
6077 // iterator redirection
6079 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6080 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6081 storey.CaptureLocalVariable (ec, li);
6084 return this;
6087 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6089 return Resolve (ec);
6092 public override void Emit (EmitContext ec)
6094 Emit (ec, false);
6097 public void EmitAssign (EmitContext ec, Expression source)
6099 EmitAssign (ec, source, false, false);
6102 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6104 return li.HoistedVariant;
6107 public override bool IsFixed {
6108 get { return true; }
6111 public override bool IsRef {
6112 get { return false; }
6115 public override string Name {
6116 get { throw new NotImplementedException (); }
6119 public override void SetHasAddressTaken ()
6121 throw new NotImplementedException ();
6124 protected override ILocalVariable Variable {
6125 get { return li; }
6128 public override VariableInfo VariableInfo {
6129 get { throw new NotImplementedException (); }
6133 ///
6134 /// Handles `var' contextual keyword; var becomes a keyword only
6135 /// if no type called var exists in a variable scope
6136 ///
6137 class VarExpr : SimpleName
6139 // Used for error reporting only
6140 int initializers_count;
6142 public VarExpr (Location loc)
6143 : base ("var", loc)
6145 initializers_count = 1;
6148 public int VariableInitializersCount {
6149 set {
6150 this.initializers_count = value;
6154 public bool InferType (ResolveContext ec, Expression right_side)
6156 if (type != null)
6157 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6159 type = right_side.Type;
6160 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6161 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6162 right_side.GetSignatureForError ());
6163 return false;
6166 eclass = ExprClass.Variable;
6167 return true;
6170 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6172 if (RootContext.Version < LanguageVersion.V_3)
6173 base.Error_TypeOrNamespaceNotFound (ec);
6174 else
6175 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6178 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6180 TypeExpr te = base.ResolveAsContextualType (rc, true);
6181 if (te != null)
6182 return te;
6184 if (RootContext.Version < LanguageVersion.V_3)
6185 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6187 if (initializers_count == 1)
6188 return null;
6190 if (initializers_count > 1) {
6191 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
6192 initializers_count = 1;
6193 return null;
6196 if (initializers_count == 0) {
6197 initializers_count = 1;
6198 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
6199 return null;
6202 return null;