2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
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,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
67 // This is just as a hint to AddressOf of what will be done with the
70 public enum AddressOp {
77 /// This interface is implemented by variables
79 public interface IMemoryLocation {
81 /// The AddressOf method should generate code that loads
82 /// the address of the object and leaves it on the stack.
84 /// The `mode' argument is used to notify the expression
85 /// of whether this will be used to read from the address or
86 /// write to the address.
88 /// This is just a hint that can be used to provide good error
89 /// reporting, and should have no other side effects.
91 void AddressOf (EmitContext ec, AddressOp mode);
95 // An expressions resolved as a direct variable reference
97 public interface IVariableReference : IFixedExpression
99 bool IsHoisted { get; }
101 VariableInfo VariableInfo { get; }
103 void SetHasAddressTaken ();
107 // Implemented by an expression which could be or is always
110 public interface IFixedExpression
112 bool IsFixed { get; }
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
120 protected TypeSpec type;
121 protected Location loc;
123 public TypeSpec Type {
125 set { type = value; }
128 public virtual Location Location {
132 // Not nice but we have broken hierarchy.
133 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public static bool IsMemberAccessible (TypeSpec invocation_type, MemberSpec mi, out bool must_do_cs1540_check)
144 var ma = mi.Modifiers & Modifiers.AccessibilityMask;
146 must_do_cs1540_check = false; // by default we do not check for this
148 if (ma == Modifiers.PUBLIC)
152 // If only accessible to the current class or children
154 if (ma == Modifiers.PRIVATE)
155 return invocation_type.MemberDefinition == mi.DeclaringType.MemberDefinition ||
156 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
158 if ((ma & Modifiers.INTERNAL) != 0) {
159 var b = TypeManager.IsThisOrFriendAssembly (invocation_type == InternalType.FakeInternalType ?
160 CodeGen.Assembly.Builder : invocation_type.Assembly, mi.DeclaringType.Assembly);
161 if (b || ma == Modifiers.INTERNAL)
165 // Family and FamANDAssem require that we derive.
166 // FamORAssem requires that we derive if in different assemblies.
167 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
170 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
171 must_do_cs1540_check = true;
176 public virtual bool IsNull {
183 /// Performs semantic analysis on the Expression
187 /// The Resolve method is invoked to perform the semantic analysis
190 /// The return value is an expression (it can be the
191 /// same expression in some cases) or a new
192 /// expression that better represents this node.
194 /// For example, optimizations of Unary (LiteralInt)
195 /// would return a new LiteralInt with a negated
198 /// If there is an error during semantic analysis,
199 /// then an error should be reported (using Report)
200 /// and a null value should be returned.
202 /// There are two side effects expected from calling
203 /// Resolve(): the the field variable "eclass" should
204 /// be set to any value of the enumeration
205 /// `ExprClass' and the type variable should be set
206 /// to a valid type (this is the type of the
209 protected abstract Expression DoResolve (ResolveContext rc);
211 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
217 // This is used if the expression should be resolved as a type or namespace name.
218 // the default implementation fails.
220 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
223 ResolveContext ec = new ResolveContext (rc);
224 Expression e = Resolve (ec);
226 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
233 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
234 // same name exists or as a keyword when no type was found
236 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
238 return ResolveAsTypeTerminal (rc, silent);
242 // This is used to resolve the expression as a type, a null
243 // value will be returned if the expression is not a type
246 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
248 int errors = ec.Compiler.Report.Errors;
250 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
255 TypeExpr te = fne as TypeExpr;
257 if (!silent && errors == ec.Compiler.Report.Errors)
258 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
262 if (!te.CheckAccessLevel (ec)) {
263 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
264 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
270 // Obsolete checks cannot be done when resolving base context as they
271 // require type dependecies to be set but we are just resolving them
273 if (!silent && !(ec is TypeContainer.BaseContext)) {
274 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
275 if (obsolete_attr != null && !ec.IsObsolete) {
276 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
283 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
285 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
288 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberSpec m, TypeSpec qualifier, TypeSpec container)
290 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
291 + " The qualifier must be of type `{2}' or derived from it",
292 m.GetSignatureForError (),
293 TypeManager.CSharpName (qualifier),
294 TypeManager.CSharpName (container));
298 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
300 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
303 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
305 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
306 name, TypeManager.CSharpName (type));
309 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
311 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
312 "expressions can be used as a statement");
315 public void Error_InvalidExpressionStatement (BlockContext ec)
317 Error_InvalidExpressionStatement (ec.Report, loc);
320 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
322 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
325 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
327 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
330 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
332 // The error was already reported as CS1660
333 if (type == InternalType.AnonymousMethod)
337 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
338 string sig1 = type.DeclaringMethod == null ?
339 TypeManager.CSharpName (type.DeclaringType) :
340 TypeManager.CSharpSignature (type.DeclaringMethod);
341 string sig2 = target.DeclaringMethod == null ?
342 TypeManager.CSharpName (target.DeclaringType) :
343 TypeManager.CSharpSignature (target.DeclaringMethod);
344 ec.Report.ExtraInformation (loc,
346 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
347 Type.Name, sig1, sig2));
348 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
349 ec.Report.ExtraInformation (loc,
351 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
352 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
356 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
357 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
361 ec.Report.DisableReporting ();
362 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
363 ec.Report.EnableReporting ();
366 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
367 "An explicit conversion exists (are you missing a cast?)",
368 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
372 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
373 type.GetSignatureForError (), target.GetSignatureForError ());
376 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
378 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
381 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
383 // Better message for possible generic expressions
384 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
385 report.SymbolRelatedToPreviousError (member);
386 if (member is TypeSpec)
387 member = ((TypeSpec) member).GetDefinition ();
389 member = ((MethodSpec) member).GetGenericMethodDefinition ();
391 string name = member.Kind == MemberKind.Method ? "method" : "type";
392 if (member.IsGeneric) {
393 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
394 name, member.GetSignatureForError (), member.Arity.ToString ());
396 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
397 name, member.GetSignatureForError ());
400 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
401 ExprClassName, GetSignatureForError ());
405 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
407 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
410 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
412 ec.Report.SymbolRelatedToPreviousError (type);
413 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
414 TypeManager.CSharpName (type), name);
417 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
419 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
422 public ResolveFlags ExprClassToResolveFlags {
426 case ExprClass.Namespace:
427 return ResolveFlags.Type;
429 case ExprClass.MethodGroup:
430 return ResolveFlags.MethodGroup;
432 case ExprClass.TypeParameter:
433 return ResolveFlags.TypeParameter;
435 case ExprClass.Value:
436 case ExprClass.Variable:
437 case ExprClass.PropertyAccess:
438 case ExprClass.EventAccess:
439 case ExprClass.IndexerAccess:
440 return ResolveFlags.VariableOrValue;
443 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
449 /// Resolves an expression and performs semantic analysis on it.
453 /// Currently Resolve wraps DoResolve to perform sanity
454 /// checking and assertion checking on what we expect from Resolve.
456 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
458 if (eclass != ExprClass.Unresolved)
469 if ((flags & e.ExprClassToResolveFlags) == 0) {
470 e.Error_UnexpectedKind (ec, flags, loc);
475 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
478 } catch (Exception ex) {
479 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
482 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
483 return EmptyExpression.Null;
488 /// Resolves an expression and performs semantic analysis on it.
490 public Expression Resolve (ResolveContext rc)
492 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
496 /// Resolves an expression for LValue assignment
500 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
501 /// checking and assertion checking on what we expect from Resolve
503 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
505 int errors = ec.Report.Errors;
506 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
508 Expression e = DoResolveLValue (ec, right_side);
510 if (e != null && out_access && !(e is IMemoryLocation)) {
511 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
512 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
514 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
515 // e.GetType () + " " + e.GetSignatureForError ());
520 if (errors == ec.Report.Errors) {
522 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
524 Error_ValueAssignment (ec, loc);
529 if (e.eclass == ExprClass.Unresolved)
530 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
532 if ((e.type == null) && !(e is GenericTypeExpr))
533 throw new Exception ("Expression " + e + " did not set its type after Resolve");
538 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
540 Attribute.Error_AttributeArgumentNotValid (rc, loc);
544 /// Emits the code for the expression
548 /// The Emit method is invoked to generate the code
549 /// for the expression.
551 public abstract void Emit (EmitContext ec);
554 // Emit code to branch to @target if this expression is equivalent to @on_true.
555 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
556 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
557 // including the use of conditional branches. Note also that a branch MUST be emitted
558 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
561 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
564 // Emit this expression for its side effects, not for its value.
565 // The default implementation is to emit the value, and then throw it away.
566 // Subclasses can provide more efficient implementations, but those MUST be equivalent
567 public virtual void EmitSideEffect (EmitContext ec)
570 ec.Emit (OpCodes.Pop);
574 /// Protected constructor. Only derivate types should
575 /// be able to be created
578 protected Expression ()
583 /// Returns a fully formed expression after a MemberLookup
586 public static Expression ExprClassFromMemberInfo (TypeSpec container_type, MemberSpec spec, Location loc)
588 if (spec is EventSpec)
589 return new EventExpr ((EventSpec) spec, loc);
590 if (spec is ConstSpec)
591 return new ConstantExpr ((ConstSpec) spec, loc);
592 if (spec is FieldSpec)
593 return new FieldExpr ((FieldSpec) spec, loc);
594 if (spec is PropertySpec)
595 return new PropertyExpr ((PropertySpec) spec, loc);
596 if (spec is TypeSpec)
597 return new TypeExpression (((TypeSpec) spec), loc);
603 // FIXME: Probably implement a cache for (t,name,current_access_set)?
605 // This code could use some optimizations, but we need to do some
606 // measurements. For example, we could use a delegate to `flag' when
607 // something can not any longer be a method-group (because it is something
611 // If the return value is an Array, then it is an array of
614 // If the return value is an MemberInfo, it is anything, but a Method
618 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
619 // the arguments here and have MemberLookup return only the methods that
620 // match the argument count/type, unlike we are doing now (we delay this
623 // This is so we can catch correctly attempts to invoke instance methods
624 // from a static body (scan for error 120 in ResolveSimpleName).
627 // FIXME: Potential optimization, have a static ArrayList
630 public static Expression MemberLookup (CompilerContext ctx, TypeSpec container_type, TypeSpec queried_type, string name, int arity,
631 MemberKind mt, BindingRestriction bf, Location loc)
633 return MemberLookup (ctx, container_type, null, queried_type, name, arity, mt, bf, loc);
637 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
638 // `qualifier_type' or null to lookup members in the current class.
640 public static Expression MemberLookup (CompilerContext ctx, TypeSpec container_type,
641 TypeSpec qualifier_type, TypeSpec queried_type,
642 string name, int arity, MemberKind mt,
643 BindingRestriction binding, Location loc)
645 var mi = TypeManager.MemberLookup (container_type, qualifier_type,
646 queried_type, mt, binding, name, arity, null);
652 foreach (var mc in mi) {
653 if (mc is MethodSpec)
654 return new MethodGroupExpr (mi, queried_type, loc);
657 ctx.Report.SymbolRelatedToPreviousError (mi [1]);
658 ctx.Report.SymbolRelatedToPreviousError (first);
659 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
660 first.GetSignatureForError (), mi [1].GetSignatureForError ());
663 if (first is MethodSpec)
664 return new MethodGroupExpr (mi, queried_type, loc);
666 return ExprClassFromMemberInfo (container_type, first, loc);
669 public static Expression MemberLookup (CompilerContext ctx, TypeSpec container_type, TypeSpec queried_type,
670 string name, int arity, BindingRestriction binding, Location loc)
672 return MemberLookup (ctx, container_type, null, queried_type, name, arity,
673 MemberKind.All, binding | BindingRestriction.AccessibleOnly, loc);
676 public static Expression MemberLookup (CompilerContext ctx, TypeSpec container_type, TypeSpec qualifier_type,
677 TypeSpec queried_type, string name, int arity, BindingRestriction binding, Location loc)
679 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
680 name, arity, MemberKind.All, binding | BindingRestriction.AccessibleOnly, loc);
684 /// This is a wrapper for MemberLookup that is not used to "probe", but
685 /// to find a final definition. If the final definition is not found, we
686 /// look for private members and display a useful debugging message if we
689 protected Expression MemberLookupFinal (ResolveContext ec, TypeSpec qualifier_type,
690 TypeSpec queried_type, string name, int arity,
691 MemberKind mt, BindingRestriction bf,
696 int errors = ec.Report.Errors;
697 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, arity, mt, bf, loc);
699 if (e != null || errors != ec.Report.Errors)
702 // No errors were reported by MemberLookup, but there was an error.
703 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
704 name, arity, null, mt, bf);
707 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, TypeSpec container_type, TypeSpec qualifier_type,
708 TypeSpec queried_type, string name, int arity, string class_name,
709 MemberKind mt, BindingRestriction bf)
711 IList<MemberSpec> lookup = null;
712 if (queried_type == null) {
713 class_name = "global::";
715 BindingRestriction restriction = bf & BindingRestriction.DeclaredOnly;
717 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
718 mt, restriction, name, arity, null);
720 if (lookup != null) {
721 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
724 // FIXME: This is still very wrong, it should be done inside
725 // OverloadResolve to do correct arguments matching.
726 // Requires MemberLookup accessiblity check removal
728 if (e == null || (mt & (MemberKind.Method | MemberKind.Constructor)) == 0) {
729 var mi = lookup.First ();
730 ec.Report.SymbolRelatedToPreviousError (mi);
731 if ((mi.Modifiers & Modifiers.PROTECTED) != 0 && qualifier_type != null && container_type != null && qualifier_type != container_type &&
732 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
733 // Although a derived class can access protected members of
734 // its base class it cannot do so through an instance of the
735 // base class (CS1540). If the qualifier_type is a base of the
736 // ec.CurrentType and the lookup succeeds with the latter one,
737 // then we are in this situation.
738 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
740 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
747 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
748 MemberKind.All, BindingRestriction.None, name, -System.Math.Max (1, arity), null);
751 if (lookup == null) {
752 if (class_name != null) {
753 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
756 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
761 var mge = Error_MemberLookupFailed (ec, queried_type, lookup);
762 if (arity > 0 && mge != null) {
763 mge.SetTypeArguments (ec, new TypeArguments (new FullNamedExpression [arity]));
766 return mge.Resolve (ec);
769 protected virtual MemberExpr Error_MemberLookupFailed (ResolveContext ec, TypeSpec type, IList<MemberSpec> members)
771 if (members.Any ((m) => !(m is MethodSpec)))
772 return (MemberExpr) ExprClassFromMemberInfo (type, members.First (), loc);
774 // By default propagate the closest candidates upwards
775 return new MethodGroupExpr (members, type, loc, true);
778 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
780 throw new NotImplementedException ();
783 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
785 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
789 /// Returns an expression that can be used to invoke operator true
790 /// on the expression if it exists.
792 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
794 return GetOperatorTrueOrFalse (ec, e, true, loc);
798 /// Returns an expression that can be used to invoke operator false
799 /// on the expression if it exists.
801 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
803 return GetOperatorTrueOrFalse (ec, e, false, loc);
806 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
808 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
809 var methods = MemberCache.GetUserOperator (e.type, op, false);
813 var mg = new MethodGroupExpr (methods, e.type, loc);
815 Arguments arguments = new Arguments (1);
816 arguments.Add (new Argument (e));
817 mg = mg.OverloadResolve (ec, ref arguments, false, loc);
822 return new UserOperatorCall (mg, arguments, null, loc);
825 public virtual string ExprClassName
829 case ExprClass.Unresolved:
831 case ExprClass.Value:
833 case ExprClass.Variable:
835 case ExprClass.Namespace:
839 case ExprClass.MethodGroup:
840 return "method group";
841 case ExprClass.PropertyAccess:
842 return "property access";
843 case ExprClass.EventAccess:
844 return "event access";
845 case ExprClass.IndexerAccess:
846 return "indexer access";
847 case ExprClass.Nothing:
849 case ExprClass.TypeParameter:
850 return "type parameter";
852 throw new Exception ("Should not happen");
857 /// Reports that we were expecting `expr' to be of class `expected'
859 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
861 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
864 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
868 name = mc.GetSignatureForError ();
870 name = GetSignatureForError ();
872 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
873 name, was, expected);
876 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
878 string [] valid = new string [4];
881 if ((flags & ResolveFlags.VariableOrValue) != 0) {
882 valid [count++] = "variable";
883 valid [count++] = "value";
886 if ((flags & ResolveFlags.Type) != 0)
887 valid [count++] = "type";
889 if ((flags & ResolveFlags.MethodGroup) != 0)
890 valid [count++] = "method group";
893 valid [count++] = "unknown";
895 StringBuilder sb = new StringBuilder (valid [0]);
896 for (int i = 1; i < count - 1; i++) {
898 sb.Append (valid [i]);
901 sb.Append ("' or `");
902 sb.Append (valid [count - 1]);
905 ec.Report.Error (119, loc,
906 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
909 public static void UnsafeError (ResolveContext ec, Location loc)
911 UnsafeError (ec.Report, loc);
914 public static void UnsafeError (Report Report, Location loc)
916 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
921 // Returns the size of type `t' if known, otherwise, 0
923 public static int GetTypeSize (TypeSpec t)
925 if (t == TypeManager.int32_type ||
926 t == TypeManager.uint32_type ||
927 t == TypeManager.float_type)
929 else if (t == TypeManager.int64_type ||
930 t == TypeManager.uint64_type ||
931 t == TypeManager.double_type)
933 else if (t == TypeManager.byte_type ||
934 t == TypeManager.sbyte_type ||
935 t == TypeManager.bool_type)
937 else if (t == TypeManager.short_type ||
938 t == TypeManager.char_type ||
939 t == TypeManager.ushort_type)
941 else if (t == TypeManager.decimal_type)
947 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
949 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
952 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
954 ec.Report.SymbolRelatedToPreviousError (type);
955 if (ec.CurrentInitializerVariable != null) {
956 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
957 TypeManager.CSharpName (type), GetSignatureForError ());
959 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
960 GetSignatureForError ());
965 // Converts `source' to an int, uint, long or ulong.
967 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
969 if (source.type == InternalType.Dynamic) {
970 Arguments args = new Arguments (1);
971 args.Add (new Argument (source));
972 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
975 Expression converted;
977 using (ec.Set (ResolveContext.Options.CheckedScope)) {
978 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
979 if (converted == null)
980 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
981 if (converted == null)
982 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
983 if (converted == null)
984 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
986 if (converted == null) {
987 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
993 // Only positive constants are allowed at compile time
995 Constant c = converted as Constant;
996 if (c != null && c.IsNegative)
997 Error_NegativeArrayIndex (ec, source.loc);
999 // No conversion needed to array index
1000 if (converted.Type == TypeManager.int32_type)
1003 return new ArrayIndexCast (converted).Resolve (ec);
1007 // Derived classes implement this method by cloning the fields that
1008 // could become altered during the Resolve stage
1010 // Only expressions that are created for the parser need to implement
1013 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1015 throw new NotImplementedException (
1017 "CloneTo not implemented for expression {0}", this.GetType ()));
1021 // Clones an expression created by the parser.
1023 // We only support expressions created by the parser so far, not
1024 // expressions that have been resolved (many more classes would need
1025 // to implement CloneTo).
1027 // This infrastructure is here merely for Lambda expressions which
1028 // compile the same code using different type values for the same
1029 // arguments to find the correct overload
1031 public Expression Clone (CloneContext clonectx)
1033 Expression cloned = (Expression) MemberwiseClone ();
1034 CloneTo (clonectx, cloned);
1040 // Implementation of expression to expression tree conversion
1042 public abstract Expression CreateExpressionTree (ResolveContext ec);
1044 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1046 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1049 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1051 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1054 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1056 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1059 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1061 TypeExpr texpr = TypeManager.expression_type_expr;
1062 if (texpr == null) {
1063 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
1067 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1074 // Implemented by all expressions which support conversion from
1075 // compiler expression to invokable runtime expression. Used by
1076 // dynamic C# binder.
1078 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1080 throw new NotImplementedException ("MakeExpression for " + GetType ());
1085 /// This is just a base class for expressions that can
1086 /// appear on statements (invocations, object creation,
1087 /// assignments, post/pre increment and decrement). The idea
1088 /// being that they would support an extra Emition interface that
1089 /// does not leave a result on the stack.
1091 public abstract class ExpressionStatement : Expression {
1093 public ExpressionStatement ResolveStatement (BlockContext ec)
1095 Expression e = Resolve (ec);
1099 ExpressionStatement es = e as ExpressionStatement;
1101 Error_InvalidExpressionStatement (ec);
1107 /// Requests the expression to be emitted in a `statement'
1108 /// context. This means that no new value is left on the
1109 /// stack after invoking this method (constrasted with
1110 /// Emit that will always leave a value on the stack).
1112 public abstract void EmitStatement (EmitContext ec);
1114 public override void EmitSideEffect (EmitContext ec)
1121 /// This kind of cast is used to encapsulate the child
1122 /// whose type is child.Type into an expression that is
1123 /// reported to return "return_type". This is used to encapsulate
1124 /// expressions which have compatible types, but need to be dealt
1125 /// at higher levels with.
1127 /// For example, a "byte" expression could be encapsulated in one
1128 /// of these as an "unsigned int". The type for the expression
1129 /// would be "unsigned int".
1132 public abstract class TypeCast : Expression
1134 protected readonly Expression child;
1136 protected TypeCast (Expression child, TypeSpec return_type)
1138 eclass = child.eclass;
1139 loc = child.Location;
1144 public Expression Child {
1150 public override Expression CreateExpressionTree (ResolveContext ec)
1152 Arguments args = new Arguments (2);
1153 args.Add (new Argument (child.CreateExpressionTree (ec)));
1154 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1156 if (type.IsPointer || child.Type.IsPointer)
1157 Error_PointerInsideExpressionTree (ec);
1159 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1162 protected override Expression DoResolve (ResolveContext ec)
1164 // This should never be invoked, we are born in fully
1165 // initialized state.
1170 public override void Emit (EmitContext ec)
1175 public override SLE.Expression MakeExpression (BuilderContext ctx)
1177 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1178 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1179 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1182 protected override void CloneTo (CloneContext clonectx, Expression t)
1187 public override bool IsNull {
1188 get { return child.IsNull; }
1192 public class EmptyCast : TypeCast {
1193 EmptyCast (Expression child, TypeSpec target_type)
1194 : base (child, target_type)
1198 public static Expression Create (Expression child, TypeSpec type)
1200 Constant c = child as Constant;
1202 return new EmptyConstantCast (c, type);
1204 EmptyCast e = child as EmptyCast;
1206 return new EmptyCast (e.child, type);
1208 return new EmptyCast (child, type);
1211 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1213 child.EmitBranchable (ec, label, on_true);
1216 public override void EmitSideEffect (EmitContext ec)
1218 child.EmitSideEffect (ec);
1223 // Used for predefined class library user casts (no obsolete check, etc.)
1225 public class OperatorCast : TypeCast {
1226 MethodSpec conversion_operator;
1228 public OperatorCast (Expression child, TypeSpec target_type)
1229 : this (child, target_type, false)
1233 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1234 : base (child, target_type)
1236 conversion_operator = GetConversionOperator (find_explicit);
1237 if (conversion_operator == null)
1238 throw new InternalErrorException ("Outer conversion routine is out of sync");
1241 // Returns the implicit operator that converts from
1242 // 'child.Type' to our target type (type)
1243 MethodSpec GetConversionOperator (bool find_explicit)
1245 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1247 // Operators are always public
1248 var mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberKind.Operator,
1249 BindingRestriction.None, operator_name, 0, null);
1252 mi = TypeManager.MemberLookup (type, type, type, MemberKind.Operator,
1253 BindingRestriction.None, operator_name, 0, null);
1256 foreach (MethodSpec oper in mi) {
1257 AParametersCollection pd = oper.Parameters;
1259 if (pd.Types [0] == child.Type && oper.ReturnType == type)
1266 public override void Emit (EmitContext ec)
1269 ec.Emit (OpCodes.Call, conversion_operator);
1274 /// This is a numeric cast to a Decimal
1276 public class CastToDecimal : OperatorCast {
1277 public CastToDecimal (Expression child)
1278 : this (child, false)
1282 public CastToDecimal (Expression child, bool find_explicit)
1283 : base (child, TypeManager.decimal_type, find_explicit)
1289 /// This is an explicit numeric cast from a Decimal
1291 public class CastFromDecimal : TypeCast
1293 static Dictionary<TypeSpec, MethodSpec> operators;
1295 public CastFromDecimal (Expression child, TypeSpec return_type)
1296 : base (child, return_type)
1298 if (child.Type != TypeManager.decimal_type)
1299 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1302 // Returns the explicit operator that converts from an
1303 // express of type System.Decimal to 'type'.
1304 public Expression Resolve ()
1306 if (operators == null) {
1307 var all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1308 TypeManager.decimal_type, TypeManager.decimal_type, MemberKind.Operator,
1309 BindingRestriction.None, "op_Explicit", 0, null);
1311 operators = new Dictionary<TypeSpec, MethodSpec> ();
1312 foreach (MethodSpec oper in all_oper) {
1313 AParametersCollection pd = oper.Parameters;
1314 if (pd.Types [0] == TypeManager.decimal_type)
1315 operators.Add (oper.ReturnType, oper);
1319 return operators.ContainsKey (type) ? this : null;
1322 public override void Emit (EmitContext ec)
1326 ec.Emit (OpCodes.Call, operators [type]);
1329 public static void Reset ()
1337 // Constant specialization of EmptyCast.
1338 // We need to special case this since an empty cast of
1339 // a constant is still a constant.
1341 public class EmptyConstantCast : Constant
1343 public Constant child;
1345 public EmptyConstantCast (Constant child, TypeSpec type)
1346 : base (child.Location)
1349 throw new ArgumentNullException ("child");
1352 this.eclass = child.eclass;
1356 public override string AsString ()
1358 return child.AsString ();
1361 public override object GetValue ()
1363 return child.GetValue ();
1366 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1368 if (child.Type == target_type)
1371 // FIXME: check that 'type' can be converted to 'target_type' first
1372 return child.ConvertExplicitly (in_checked_context, target_type);
1375 public override Expression CreateExpressionTree (ResolveContext ec)
1377 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1378 child.CreateExpressionTree (ec),
1379 new TypeOf (new TypeExpression (type, loc), loc));
1382 Error_PointerInsideExpressionTree (ec);
1384 return CreateExpressionFactoryCall (ec, "Convert", args);
1387 public override bool IsDefaultValue {
1388 get { return child.IsDefaultValue; }
1391 public override bool IsNegative {
1392 get { return child.IsNegative; }
1395 public override bool IsNull {
1396 get { return child.IsNull; }
1399 public override bool IsOneInteger {
1400 get { return child.IsOneInteger; }
1403 public override bool IsZeroInteger {
1404 get { return child.IsZeroInteger; }
1407 protected override Expression DoResolve (ResolveContext rc)
1412 public override void Emit (EmitContext ec)
1417 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1419 child.EmitBranchable (ec, label, on_true);
1421 // Only to make verifier happy
1422 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1423 ec.Emit (OpCodes.Unbox_Any, type);
1426 public override void EmitSideEffect (EmitContext ec)
1428 child.EmitSideEffect (ec);
1431 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1433 // FIXME: Do we need to check user conversions?
1434 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1436 return child.ConvertImplicitly (rc, target_type);
1441 /// This class is used to wrap literals which belong inside Enums
1443 public class EnumConstant : Constant
1445 public Constant Child;
1447 public EnumConstant (Constant child, TypeSpec enum_type)
1448 : base (child.Location)
1451 this.type = enum_type;
1454 protected EnumConstant (Location loc)
1459 protected override Expression DoResolve (ResolveContext rc)
1461 Child = Child.Resolve (rc);
1462 this.eclass = ExprClass.Value;
1466 public override void Emit (EmitContext ec)
1471 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1473 Child.EncodeAttributeValue (rc, enc, Child.Type);
1476 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1478 Child.EmitBranchable (ec, label, on_true);
1481 public override void EmitSideEffect (EmitContext ec)
1483 Child.EmitSideEffect (ec);
1486 public override string GetSignatureForError()
1488 return TypeManager.CSharpName (Type);
1491 public override object GetValue ()
1493 return Child.GetValue ();
1496 public override object GetTypedValue ()
1498 // FIXME: runtime is not ready to work with just emited enums
1499 if (!RootContext.StdLib) {
1500 return Child.GetValue ();
1504 // Small workaround for big problem
1505 // System.Enum.ToObject cannot be called on dynamic types
1506 // EnumBuilder has to be used, but we cannot use EnumBuilder
1507 // because it does not properly support generics
1509 // This works only sometimes
1511 if (type.MemberDefinition is TypeContainer)
1512 return Child.GetValue ();
1515 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1518 public override string AsString ()
1520 return Child.AsString ();
1523 public EnumConstant Increment()
1525 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1528 public override bool IsDefaultValue {
1530 return Child.IsDefaultValue;
1534 public override bool IsZeroInteger {
1535 get { return Child.IsZeroInteger; }
1538 public override bool IsNegative {
1540 return Child.IsNegative;
1544 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1546 if (Child.Type == target_type)
1549 return Child.ConvertExplicitly (in_checked_context, target_type);
1552 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1554 if (this.type == type) {
1558 if (!Convert.ImplicitStandardConversionExists (this, type)){
1562 return Child.ConvertImplicitly (rc, type);
1567 /// This kind of cast is used to encapsulate Value Types in objects.
1569 /// The effect of it is to box the value type emitted by the previous
1572 public class BoxedCast : TypeCast {
1574 public BoxedCast (Expression expr, TypeSpec target_type)
1575 : base (expr, target_type)
1577 eclass = ExprClass.Value;
1580 protected override Expression DoResolve (ResolveContext ec)
1582 // This should never be invoked, we are born in fully
1583 // initialized state.
1588 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1590 enc.Encode (child.Type);
1591 child.EncodeAttributeValue (rc, enc, child.Type);
1594 public override void Emit (EmitContext ec)
1598 ec.Emit (OpCodes.Box, child.Type);
1601 public override void EmitSideEffect (EmitContext ec)
1603 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1604 // so, we need to emit the box+pop instructions in most cases
1605 if (TypeManager.IsStruct (child.Type) &&
1606 (type == TypeManager.object_type || type == TypeManager.value_type))
1607 child.EmitSideEffect (ec);
1609 base.EmitSideEffect (ec);
1613 public class UnboxCast : TypeCast {
1614 public UnboxCast (Expression expr, TypeSpec return_type)
1615 : base (expr, return_type)
1619 protected override Expression DoResolve (ResolveContext ec)
1621 // This should never be invoked, we are born in fully
1622 // initialized state.
1627 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1629 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1630 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1631 return base.DoResolveLValue (ec, right_side);
1634 public override void Emit (EmitContext ec)
1638 ec.Emit (OpCodes.Unbox_Any, type);
1643 /// This is used to perform explicit numeric conversions.
1645 /// Explicit numeric conversions might trigger exceptions in a checked
1646 /// context, so they should generate the conv.ovf opcodes instead of
1649 public class ConvCast : TypeCast {
1650 public enum Mode : byte {
1651 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1653 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1654 U2_I1, U2_U1, U2_I2, U2_CH,
1655 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1656 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1657 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1658 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1659 CH_I1, CH_U1, CH_I2,
1660 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1661 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1667 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1668 : base (child, return_type)
1673 protected override Expression DoResolve (ResolveContext ec)
1675 // This should never be invoked, we are born in fully
1676 // initialized state.
1681 public override string ToString ()
1683 return String.Format ("ConvCast ({0}, {1})", mode, child);
1686 public override void Emit (EmitContext ec)
1690 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1692 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1693 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1694 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1695 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1696 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1698 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1699 case Mode.U1_CH: /* nothing */ break;
1701 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1702 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1703 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1704 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1705 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1706 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1708 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1709 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1710 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1711 case Mode.U2_CH: /* nothing */ break;
1713 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1714 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1715 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1716 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1717 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1718 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1719 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1721 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1722 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1723 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1724 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1725 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1726 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1728 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1729 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1730 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1731 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1732 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1733 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1734 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1735 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1736 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1738 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1739 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1740 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1741 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1742 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1743 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1744 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1745 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1746 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1748 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1749 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1750 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1752 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1753 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1754 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1755 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1756 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1757 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1758 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1759 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1760 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1762 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1763 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1764 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1765 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1766 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1767 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1768 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1769 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1770 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1771 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1773 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1777 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1778 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1779 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1780 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1781 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1783 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1784 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1786 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1787 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1788 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1789 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1790 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1791 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1793 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1794 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1795 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1796 case Mode.U2_CH: /* nothing */ break;
1798 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1799 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1800 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1801 case Mode.I4_U4: /* nothing */ break;
1802 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1803 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1804 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1806 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1807 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1808 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1809 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1810 case Mode.U4_I4: /* nothing */ break;
1811 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1813 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1814 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1815 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1816 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1817 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1818 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1819 case Mode.I8_U8: /* nothing */ break;
1820 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1821 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1823 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1824 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1825 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1826 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1827 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1828 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1829 case Mode.U8_I8: /* nothing */ break;
1830 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1831 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1833 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1834 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1835 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1837 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1838 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1839 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1840 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1841 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1842 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1843 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1844 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1845 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1847 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1848 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1849 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1850 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1851 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1852 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1853 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1854 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1855 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1856 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1858 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1864 public class OpcodeCast : TypeCast {
1867 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1868 : base (child, return_type)
1873 protected override Expression DoResolve (ResolveContext ec)
1875 // This should never be invoked, we are born in fully
1876 // initialized state.
1881 public override void Emit (EmitContext ec)
1887 public TypeSpec UnderlyingType {
1888 get { return child.Type; }
1893 /// This kind of cast is used to encapsulate a child and cast it
1894 /// to the class requested
1896 public sealed class ClassCast : TypeCast {
1897 readonly bool forced;
1899 public ClassCast (Expression child, TypeSpec return_type)
1900 : base (child, return_type)
1904 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1905 : base (child, return_type)
1907 this.forced = forced;
1910 public override void Emit (EmitContext ec)
1914 bool gen = TypeManager.IsGenericParameter (child.Type);
1916 ec.Emit (OpCodes.Box, child.Type);
1918 if (type.IsGenericParameter) {
1919 ec.Emit (OpCodes.Unbox_Any, type);
1926 ec.Emit (OpCodes.Castclass, type);
1931 // Created during resolving pahse when an expression is wrapped or constantified
1932 // and original expression can be used later (e.g. for expression trees)
1934 public class ReducedExpression : Expression
1936 sealed class ReducedConstantExpression : EmptyConstantCast
1938 readonly Expression orig_expr;
1940 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1941 : base (expr, expr.Type)
1943 this.orig_expr = orig_expr;
1946 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1948 Constant c = base.ConvertImplicitly (rc, target_type);
1950 c = new ReducedConstantExpression (c, orig_expr);
1955 public override Expression CreateExpressionTree (ResolveContext ec)
1957 return orig_expr.CreateExpressionTree (ec);
1960 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1962 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1964 c = new ReducedConstantExpression (c, orig_expr);
1969 sealed class ReducedExpressionStatement : ExpressionStatement
1971 readonly Expression orig_expr;
1972 readonly ExpressionStatement stm;
1974 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1976 this.orig_expr = orig;
1978 this.loc = orig.Location;
1981 public override Expression CreateExpressionTree (ResolveContext ec)
1983 return orig_expr.CreateExpressionTree (ec);
1986 protected override Expression DoResolve (ResolveContext ec)
1988 eclass = stm.eclass;
1993 public override void Emit (EmitContext ec)
1998 public override void EmitStatement (EmitContext ec)
2000 stm.EmitStatement (ec);
2004 readonly Expression expr, orig_expr;
2006 private ReducedExpression (Expression expr, Expression orig_expr)
2009 this.eclass = expr.eclass;
2010 this.type = expr.Type;
2011 this.orig_expr = orig_expr;
2012 this.loc = orig_expr.Location;
2016 // Creates fully resolved expression switcher
2018 public static Constant Create (Constant expr, Expression original_expr)
2020 if (expr.eclass == ExprClass.Unresolved)
2021 throw new ArgumentException ("Unresolved expression");
2023 return new ReducedConstantExpression (expr, original_expr);
2026 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2028 return new ReducedExpressionStatement (s, orig);
2032 // Creates unresolved reduce expression. The original expression has to be
2035 public static Expression Create (Expression expr, Expression original_expr)
2037 Constant c = expr as Constant;
2039 return Create (c, original_expr);
2041 ExpressionStatement s = expr as ExpressionStatement;
2043 return Create (s, original_expr);
2045 if (expr.eclass == ExprClass.Unresolved)
2046 throw new ArgumentException ("Unresolved expression");
2048 return new ReducedExpression (expr, original_expr);
2051 public override Expression CreateExpressionTree (ResolveContext ec)
2053 return orig_expr.CreateExpressionTree (ec);
2056 protected override Expression DoResolve (ResolveContext ec)
2061 public override void Emit (EmitContext ec)
2066 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2068 expr.EmitBranchable (ec, target, on_true);
2071 public override SLE.Expression MakeExpression (BuilderContext ctx)
2073 return orig_expr.MakeExpression (ctx);
2078 // Standard composite pattern
2080 public abstract class CompositeExpression : Expression
2084 protected CompositeExpression (Expression expr)
2087 this.loc = expr.Location;
2090 public override Expression CreateExpressionTree (ResolveContext ec)
2092 return expr.CreateExpressionTree (ec);
2095 public Expression Child {
2096 get { return expr; }
2099 protected override Expression DoResolve (ResolveContext ec)
2101 expr = expr.Resolve (ec);
2104 eclass = expr.eclass;
2110 public override void Emit (EmitContext ec)
2115 public override bool IsNull {
2116 get { return expr.IsNull; }
2121 // Base of expressions used only to narrow resolve flow
2123 public abstract class ShimExpression : Expression
2125 protected Expression expr;
2127 protected ShimExpression (Expression expr)
2132 protected override void CloneTo (CloneContext clonectx, Expression t)
2137 ShimExpression target = (ShimExpression) t;
2138 target.expr = expr.Clone (clonectx);
2141 public override Expression CreateExpressionTree (ResolveContext ec)
2143 throw new NotSupportedException ("ET");
2146 public override void Emit (EmitContext ec)
2148 throw new InternalErrorException ("Missing Resolve call");
2151 public Expression Expr {
2152 get { return expr; }
2157 // Unresolved type name expressions
2159 public abstract class ATypeNameExpression : FullNamedExpression
2162 protected TypeArguments targs;
2164 protected ATypeNameExpression (string name, Location l)
2170 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2177 protected ATypeNameExpression (string name, int arity, Location l)
2178 : this (name, new UnboundTypeArguments (arity), l)
2184 protected int Arity {
2186 return targs == null ? 0 : targs.Count;
2190 public bool HasTypeArguments {
2192 return targs != null && !targs.IsEmpty;
2196 public string Name {
2205 public TypeArguments TypeArguments {
2213 public override bool Equals (object obj)
2215 ATypeNameExpression atne = obj as ATypeNameExpression;
2216 return atne != null && atne.Name == Name &&
2217 (targs == null || targs.Equals (atne.targs));
2220 public override int GetHashCode ()
2222 return Name.GetHashCode ();
2225 // TODO: Move it to MemberCore
2226 public static string GetMemberType (MemberCore mc)
2232 if (mc is FieldBase)
2234 if (mc is MethodCore)
2236 if (mc is EnumMember)
2244 public override string GetSignatureForError ()
2246 if (targs != null) {
2247 return Name + "<" + targs.GetSignatureForError () + ">";
2255 /// SimpleName expressions are formed of a single word and only happen at the beginning
2256 /// of a dotted-name.
2258 public class SimpleName : ATypeNameExpression
2260 public SimpleName (string name, Location l)
2265 public SimpleName (string name, TypeArguments args, Location l)
2266 : base (name, args, l)
2270 public SimpleName (string name, int arity, Location l)
2271 : base (name, arity, l)
2275 public SimpleName GetMethodGroup ()
2277 return new SimpleName (Name, targs, loc);
2280 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2282 if (ec.CurrentType != null) {
2283 if (ec.CurrentMemberDefinition != null) {
2284 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2286 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2292 // TODO MemberCache: Implement
2294 string ns = ec.CurrentType.Namespace;
2295 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2296 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2297 var type = a.GetType (fullname);
2299 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2300 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2305 if (ec.CurrentTypeDefinition != null) {
2306 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2308 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2315 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2316 if (retval != null) {
2317 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2319 var te = retval as TypeExpr;
2320 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2321 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2323 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2328 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2331 protected override Expression DoResolve (ResolveContext ec)
2333 return SimpleNameResolve (ec, null, false);
2336 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2338 return SimpleNameResolve (ec, right_side, false);
2341 public Expression DoResolve (ResolveContext ec, bool intermediate)
2343 return SimpleNameResolve (ec, null, intermediate);
2346 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2348 int errors = ec.Compiler.Report.Errors;
2349 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2352 if (fne.Type != null && Arity > 0) {
2353 if (HasTypeArguments) {
2354 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2355 return ct.ResolveAsTypeStep (ec, false);
2358 return new GenericOpenTypeExpr (fne.Type, loc);
2362 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2364 if (!(fne is Namespace))
2368 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2369 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2370 ec.Compiler.Report.Error (1980, Location,
2371 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2372 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2375 return new DynamicTypeExpr (loc);
2381 if (silent || errors != ec.Compiler.Report.Errors)
2384 Error_TypeOrNamespaceNotFound (ec);
2388 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2390 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2395 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2402 /// 7.5.2: Simple Names.
2404 /// Local Variables and Parameters are handled at
2405 /// parse time, so they never occur as SimpleNames.
2407 /// The `intermediate' flag is used by MemberAccess only
2408 /// and it is used to inform us that it is ok for us to
2409 /// avoid the static check, because MemberAccess might end
2410 /// up resolving the Name as a Type name and the access as
2411 /// a static type access.
2413 /// ie: Type Type; .... { Type.GetType (""); }
2415 /// Type is both an instance variable and a Type; Type.GetType
2416 /// is the static method not an instance method of type.
2418 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2420 Expression e = null;
2423 // Stage 1: Performed by the parser (binding to locals or parameters).
2425 Block current_block = ec.CurrentBlock;
2426 if (current_block != null){
2427 LocalInfo vi = current_block.GetLocalInfo (Name);
2429 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2431 if (right_side != null) {
2432 e = e.ResolveLValue (ec, right_side);
2435 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
2436 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2439 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2443 if (e != null && Arity > 0)
2444 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc, null, 0);
2449 e = current_block.Toplevel.GetParameterReference (Name, loc);
2451 if (right_side != null)
2452 e = e.ResolveLValue (ec, right_side);
2456 if (e != null && Arity > 0)
2457 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc, null, 0);
2464 // Stage 2: Lookup members
2466 int arity = HasTypeArguments ? Arity : -1;
2467 // TypeSpec almost_matched_type = null;
2468 // IList<MemberSpec> almost_matched = null;
2469 for (TypeSpec lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2470 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, arity, BindingRestriction.DefaultMemberLookup, loc);
2472 PropertyExpr pe = e as PropertyExpr;
2474 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2475 // it doesn't know which accessor to check permissions against
2476 if (pe.PropertyInfo.Kind == MemberKind.Property && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2478 } else if (e is EventExpr) {
2479 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2481 } else if (HasTypeArguments && e is TypeExpression) {
2482 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2490 if (almost_matched == null && almost_matched_members.Count > 0) {
2491 almost_matched_type = lookup_ds;
2492 almost_matched = new List<MemberSpec>(almost_matched_members);
2499 if (almost_matched == null && almost_matched_members.Count > 0) {
2500 almost_matched_type = ec.CurrentType;
2501 almost_matched = new List<MemberSpec> (almost_matched_members);
2504 e = ResolveAsTypeStep (ec, true);
2508 if (current_block != null) {
2509 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2511 LocalInfo li = ikv as LocalInfo;
2512 // Supress CS0219 warning
2516 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2521 if (RootContext.EvalMode){
2522 var fi = Evaluator.LookupField (Name);
2524 return new FieldExpr (fi.Item1, loc).Resolve (ec);
2527 if (almost_matched != null)
2528 almost_matched_members = almost_matched;
2529 if (almost_matched_type == null)
2530 almost_matched_type = ec.CurrentType;
2532 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2533 return Error_MemberLookupFailed (ec, ec.CurrentType, null, ec.CurrentType, Name, arity,
2534 type_name, MemberKind.All, BindingRestriction.AccessibleOnly);
2537 if (e is MemberExpr) {
2538 MemberExpr me = (MemberExpr) e;
2540 // TODO: It's used by EventExpr -> FieldExpr transformation only
2541 me = me.ResolveMemberAccess (ec, null, null);
2543 if (HasTypeArguments) {
2544 if (!targs.Resolve (ec))
2547 me.SetTypeArguments (ec, targs);
2553 return (right_side != null)
2554 ? me.DoResolveLValue (ec, right_side)
2563 /// Represents a namespace or a type. The name of the class was inspired by
2564 /// section 10.8.1 (Fully Qualified Names).
2566 public abstract class FullNamedExpression : Expression
2568 protected override void CloneTo (CloneContext clonectx, Expression target)
2570 // Do nothing, most unresolved type expressions cannot be
2571 // resolved to different type
2574 public override Expression CreateExpressionTree (ResolveContext ec)
2576 throw new NotSupportedException ("ET");
2579 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2584 public override void Emit (EmitContext ec)
2586 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2587 GetSignatureForError ());
2592 /// Expression that evaluates to a type
2594 public abstract class TypeExpr : FullNamedExpression {
2595 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2597 TypeExpr t = DoResolveAsTypeStep (ec);
2601 eclass = ExprClass.Type;
2605 protected override Expression DoResolve (ResolveContext ec)
2607 return ResolveAsTypeTerminal (ec, false);
2610 public virtual bool CheckAccessLevel (IMemberContext mc)
2612 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2614 c = mc.CurrentMemberDefinition.Parent;
2616 return c.CheckAccessLevel (Type);
2619 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2621 public override bool Equals (object obj)
2623 TypeExpr tobj = obj as TypeExpr;
2627 return Type == tobj.Type;
2630 public override int GetHashCode ()
2632 return Type.GetHashCode ();
2637 /// Fully resolved Expression that already evaluated to a type
2639 public class TypeExpression : TypeExpr {
2640 public TypeExpression (TypeSpec t, Location l)
2643 eclass = ExprClass.Type;
2647 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2652 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2659 /// This class denotes an expression which evaluates to a member
2660 /// of a struct or a class.
2662 public abstract class MemberExpr : Expression
2665 // An instance expression associated with this member, if it's a
2666 // non-static member
2668 public Expression InstanceExpression;
2671 /// The name of this member.
2673 public abstract string Name {
2678 // When base.member is used
2680 public bool IsBase {
2681 get { return QueriedBaseType != null; }
2685 // A type used for base.member lookup or null
2687 public TypeSpec QueriedBaseType { get; set; }
2690 /// Whether this is an instance member.
2692 public abstract bool IsInstance {
2697 /// Whether this is a static member.
2699 public abstract bool IsStatic {
2704 /// The type which declares this member.
2706 public abstract TypeSpec DeclaringType {
2710 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
2712 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
2716 // Converts best base candidate for virtual method starting from QueriedBaseType
2718 protected MethodSpec CandidateToBaseOverride (MethodSpec method)
2721 // Only when base.member is used
2723 if (QueriedBaseType == null || method.DeclaringType == QueriedBaseType)
2727 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2728 // means for base.member access we have to find the closest match after we found best candidate
2730 if ((method.Modifiers & Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC) != Modifiers.STATIC) {
2731 var base_override = MemberCache.FindMember (QueriedBaseType, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2732 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2733 if (base_override.IsGeneric)
2734 return base_override.MakeGenericMethod (method.TypeArguments);
2736 return base_override;
2744 // Implements identicial simple name and type-name
2746 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2749 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2752 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
2753 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2755 if (left is MemberExpr || left is VariableReference) {
2756 rc.Report.DisableReporting ();
2757 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2758 rc.Report.EnableReporting ();
2759 if (identical_type != null && identical_type.Type == left.Type)
2760 return identical_type;
2766 protected bool ResolveInstanceExpression (ResolveContext rc)
2769 if (InstanceExpression != null) {
2770 if (InstanceExpression is TypeExpr) {
2771 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2772 if (oa != null && !rc.IsObsolete) {
2773 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2776 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2777 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2778 rc.Report.Error (176, loc,
2779 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2780 GetSignatureForError ());
2784 InstanceExpression = null;
2790 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2791 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2792 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2793 rc.Report.Error (236, loc,
2794 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2795 GetSignatureForError ());
2797 rc.Report.Error (120, loc,
2798 "An object reference is required to access non-static member `{0}'",
2799 GetSignatureForError ());
2804 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2805 rc.Report.Error (38, loc,
2806 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2807 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2810 InstanceExpression = rc.GetThis (loc);
2814 var me = InstanceExpression as MemberExpr;
2816 me.ResolveInstanceExpression (rc);
2821 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2823 Constant c = left as Constant;
2824 if (c != null && c.GetValue () == null) {
2825 ec.Report.Warning (1720, 1, left.Location,
2826 "Expression will always cause a `{0}'", "System.NullReferenceException");
2829 InstanceExpression = left;
2833 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2835 if (TypeManager.IsValueType (InstanceExpression.Type)) {
2836 if (InstanceExpression is IMemoryLocation) {
2837 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2839 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2840 InstanceExpression.Emit (ec);
2842 t.AddressOf (ec, AddressOp.Store);
2845 InstanceExpression.Emit (ec);
2847 if (prepare_for_load)
2848 ec.Emit (OpCodes.Dup);
2851 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
2853 // TODO: need to get correct member type
2854 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
2855 GetSignatureForError ());
2860 /// Represents group of extension methods
2862 public class ExtensionMethodGroupExpr : MethodGroupExpr
2864 readonly NamespaceEntry namespace_entry;
2865 public Expression ExtensionExpression;
2867 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, TypeSpec extensionType, Location l)
2868 : base (list.Cast<MemberSpec>().ToList (), extensionType, l)
2870 this.namespace_entry = n;
2873 public override bool IsStatic {
2874 get { return true; }
2877 public bool IsTopLevel {
2878 get { return namespace_entry == null; }
2881 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
2883 if (arguments == null)
2884 arguments = new Arguments (1);
2886 arguments.Insert (0, new Argument (ExtensionExpression));
2887 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
2889 // Store resolved argument and restore original arguments
2891 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
2896 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
2898 // Use normal resolve rules
2899 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
2907 int arity = type_arguments == null ? -1 : type_arguments.Count;
2908 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, arity, loc);
2910 return base.OverloadResolve (ec, ref arguments, false, loc);
2912 e.ExtensionExpression = ExtensionExpression;
2913 e.SetTypeArguments (ec, type_arguments);
2914 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
2919 /// MethodGroupExpr represents a group of method candidates which
2920 /// can be resolved to the best method overload
2922 public class MethodGroupExpr : MemberExpr
2924 public interface IErrorHandler
2926 bool AmbiguousCall (ResolveContext ec, MethodGroupExpr mg, MethodSpec ambiguous);
2927 bool NoExactMatch (ResolveContext ec, MethodSpec method);
2930 public IErrorHandler CustomErrorHandler;
2931 protected IList<MemberSpec> Methods;
2932 MethodSpec best_candidate;
2933 // TODO: make private
2934 public TypeArguments type_arguments;
2935 SimpleName simple_name;
2936 bool has_inaccessible_candidates_only;
2937 TypeSpec delegate_type;
2938 TypeSpec queried_type;
2940 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location l)
2946 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location l)
2949 Methods = new List<MemberSpec> (1) { m };
2952 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location l, bool inacessibleCandidatesOnly)
2953 : this (mi, type, l)
2955 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
2958 protected MethodGroupExpr (TypeSpec type, Location loc)
2961 eclass = ExprClass.MethodGroup;
2962 this.type = InternalType.MethodGroup;
2963 queried_type = type;
2968 public override TypeSpec DeclaringType {
2970 return queried_type;
2974 public MethodSpec BestCandidate {
2976 return best_candidate;
2980 public TypeSpec DelegateType {
2982 delegate_type = value;
2989 // When best candidate is already know this factory can be used
2990 // NOTE: InstanceExpression has to be set manually
2992 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2994 return new MethodGroupExpr (best, queriedType, loc) {
2995 best_candidate = best
2999 public override string GetSignatureForError ()
3001 if (best_candidate != null)
3002 return best_candidate.GetSignatureForError ();
3004 return Methods.First ().GetSignatureForError ();
3007 public override string Name {
3009 return Methods.First ().Name;
3013 public override bool IsInstance {
3015 if (best_candidate != null)
3016 return !best_candidate.IsStatic;
3022 public override bool IsStatic {
3024 if (best_candidate != null)
3025 return best_candidate.IsStatic;
3031 public static explicit operator MethodSpec (MethodGroupExpr mg)
3033 return mg.best_candidate;
3037 // 7.4.3.3 Better conversion from expression
3038 // Returns : 1 if a->p is better,
3039 // 2 if a->q is better,
3040 // 0 if neither is better
3042 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3044 TypeSpec argument_type = a.Type;
3045 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3047 // Uwrap delegate from Expression<T>
3049 if (p.GetDefinition () == TypeManager.expression_type) {
3050 p = TypeManager.GetTypeArguments (p) [0];
3052 if (q.GetDefinition () == TypeManager.expression_type) {
3053 q = TypeManager.GetTypeArguments (q) [0];
3056 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3057 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3058 if (p == TypeManager.void_type && q != TypeManager.void_type)
3060 if (q == TypeManager.void_type && p != TypeManager.void_type)
3063 if (argument_type == p)
3066 if (argument_type == q)
3070 return BetterTypeConversion (ec, p, q);
3074 // 7.4.3.4 Better conversion from type
3076 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3078 if (p == null || q == null)
3079 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3081 if (p == TypeManager.int32_type) {
3082 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3084 } else if (p == TypeManager.int64_type) {
3085 if (q == TypeManager.uint64_type)
3087 } else if (p == TypeManager.sbyte_type) {
3088 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3089 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3091 } else if (p == TypeManager.short_type) {
3092 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3093 q == TypeManager.uint64_type)
3095 } else if (p == InternalType.Dynamic) {
3096 if (q == TypeManager.object_type)
3100 if (q == TypeManager.int32_type) {
3101 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3103 } if (q == TypeManager.int64_type) {
3104 if (p == TypeManager.uint64_type)
3106 } else if (q == TypeManager.sbyte_type) {
3107 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3108 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3110 } if (q == TypeManager.short_type) {
3111 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3112 p == TypeManager.uint64_type)
3114 } else if (q == InternalType.Dynamic) {
3115 if (p == TypeManager.object_type)
3119 // TODO: this is expensive
3120 Expression p_tmp = new EmptyExpression (p);
3121 Expression q_tmp = new EmptyExpression (q);
3123 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3124 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3126 if (p_to_q && !q_to_p)
3129 if (q_to_p && !p_to_q)
3136 /// Determines "Better function" between candidate
3137 /// and the current best match
3140 /// Returns a boolean indicating :
3141 /// false if candidate ain't better
3142 /// true if candidate is better than the current best match
3144 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3145 MethodSpec candidate, bool candidate_params,
3146 MethodSpec best, bool best_params)
3148 AParametersCollection candidate_pd = candidate.Parameters;
3149 AParametersCollection best_pd = best.Parameters;
3151 bool better_at_least_one = false;
3153 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3155 Argument a = args [j];
3157 // Provided default argument value is never better
3158 if (a.IsDefaultArgument && candidate_params == best_params)
3161 TypeSpec ct = candidate_pd.Types [c_idx];
3162 TypeSpec bt = best_pd.Types [b_idx];
3164 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3166 ct = TypeManager.GetElementType (ct);
3170 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3172 bt = TypeManager.GetElementType (bt);
3176 if (TypeManager.IsEqual (ct, bt))
3180 int result = BetterExpressionConversion (ec, a, ct, bt);
3182 // for each argument, the conversion to 'ct' should be no worse than
3183 // the conversion to 'bt'.
3187 // for at least one argument, the conversion to 'ct' should be better than
3188 // the conversion to 'bt'.
3190 better_at_least_one = true;
3193 if (better_at_least_one)
3197 // This handles the case
3199 // Add (float f1, float f2, float f3);
3200 // Add (params decimal [] foo);
3202 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3203 // first candidate would've chosen as better.
3209 // The two methods have equal parameter types. Now apply tie-breaking rules
3211 if (best.IsGeneric) {
3212 if (!candidate.IsGeneric)
3214 } else if (candidate.IsGeneric) {
3219 // This handles the following cases:
3221 // Trim () is better than Trim (params char[] chars)
3222 // Concat (string s1, string s2, string s3) is better than
3223 // Concat (string s1, params string [] srest)
3224 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3226 if (!candidate_params && best_params)
3228 if (candidate_params && !best_params)
3231 int candidate_param_count = candidate_pd.Count;
3232 int best_param_count = best_pd.Count;
3234 if (candidate_param_count != best_param_count)
3235 // can only happen if (candidate_params && best_params)
3236 return candidate_param_count > best_param_count && best_pd.HasParams;
3239 // Both methods have the same number of parameters, and the parameters have equal types
3240 // Pick the "more specific" signature using rules over original (non-inflated) types
3242 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3243 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3245 bool specific_at_least_once = false;
3246 for (int j = 0; j < candidate_param_count; ++j)
3248 var ct = candidate_def_pd.Types [j];
3249 var bt = best_def_pd.Types [j];
3252 TypeSpec specific = MoreSpecific (ct, bt);
3256 specific_at_least_once = true;
3259 if (specific_at_least_once)
3262 // FIXME: handle lifted operators
3268 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3270 simple_name = original;
3272 return base.ResolveMemberAccess (ec, left, original);
3275 public override Expression CreateExpressionTree (ResolveContext ec)
3277 if (best_candidate == null) {
3278 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3282 if (best_candidate.IsConditionallyExcluded (loc))
3283 ec.Report.Error (765, loc,
3284 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3286 return new TypeOfMethod (best_candidate, loc);
3289 protected override Expression DoResolve (ResolveContext ec)
3291 this.eclass = ExprClass.MethodGroup;
3293 if (InstanceExpression != null) {
3294 InstanceExpression = InstanceExpression.Resolve (ec);
3295 if (InstanceExpression == null)
3302 public void ReportUsageError (ResolveContext ec)
3304 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3305 Name + "()' is referenced without parentheses");
3308 override public void Emit (EmitContext ec)
3310 throw new NotSupportedException ();
3311 // ReportUsageError ();
3314 public void EmitCall (EmitContext ec, Arguments arguments)
3316 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3319 void Error_AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
3321 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, this, ambiguous))
3324 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3325 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3326 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
3329 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodSpec method,
3330 Argument a, AParametersCollection expected_par, TypeSpec paramType)
3332 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3334 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3335 ec.Report.SymbolRelatedToPreviousError (method);
3336 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3337 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3338 TypeManager.CSharpSignature (method));
3341 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3342 TypeManager.CSharpSignature (method));
3343 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3344 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3345 TypeManager.CSharpName (method.DeclaringType));
3347 ec.Report.SymbolRelatedToPreviousError (method);
3349 ec.Report.Error (1928, loc,
3350 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3351 emg.ExtensionExpression.GetSignatureForError (),
3352 emg.Name, TypeManager.CSharpSignature (method));
3354 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3355 TypeManager.CSharpSignature (method));
3359 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3361 string index = (idx + 1).ToString ();
3362 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3363 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3364 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3365 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3366 index, Parameter.GetModifierSignature (a.Modifier));
3368 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3369 index, Parameter.GetModifierSignature (mod));
3371 string p1 = a.GetSignatureForError ();
3372 string p2 = TypeManager.CSharpName (paramType);
3375 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3376 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3377 ec.Report.SymbolRelatedToPreviousError (paramType);
3380 if (idx == 0 && emg != null) {
3381 ec.Report.Error (1929, loc,
3382 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3384 ec.Report.Error (1503, loc,
3385 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3390 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3392 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3393 Name, TypeManager.CSharpName (target));
3396 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3398 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3399 Name, arg_count.ToString ());
3402 protected virtual int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
3404 return parameters.Count;
3407 protected virtual IList<MemberSpec> GetBaseTypeMethods (ResolveContext rc, TypeSpec type)
3409 var arity = type_arguments == null ? -1 : type_arguments.Count;
3411 return TypeManager.MemberLookup (rc.CurrentType, null, type,
3412 MemberKind.Method, BindingRestriction.AccessibleOnly | BindingRestriction.DefaultMemberLookup,
3416 bool GetBaseTypeMethods (ResolveContext rc)
3418 var base_type = Methods [0].DeclaringType.BaseType;
3419 if (base_type == null)
3422 var methods = GetBaseTypeMethods (rc, base_type);
3423 if (methods == null)
3431 /// Determines if the candidate method is applicable (section 14.4.2.1)
3432 /// to the given set of arguments
3433 /// A return value rates candidate method compatibility,
3434 /// 0 = the best, int.MaxValue = the worst
3436 public int IsApplicable (ResolveContext ec,
3437 ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form)
3439 var candidate = method;
3441 AParametersCollection pd = candidate.Parameters;
3442 int param_count = GetApplicableParametersCount (candidate, pd);
3443 int optional_count = 0;
3445 if (arg_count != param_count) {
3446 for (int i = 0; i < pd.Count; ++i) {
3447 if (pd.FixedParameters [i].HasDefaultValue) {
3448 optional_count = pd.Count - i;
3453 int args_gap = System.Math.Abs (arg_count - param_count);
3454 if (optional_count != 0) {
3455 if (args_gap > optional_count)
3456 return int.MaxValue - 10000 + args_gap - optional_count;
3458 // Readjust expected number when params used
3461 if (arg_count < param_count)
3463 } else if (arg_count > param_count) {
3464 return int.MaxValue - 10000 + args_gap;
3466 } else if (arg_count != param_count) {
3468 return int.MaxValue - 10000 + args_gap;
3469 if (arg_count < param_count - 1)
3470 return int.MaxValue - 10000 + args_gap;
3473 // Initialize expanded form of a method with 1 params parameter
3474 params_expanded_form = param_count == 1 && pd.HasParams;
3476 // Resize to fit optional arguments
3477 if (optional_count != 0) {
3479 if (arguments == null) {
3480 resized = new Arguments (optional_count);
3482 resized = new Arguments (param_count);
3483 resized.AddRange (arguments);
3486 for (int i = arg_count; i < param_count; ++i)
3488 arguments = resized;
3492 if (arg_count > 0) {
3494 // Shuffle named arguments to the right positions if there are any
3496 if (arguments [arg_count - 1] is NamedArgument) {
3497 arg_count = arguments.Count;
3499 for (int i = 0; i < arg_count; ++i) {
3500 bool arg_moved = false;
3502 NamedArgument na = arguments[i] as NamedArgument;
3506 int index = pd.GetParameterIndexByName (na.Name);
3508 // Named parameter not found or already reordered
3512 // When using parameters which should not be available to the user
3513 if (index >= param_count)
3517 arguments.MarkReorderedArgument (na);
3521 Argument temp = arguments[index];
3522 arguments[index] = arguments[i];
3523 arguments[i] = temp;
3530 arg_count = arguments.Count;
3532 } else if (arguments != null) {
3533 arg_count = arguments.Count;
3537 // 1. Handle generic method using type arguments when specified or type inference
3539 if (candidate.IsGeneric) {
3540 if (type_arguments != null) {
3541 var g_args_count = candidate.Arity;
3542 if (g_args_count != type_arguments.Count)
3543 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3545 method = candidate.MakeGenericMethod (type_arguments.Arguments);
3547 pd = candidate.Parameters;
3549 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3551 return score - 20000;
3553 pd = candidate.Parameters;
3556 if (type_arguments != null)
3557 return int.MaxValue - 15000;
3561 // 2. Each argument has to be implicitly convertible to method parameter
3564 Parameter.Modifier p_mod = 0;
3566 for (int i = 0; i < arg_count; i++) {
3567 Argument a = arguments [i];
3569 if (!pd.FixedParameters [i].HasDefaultValue)
3570 throw new InternalErrorException ();
3572 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3574 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3576 arguments [i] = new Argument (e, Argument.AType.Default);
3580 if (p_mod != Parameter.Modifier.PARAMS) {
3581 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3584 params_expanded_form = true;
3587 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3589 if (!params_expanded_form)
3590 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3592 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
3593 // It can be applicable in expanded form
3594 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3596 params_expanded_form = true;
3600 if (params_expanded_form)
3602 return (arg_count - i) * 2 + score;
3606 if (arg_count != param_count)
3607 params_expanded_form = true;
3612 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3615 // Types have to be identical when ref or out modifer is used
3617 if (arg_mod != 0 || param_mod != 0) {
3618 if (argument.Type != parameter) {
3619 if (argument.Type == InternalType.Dynamic)
3625 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3626 if (argument.Type == InternalType.Dynamic)
3633 if (arg_mod != param_mod)
3639 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3641 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3643 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3646 var ac_p = p as ArrayContainer;
3648 var ac_q = ((ArrayContainer) q);
3649 TypeSpec specific = MoreSpecific (ac_p.Element, (ac_q.Element));
3650 if (specific == ac_p.Element)
3652 if (specific == ac_q.Element)
3654 } else if (TypeManager.IsGenericType (p)) {
3655 var pargs = TypeManager.GetTypeArguments (p);
3656 var qargs = TypeManager.GetTypeArguments (q);
3658 bool p_specific_at_least_once = false;
3659 bool q_specific_at_least_once = false;
3661 for (int i = 0; i < pargs.Length; i++) {
3662 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3663 if (specific == pargs[i])
3664 p_specific_at_least_once = true;
3665 if (specific == qargs[i])
3666 q_specific_at_least_once = true;
3669 if (p_specific_at_least_once && !q_specific_at_least_once)
3671 if (!p_specific_at_least_once && q_specific_at_least_once)
3679 /// Find the Applicable Function Members (7.4.2.1)
3681 /// me: Method Group expression with the members to select.
3682 /// it might contain constructors or methods (or anything
3683 /// that maps to a method).
3685 /// Arguments: ArrayList containing resolved Argument objects.
3687 /// loc: The location if we want an error to be reported, or a Null
3688 /// location for "probing" purposes.
3690 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3691 /// that is the best match of me on Arguments.
3694 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
3695 bool may_fail, Location loc)
3697 // TODO: causes some issues with linq
3698 //if (best_candidate != null)
3701 var candidates = new List<MethodSpec> (2);
3702 List<MethodSpec> params_candidates = null;
3704 int arg_count = Arguments != null ? Arguments.Count : 0;
3705 Dictionary<MethodSpec, Arguments> candidates_expanded = null;
3706 Arguments candidate_args = Arguments;
3708 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
3710 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
3715 // Enable message recording, it's used mainly by lambda expressions
3717 var msg_recorder = new SessionReportPrinter ();
3718 var prev_recorder = ec.Report.SetPrinter (msg_recorder);
3722 // Methods in a base class are not candidates if any method in a derived
3723 // class is applicable
3725 int best_candidate_rate = int.MaxValue;
3727 foreach (var member in Methods) {
3728 var m = member as MethodSpec;
3730 // TODO: It's wrong when non-member is before applicable method
3731 // TODO: Should report only when at least 1 from the batch is applicable
3732 if (candidates.Count != 0) {
3733 ec.Report.SymbolRelatedToPreviousError (candidates[0]);
3734 ec.Report.SymbolRelatedToPreviousError (member);
3735 ec.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
3736 candidates[0].GetSignatureForError (), member.GetSignatureForError ());
3742 // Check if candidate is applicable (section 14.4.2.1)
3744 bool params_expanded_form = false;
3745 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref m, ref params_expanded_form);
3747 if (candidate_rate < best_candidate_rate) {
3748 best_candidate_rate = candidate_rate;
3752 if (params_expanded_form) {
3753 if (params_candidates == null)
3754 params_candidates = new List<MethodSpec> (2);
3755 params_candidates.Add (m);
3758 if (candidate_args != Arguments) {
3759 if (candidates_expanded == null)
3760 candidates_expanded = new Dictionary<MethodSpec, Arguments> (2);
3762 candidates_expanded.Add (m, candidate_args);
3763 candidate_args = Arguments;
3766 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
3767 if (msg_recorder != null)
3768 msg_recorder.EndSession ();
3772 msg_recorder = null;
3775 } while (candidates.Count == 0 && GetBaseTypeMethods (ec));
3777 ec.Report.SetPrinter (prev_recorder);
3780 int candidate_top = candidates.Count;
3781 if (candidate_top == 0) {
3783 // When we found a top level method which does not match and it's
3784 // not an extension method. We start extension methods lookup from here
3786 if (InstanceExpression != null) {
3787 var first = Methods.First ();
3788 var arity = type_arguments == null ? -1 : type_arguments.Count;
3789 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, first.Name, arity, loc);
3790 if (ex_method_lookup != null) {
3791 ex_method_lookup.ExtensionExpression = InstanceExpression.Resolve (ec);
3792 ex_method_lookup.SetTypeArguments (ec, type_arguments);
3793 var emg = ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
3799 if (msg_recorder != null && !msg_recorder.IsEmpty) {
3801 msg_recorder.Merge (prev_recorder);
3810 // Okay so we have failed to find exact match so we
3811 // return error info about the closest match
3813 if (best_candidate != null) {
3814 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
3817 bool params_expanded = params_candidates != null && params_candidates.Contains (best_candidate);
3818 if (NoExactMatch (ec, ref Arguments, params_expanded))
3823 // We failed to find any method with correct argument count
3825 if (Methods.First ().Kind == MemberKind.Constructor) {
3826 ec.Report.SymbolRelatedToPreviousError (queried_type);
3827 ec.Report.Error (1729, loc,
3828 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3829 TypeManager.CSharpName (queried_type), arg_count.ToString ());
3831 Error_ArgumentCountWrong (ec, arg_count);
3837 if (arg_count != 0 && Arguments.HasDynamic) {
3838 best_candidate = null;
3843 // Now we actually find the best method
3845 best_candidate = candidates [0];
3846 bool method_params = params_candidates != null && params_candidates.Contains (best_candidate);
3848 for (int ix = 1; ix < candidate_top; ix++) {
3849 var candidate = candidates [ix];
3851 if (candidate == best_candidate)
3854 bool cand_params = params_candidates != null && params_candidates.Contains (candidate);
3856 if (candidates_expanded != null && candidates_expanded.ContainsKey (candidate)) {
3857 candidate_args = candidates_expanded[candidate];
3858 arg_count = candidate_args.Count;
3861 if (BetterFunction (ec, candidate_args, arg_count,
3862 candidate, cand_params,
3863 best_candidate, method_params)) {
3864 best_candidate = candidate;
3865 method_params = cand_params;
3868 if (candidate_args != Arguments) {
3869 candidate_args = Arguments;
3870 arg_count = candidate_args != null ? candidate_args.Count : 0;
3874 if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) {
3875 candidate_args = candidates_expanded[best_candidate];
3876 arg_count = candidate_args.Count;
3880 // Now check that there are no ambiguities i.e the selected method
3881 // should be better than all the others
3883 MethodSpec ambiguous = null;
3884 for (int ix = 1; ix < candidate_top; ix++) {
3885 var candidate = candidates [ix];
3887 if (candidate == best_candidate)
3890 bool cand_params = params_candidates != null && params_candidates.Contains (candidate);
3891 if (!BetterFunction (ec, candidate_args, arg_count,
3892 best_candidate, method_params,
3893 candidate, cand_params))
3896 ec.Report.SymbolRelatedToPreviousError (candidate);
3897 ambiguous = candidate;
3901 if (ambiguous != null) {
3902 Error_AmbiguousCall (ec, ambiguous);
3907 best_candidate = CandidateToBaseOverride (best_candidate);
3910 // And now check if the arguments are all
3911 // compatible, perform conversions if
3912 // necessary etc. and return if everything is
3915 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
3916 method_params, may_fail, loc))
3919 if (best_candidate == null)
3922 if (best_candidate.Kind == MemberKind.Method) {
3923 if (InstanceExpression != null) {
3924 if (best_candidate.IsStatic && simple_name != null) {
3925 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3928 InstanceExpression.Resolve (ec);
3931 ResolveInstanceExpression (ec);
3934 if (best_candidate.IsGeneric) {
3935 ConstraintChecker.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments,
3936 best_candidate.Constraints, loc, ec.Report);
3940 // Check ObsoleteAttribute on the best method
3942 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
3943 if (oa != null && !ec.IsObsolete)
3944 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
3946 best_candidate.MemberDefinition.SetIsUsed ();
3948 Arguments = candidate_args;
3952 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, bool params_expanded)
3954 AParametersCollection pd = best_candidate.Parameters;
3955 int arg_count = Arguments == null ? 0 : Arguments.Count;
3957 if (arg_count == pd.Count || pd.HasParams) {
3958 if (best_candidate.IsGeneric) {
3959 if (type_arguments == null) {
3960 ec.Report.Error (411, loc,
3961 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
3962 best_candidate.GetGenericMethodDefinition().GetSignatureForError ());
3967 var ta = type_arguments == null ? 0 : type_arguments.Count;
3968 if (ta != best_candidate.Arity) {
3969 Error_TypeArgumentsCannotBeUsed (ec.Report, loc, best_candidate, type_arguments.Count);
3973 if (has_inaccessible_candidates_only) {
3974 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
3975 // Although a derived class can access protected members of
3976 // its base class it cannot do so through an instance of the
3977 // base class (CS1540). If the qualifier_type is a base of the
3978 // ec.CurrentType and the lookup succeeds with the latter one,
3979 // then we are in this situation.
3980 Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType);
3982 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3983 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
3987 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, params_expanded, false, loc))
3990 if (has_inaccessible_candidates_only)
3997 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3999 type_arguments = ta;
4002 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4003 int arg_count, MethodSpec method,
4004 bool chose_params_expanded,
4005 bool may_fail, Location loc)
4007 AParametersCollection pd = method.Parameters;
4008 int param_count = GetApplicableParametersCount (method, pd);
4010 int errors = ec.Report.Errors;
4011 Parameter.Modifier p_mod = 0;
4013 int a_idx = 0, a_pos = 0;
4015 ArrayInitializer params_initializers = null;
4016 bool has_unsafe_arg = method.ReturnType.IsPointer;
4018 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4019 a = arguments [a_idx];
4020 if (p_mod != Parameter.Modifier.PARAMS) {
4021 p_mod = pd.FixedParameters [a_idx].ModFlags;
4022 pt = pd.Types [a_idx];
4023 has_unsafe_arg |= pt.IsPointer;
4025 if (p_mod == Parameter.Modifier.PARAMS) {
4026 if (chose_params_expanded) {
4027 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4028 pt = TypeManager.GetElementType (pt);
4034 // Types have to be identical when ref or out modifer is used
4036 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4037 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4040 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4045 NamedArgument na = a as NamedArgument;
4047 int name_index = pd.GetParameterIndexByName (na.Name);
4048 if (name_index < 0 || name_index >= param_count) {
4049 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4050 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4051 ec.Report.Error (1746, na.Location,
4052 "The delegate `{0}' does not contain a parameter named `{1}'",
4053 TypeManager.CSharpName (DeclaringType), na.Name);
4055 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4056 ec.Report.Error (1739, na.Location,
4057 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4058 TypeManager.CSharpSignature (method), na.Name);
4060 } else if (arguments[name_index] != a) {
4061 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4062 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4064 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4066 ec.Report.Error (1744, na.Location,
4067 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4073 if (a.Expr.Type == InternalType.Dynamic)
4076 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4079 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4084 // Convert params arguments to an array initializer
4086 if (params_initializers != null) {
4087 // we choose to use 'a.Expr' rather than 'conv' so that
4088 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4089 params_initializers.Add (a.Expr);
4090 arguments.RemoveAt (a_idx--);
4095 // Update the argument with the implicit conversion
4099 if (a_idx != arg_count) {
4100 if (!may_fail && ec.Report.Errors == errors) {
4101 if (CustomErrorHandler != null)
4102 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4104 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4110 // Fill not provided arguments required by params modifier
4112 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4113 if (arguments == null)
4114 arguments = new Arguments (1);
4116 pt = pd.Types [param_count - 1];
4117 pt = TypeManager.GetElementType (pt);
4118 has_unsafe_arg |= pt.IsPointer;
4119 params_initializers = new ArrayInitializer (0, loc);
4123 // Append an array argument with all params arguments
4125 if (params_initializers != null) {
4126 arguments.Add (new Argument (
4127 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4131 if (arg_count < param_count) {
4133 Error_ArgumentCountWrong (ec, arg_count);
4137 if (has_unsafe_arg && !ec.IsUnsafe) {
4139 UnsafeError (ec, loc);
4147 public class ConstantExpr : MemberExpr
4151 public ConstantExpr (ConstSpec constant, Location loc)
4153 this.constant = constant;
4157 public override string Name {
4158 get { throw new NotImplementedException (); }
4161 public override bool IsInstance {
4162 get { return !IsStatic; }
4165 public override bool IsStatic {
4166 get { return true; }
4169 public override TypeSpec DeclaringType {
4170 get { return constant.DeclaringType; }
4173 public override Expression CreateExpressionTree (ResolveContext ec)
4175 throw new NotSupportedException ("ET");
4178 protected override Expression DoResolve (ResolveContext rc)
4180 constant.MemberDefinition.SetIsUsed ();
4182 ResolveInstanceExpression (rc);
4184 if (!rc.IsObsolete) {
4185 var oa = constant.GetAttributeObsolete ();
4187 AttributeTester.Report_ObsoleteMessage (oa, constant.GetSignatureForError (), loc, rc.Report);
4190 var c = constant.GetConstant (rc);
4192 // Creates reference expression to the constant value
4193 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4196 public override void Emit (EmitContext ec)
4198 throw new NotSupportedException ();
4201 public override string GetSignatureForError ()
4203 return constant.GetSignatureForError ();
4208 /// Fully resolved expression that evaluates to a Field
4210 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4211 protected FieldSpec spec;
4212 VariableInfo variable_info;
4214 LocalTemporary temp;
4217 protected FieldExpr (Location l)
4222 public FieldExpr (FieldSpec spec, Location loc)
4227 type = spec.MemberType;
4230 public FieldExpr (FieldBase fi, Location l)
4235 public override string Name {
4241 public override bool IsInstance {
4243 return !spec.IsStatic;
4247 public override bool IsStatic {
4249 return spec.IsStatic;
4253 public FieldSpec Spec {
4259 public override TypeSpec DeclaringType {
4261 return spec.DeclaringType;
4265 public override string GetSignatureForError ()
4267 return TypeManager.GetFullNameSignature (spec);
4270 public VariableInfo VariableInfo {
4272 return variable_info;
4276 public void SetHasAddressTaken ()
4278 IVariableReference vr = InstanceExpression as IVariableReference;
4280 vr.SetHasAddressTaken ();
4283 public override Expression CreateExpressionTree (ResolveContext ec)
4285 Expression instance;
4286 if (InstanceExpression == null) {
4287 instance = new NullLiteral (loc);
4289 instance = InstanceExpression.CreateExpressionTree (ec);
4292 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4294 CreateTypeOfExpression ());
4296 return CreateExpressionFactoryCall (ec, "Field", args);
4299 public Expression CreateTypeOfExpression ()
4301 return new TypeOfField (spec, loc);
4304 protected override Expression DoResolve (ResolveContext ec)
4306 return DoResolve (ec, false, false);
4309 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4311 if (ResolveInstanceExpression (ec)) {
4312 // Resolve the field's instance expression while flow analysis is turned
4313 // off: when accessing a field "a.b", we must check whether the field
4314 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4316 if (lvalue_instance) {
4317 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4318 Expression right_side =
4319 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4321 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4324 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4325 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4329 if (InstanceExpression == null)
4332 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4333 InstanceExpression.CheckMarshalByRefAccess (ec);
4337 if (type.IsPointer && !ec.IsUnsafe) {
4338 UnsafeError (ec, loc);
4341 if (!ec.IsObsolete) {
4342 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
4344 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (spec), loc, ec.Report);
4347 var fb = spec as FixedFieldSpec;
4348 IVariableReference var = InstanceExpression as IVariableReference;
4350 if (lvalue_instance && var != null && var.VariableInfo != null) {
4351 var.VariableInfo.SetFieldAssigned (ec, Name);
4355 IFixedExpression fe = InstanceExpression as IFixedExpression;
4356 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4357 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4360 if (InstanceExpression.eclass != ExprClass.Variable) {
4361 ec.Report.SymbolRelatedToPreviousError (spec);
4362 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4363 TypeManager.GetFullNameSignature (spec));
4364 } else if (var != null && var.IsHoisted) {
4365 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4368 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4371 eclass = ExprClass.Variable;
4373 // If the instance expression is a local variable or parameter.
4374 if (var == null || var.VariableInfo == null)
4377 VariableInfo vi = var.VariableInfo;
4378 if (!vi.IsFieldAssigned (ec, Name, loc))
4381 variable_info = vi.GetSubStruct (Name);
4385 static readonly int [] codes = {
4386 191, // instance, write access
4387 192, // instance, out access
4388 198, // static, write access
4389 199, // static, out access
4390 1648, // member of value instance, write access
4391 1649, // member of value instance, out access
4392 1650, // member of value static, write access
4393 1651 // member of value static, out access
4396 static readonly string [] msgs = {
4397 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4398 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4399 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4400 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4401 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4402 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4403 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4404 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4407 // The return value is always null. Returning a value simplifies calling code.
4408 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4411 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4415 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4417 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4422 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4424 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4425 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4427 Expression e = DoResolve (ec, lvalue_instance, out_access);
4432 spec.MemberDefinition.SetIsAssigned ();
4434 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4435 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4436 ec.Report.Warning (420, 1, loc,
4437 "`{0}': A volatile field references will not be treated as volatile",
4438 spec.GetSignatureForError ());
4441 if (spec.IsReadOnly) {
4442 // InitOnly fields can only be assigned in constructors or initializers
4443 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4444 return Report_AssignToReadonly (ec, right_side);
4446 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4448 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4449 if (!TypeManager.IsEqual (ec.CurrentMemberDefinition.Parent.Definition, DeclaringType.GetDefinition ()))
4450 return Report_AssignToReadonly (ec, right_side);
4451 // static InitOnly fields cannot be assigned-to in an instance constructor
4452 if (IsStatic && !ec.IsStatic)
4453 return Report_AssignToReadonly (ec, right_side);
4454 // instance constructors can't modify InitOnly fields of other instances of the same type
4455 if (!IsStatic && !(InstanceExpression is This))
4456 return Report_AssignToReadonly (ec, right_side);
4460 if (right_side == EmptyExpression.OutAccess.Instance &&
4461 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4462 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4463 ec.Report.Warning (197, 1, loc,
4464 "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",
4465 GetSignatureForError ());
4468 eclass = ExprClass.Variable;
4472 bool is_marshal_by_ref ()
4474 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4477 public override void CheckMarshalByRefAccess (ResolveContext ec)
4479 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4480 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4481 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",
4482 GetSignatureForError ());
4486 public override int GetHashCode ()
4488 return spec.GetHashCode ();
4491 public bool IsFixed {
4494 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4496 IVariableReference variable = InstanceExpression as IVariableReference;
4497 if (variable != null)
4498 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4500 IFixedExpression fe = InstanceExpression as IFixedExpression;
4501 return fe != null && fe.IsFixed;
4505 public bool IsHoisted {
4507 IVariableReference hv = InstanceExpression as IVariableReference;
4508 return hv != null && hv.IsHoisted;
4512 public override bool Equals (object obj)
4514 FieldExpr fe = obj as FieldExpr;
4518 if (spec != fe.spec)
4521 if (InstanceExpression == null || fe.InstanceExpression == null)
4524 return InstanceExpression.Equals (fe.InstanceExpression);
4527 public void Emit (EmitContext ec, bool leave_copy)
4529 bool is_volatile = false;
4531 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4534 spec.MemberDefinition.SetIsUsed ();
4538 ec.Emit (OpCodes.Volatile);
4540 ec.Emit (OpCodes.Ldsfld, spec);
4543 EmitInstance (ec, false);
4545 // Optimization for build-in types
4546 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
4547 ec.EmitLoadFromPtr (type);
4549 var ff = spec as FixedFieldSpec;
4551 ec.Emit (OpCodes.Ldflda, spec);
4552 ec.Emit (OpCodes.Ldflda, ff.Element);
4555 ec.Emit (OpCodes.Volatile);
4557 ec.Emit (OpCodes.Ldfld, spec);
4563 ec.Emit (OpCodes.Dup);
4565 temp = new LocalTemporary (this.Type);
4571 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4573 prepared = prepare_for_load;
4575 EmitInstance (ec, prepared);
4579 ec.Emit (OpCodes.Dup);
4581 temp = new LocalTemporary (this.Type);
4586 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4587 ec.Emit (OpCodes.Volatile);
4589 spec.MemberDefinition.SetIsAssigned ();
4592 ec.Emit (OpCodes.Stsfld, spec);
4594 ec.Emit (OpCodes.Stfld, spec);
4603 public override void Emit (EmitContext ec)
4608 public override void EmitSideEffect (EmitContext ec)
4610 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4612 if (is_volatile || is_marshal_by_ref ())
4613 base.EmitSideEffect (ec);
4616 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
4619 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
4620 name, GetSignatureForError ());
4623 public void AddressOf (EmitContext ec, AddressOp mode)
4625 if ((mode & AddressOp.Store) != 0)
4626 spec.MemberDefinition.SetIsAssigned ();
4627 if ((mode & AddressOp.Load) != 0)
4628 spec.MemberDefinition.SetIsUsed ();
4631 // Handle initonly fields specially: make a copy and then
4632 // get the address of the copy.
4635 if (spec.IsReadOnly){
4637 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4650 local = ec.DeclareLocal (type, false);
4651 ec.Emit (OpCodes.Stloc, local);
4652 ec.Emit (OpCodes.Ldloca, local);
4658 ec.Emit (OpCodes.Ldsflda, spec);
4661 EmitInstance (ec, false);
4662 ec.Emit (OpCodes.Ldflda, spec);
4666 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
4668 return MakeExpression (ctx);
4671 public override SLE.Expression MakeExpression (BuilderContext ctx)
4673 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4679 /// Expression that evaluates to a Property. The Assign class
4680 /// might set the `Value' expression if we are in an assignment.
4682 /// This is not an LValue because we need to re-write the expression, we
4683 /// can not take data from the stack and store it.
4685 public class PropertyExpr : MemberExpr, IDynamicAssign
4689 // getter and setter can be different for base calls
4690 MethodSpec getter, setter;
4692 TypeArguments targs;
4693 LocalTemporary temp;
4696 public PropertyExpr (PropertySpec spec, Location l)
4701 type = spec.MemberType;
4706 public override string Name {
4712 public override bool IsInstance {
4718 public override bool IsStatic {
4720 return spec.IsStatic;
4724 public PropertySpec PropertyInfo {
4732 public override Expression CreateExpressionTree (ResolveContext ec)
4735 if (IsSingleDimensionalArrayLength ()) {
4736 args = new Arguments (1);
4737 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4738 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4742 Error_BaseAccessInExpressionTree (ec, loc);
4746 args = new Arguments (2);
4747 if (InstanceExpression == null)
4748 args.Add (new Argument (new NullLiteral (loc)));
4750 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4751 args.Add (new Argument (new TypeOfMethod (spec.Get, loc)));
4752 return CreateExpressionFactoryCall (ec, "Property", args);
4755 public Expression CreateSetterTypeOfExpression ()
4757 return new TypeOfMethod (setter, loc);
4760 public override TypeSpec DeclaringType {
4762 return spec.DeclaringType;
4766 public override string GetSignatureForError ()
4768 return TypeManager.GetFullNameSignature (spec);
4771 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
4773 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) spec.Set.GetMetaInfo ());
4776 public override SLE.Expression MakeExpression (BuilderContext ctx)
4778 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) spec.Get.GetMetaInfo ());
4781 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
4783 if (!ResolveInstanceExpression (ec))
4786 InstanceExpression = InstanceExpression.Resolve (ec);
4787 if (lvalue_instance && InstanceExpression != null)
4788 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
4790 if (InstanceExpression == null)
4793 InstanceExpression.CheckMarshalByRefAccess (ec);
4795 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
4796 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
4797 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
4798 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
4799 ec.Report.SymbolRelatedToPreviousError (spec);
4800 Error_CannotAccessProtected (ec, loc, spec, InstanceExpression.Type, ec.CurrentType);
4807 void Error_PropertyNotValid (ResolveContext ec)
4809 ec.Report.SymbolRelatedToPreviousError (spec);
4810 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4811 GetSignatureForError ());
4814 public bool IsAccessibleFrom (TypeSpec invocation_type, bool lvalue)
4817 var accessor = lvalue ? spec.Set : spec.Get;
4818 if (accessor == null && lvalue)
4819 accessor = spec.Get;
4820 return accessor != null && IsMemberAccessible (invocation_type, accessor, out dummy);
4823 bool IsSingleDimensionalArrayLength ()
4825 if (DeclaringType != TypeManager.array_type || !spec.HasGet || Name != "Length")
4828 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4829 return ac != null && ac.Rank == 1;
4832 protected override Expression DoResolve (ResolveContext ec)
4834 eclass = ExprClass.PropertyAccess;
4836 bool must_do_cs1540_check = false;
4837 ec.Report.DisableReporting ();
4838 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
4839 ec.Report.EnableReporting ();
4842 if (InstanceExpression != null) {
4843 TypeSpec expr_type = InstanceExpression.Type;
4844 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, 0, loc);
4845 if (ex_method_lookup != null) {
4846 ex_method_lookup.ExtensionExpression = InstanceExpression;
4847 ex_method_lookup.SetTypeArguments (ec, targs);
4848 return ex_method_lookup.Resolve (ec);
4852 ResolveGetter (ec, ref must_do_cs1540_check);
4856 if (!InstanceResolve (ec, false, must_do_cs1540_check))
4859 if (type.IsPointer && !ec.IsUnsafe) {
4860 UnsafeError (ec, loc);
4863 getter = CandidateToBaseOverride (spec.Get);
4866 // Only base will allow this invocation to happen.
4868 if (IsBase && getter.IsAbstract) {
4869 Error_CannotCallAbstractBase (ec, spec.GetSignatureForError ());
4872 if (!ec.IsObsolete) {
4873 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
4875 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4881 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4883 eclass = ExprClass.PropertyAccess;
4885 if (right_side == EmptyExpression.OutAccess.Instance) {
4886 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
4887 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
4890 right_side.DoResolveLValue (ec, this);
4895 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4896 Error_CannotModifyIntermediateExpressionValue (ec);
4899 if (spec.IsNotRealProperty) {
4900 Error_PropertyNotValid (ec);
4905 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
4906 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
4909 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
4910 GetSignatureForError ());
4915 if (targs != null) {
4916 base.SetTypeArguments (ec, targs);
4920 bool must_do_cs1540_check;
4921 if (!IsMemberAccessible (ec.CurrentType, spec.Set, out must_do_cs1540_check)) {
4922 if (spec.HasDifferentAccessibility) {
4923 ec.Report.SymbolRelatedToPreviousError (spec.Set);
4924 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
4925 TypeManager.CSharpSignature (spec));
4927 ec.Report.SymbolRelatedToPreviousError (spec.Set);
4928 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.Set), ec.Report);
4933 if (!InstanceResolve (ec, TypeManager.IsStruct (spec.DeclaringType), must_do_cs1540_check))
4936 setter = CandidateToBaseOverride (spec.Set);
4939 // Only base will allow this invocation to happen.
4941 if (IsBase && setter.IsAbstract){
4942 Error_CannotCallAbstractBase (ec, setter.GetSignatureForError ());
4945 if (spec.MemberType.IsPointer && !ec.IsUnsafe) {
4946 UnsafeError (ec, loc);
4949 if (!ec.IsObsolete) {
4950 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
4952 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4958 public override void Emit (EmitContext ec)
4963 public void Emit (EmitContext ec, bool leave_copy)
4966 // Special case: length of single dimension array property is turned into ldlen
4968 if (IsSingleDimensionalArrayLength ()) {
4970 EmitInstance (ec, false);
4971 ec.Emit (OpCodes.Ldlen);
4972 ec.Emit (OpCodes.Conv_I4);
4976 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
4979 ec.Emit (OpCodes.Dup);
4981 temp = new LocalTemporary (this.Type);
4988 // Implements the IAssignMethod interface for assignments
4990 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4992 Expression my_source = source;
4994 if (prepare_for_load) {
4999 ec.Emit (OpCodes.Dup);
5001 temp = new LocalTemporary (this.Type);
5005 } else if (leave_copy) {
5007 temp = new LocalTemporary (this.Type);
5012 Arguments args = new Arguments (1);
5013 args.Add (new Argument (my_source));
5015 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5023 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5025 if (targs != null) {
5026 base.SetTypeArguments (ec, targs);
5030 if (spec.IsNotRealProperty) {
5031 Error_PropertyNotValid (ec);
5036 if (InstanceExpression != EmptyExpression.Null) {
5037 ec.Report.SymbolRelatedToPreviousError (spec);
5038 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5039 spec.GetSignatureForError ());
5044 if (spec.HasGet && !IsMemberAccessible (ec.CurrentType, spec.Get, out must_do_cs1540_check)) {
5045 if (spec.HasDifferentAccessibility) {
5046 ec.Report.SymbolRelatedToPreviousError (spec.Get);
5047 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5048 TypeManager.CSharpSignature (spec));
5050 ec.Report.SymbolRelatedToPreviousError (spec.Get);
5051 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.Get), ec.Report);
5060 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5067 /// Fully resolved expression that evaluates to an Event
5069 public class EventExpr : MemberExpr
5071 readonly EventSpec spec;
5073 public EventExpr (EventSpec spec, Location loc)
5079 public override string Name {
5085 public override bool IsInstance {
5087 return !spec.IsStatic;
5091 public override bool IsStatic {
5093 return spec.IsStatic;
5097 public override TypeSpec DeclaringType {
5099 return spec.DeclaringType;
5103 public void Error_AssignmentEventOnly (ResolveContext ec)
5105 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5106 GetSignatureForError ());
5109 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5112 // If the event is local to this class, we transform ourselves into a FieldExpr
5115 if (spec.DeclaringType == ec.CurrentType ||
5116 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5118 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5119 // EventField mi = spec.MemberDefinition as EventField;
5121 if (spec.BackingField != null) {
5122 spec.MemberDefinition.SetIsUsed ();
5124 if (!ec.IsObsolete) {
5125 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5127 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5130 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5131 Error_AssignmentEventOnly (ec);
5133 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5135 InstanceExpression = null;
5137 return ml.ResolveMemberAccess (ec, left, original);
5141 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5142 Error_AssignmentEventOnly (ec);
5144 return base.ResolveMemberAccess (ec, left, original);
5147 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5149 if (IsBase && spec.IsAbstract) {
5150 Error_CannotCallAbstractBase (ec, spec.GetSignatureForError ());
5153 if (!ResolveInstanceExpression (ec))
5156 InstanceExpression.Resolve (ec);
5159 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5160 // However, in the Event case, we reported a CS0122 instead.
5162 // TODO: Exact copy from PropertyExpr
5164 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5165 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5166 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5167 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5168 ec.Report.SymbolRelatedToPreviousError (spec);
5169 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec), ec.Report);
5176 public bool IsAccessibleFrom (TypeSpec invocation_type)
5179 return IsMemberAccessible (invocation_type, spec.AccessorAdd, out dummy) &&
5180 IsMemberAccessible (invocation_type, spec.AccessorRemove, out dummy);
5183 public override Expression CreateExpressionTree (ResolveContext ec)
5185 throw new NotSupportedException ("ET");
5188 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5190 // contexts where an LValue is valid have already devolved to FieldExprs
5191 Error_CannotAssign (ec);
5195 protected override Expression DoResolve (ResolveContext ec)
5197 eclass = ExprClass.EventAccess;
5199 bool must_do_cs1540_check;
5200 if (!(IsMemberAccessible (ec.CurrentType, spec.AccessorAdd, out must_do_cs1540_check) &&
5201 IsMemberAccessible (ec.CurrentType, spec.AccessorRemove, out must_do_cs1540_check))) {
5202 ec.Report.SymbolRelatedToPreviousError (spec);
5203 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec), ec.Report);
5207 type = spec.MemberType;
5209 if (!InstanceResolve (ec, must_do_cs1540_check))
5212 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5213 Error_CannotAssign (ec);
5217 if (!ec.IsObsolete) {
5218 var oa = spec.GetAttributeObsolete ();
5220 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5223 spec.MemberDefinition.SetIsUsed ();
5228 public override void Emit (EmitContext ec)
5230 throw new NotSupportedException ();
5231 //Error_CannotAssign ();
5234 public void Error_CannotAssign (ResolveContext ec)
5236 ec.Report.Error (70, loc,
5237 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5238 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5241 public override string GetSignatureForError ()
5243 return TypeManager.CSharpSignature (spec);
5246 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5248 Arguments args = new Arguments (1);
5249 args.Add (new Argument (source));
5250 Invocation.EmitCall (ec, IsBase, InstanceExpression,
5251 is_add ? spec.AccessorAdd : spec.AccessorRemove,
5256 public class TemporaryVariable : VariableReference
5260 public TemporaryVariable (TypeSpec type, Location loc)
5266 public override Expression CreateExpressionTree (ResolveContext ec)
5268 throw new NotSupportedException ("ET");
5271 protected override Expression DoResolve (ResolveContext ec)
5273 eclass = ExprClass.Variable;
5275 TypeExpr te = new TypeExpression (type, loc);
5276 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5277 if (!li.Resolve (ec))
5281 // Don't capture temporary variables except when using
5282 // iterator redirection
5284 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5285 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5286 storey.CaptureLocalVariable (ec, li);
5292 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5294 return Resolve (ec);
5297 public override void Emit (EmitContext ec)
5302 public void EmitAssign (EmitContext ec, Expression source)
5304 EmitAssign (ec, source, false, false);
5307 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5309 return li.HoistedVariant;
5312 public override bool IsFixed {
5313 get { return true; }
5316 public override bool IsRef {
5317 get { return false; }
5320 public override string Name {
5321 get { throw new NotImplementedException (); }
5324 public override void SetHasAddressTaken ()
5326 throw new NotImplementedException ();
5329 protected override ILocalVariable Variable {
5333 public override VariableInfo VariableInfo {
5334 get { throw new NotImplementedException (); }
5339 /// Handles `var' contextual keyword; var becomes a keyword only
5340 /// if no type called var exists in a variable scope
5342 class VarExpr : SimpleName
5344 // Used for error reporting only
5345 int initializers_count;
5347 public VarExpr (Location loc)
5350 initializers_count = 1;
5353 public int VariableInitializersCount {
5355 this.initializers_count = value;
5359 public bool InferType (ResolveContext ec, Expression right_side)
5362 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5364 type = right_side.Type;
5365 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5366 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5367 right_side.GetSignatureForError ());
5371 eclass = ExprClass.Variable;
5375 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5377 if (RootContext.Version < LanguageVersion.V_3)
5378 base.Error_TypeOrNamespaceNotFound (ec);
5380 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5383 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
5385 TypeExpr te = base.ResolveAsContextualType (rc, true);
5389 if (RootContext.Version < LanguageVersion.V_3)
5390 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5392 if (initializers_count == 1)
5395 if (initializers_count > 1) {
5396 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5397 initializers_count = 1;
5401 if (initializers_count == 0) {
5402 initializers_count = 1;
5403 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");