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;
16 using SLE = System.Linq.Expressions;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// The ExprClass class contains the is used to pass the
31 /// classification of an expression (value, variable, namespace,
32 /// type, method group, property access, event access, indexer access,
35 public enum ExprClass : byte {
51 /// This is used to tell Resolve in which types of expressions we're
55 public enum ResolveFlags {
56 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
59 // Returns a type expression.
62 // Returns a method group.
65 TypeParameter = 1 << 3,
67 // Mask of all the expression class flags.
68 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 // An expressions resolved as a direct variable reference
102 public interface IVariableReference : IFixedExpression
104 bool IsHoisted { get; }
106 VariableInfo VariableInfo { get; }
108 void SetHasAddressTaken ();
112 // Implemented by an expression which could be or is always
115 public interface IFixedExpression
117 bool IsFixed { get; }
121 /// Base class for expressions
123 public abstract class Expression {
124 public ExprClass eclass;
125 protected TypeSpec type;
126 protected Location loc;
128 public TypeSpec Type {
130 set { type = value; }
133 public virtual bool IsSideEffectFree {
139 public Location Location {
143 public virtual bool IsNull {
150 // Returns true when the expression during Emit phase breaks stack
151 // by using await expression
153 public virtual bool ContainsEmitWithAwait ()
159 /// Performs semantic analysis on the Expression
163 /// The Resolve method is invoked to perform the semantic analysis
166 /// The return value is an expression (it can be the
167 /// same expression in some cases) or a new
168 /// expression that better represents this node.
170 /// For example, optimizations of Unary (LiteralInt)
171 /// would return a new LiteralInt with a negated
174 /// If there is an error during semantic analysis,
175 /// then an error should be reported (using Report)
176 /// and a null value should be returned.
178 /// There are two side effects expected from calling
179 /// Resolve(): the the field variable "eclass" should
180 /// be set to any value of the enumeration
181 /// `ExprClass' and the type variable should be set
182 /// to a valid type (this is the type of the
185 protected abstract Expression DoResolve (ResolveContext rc);
187 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
193 // This is used if the expression should be resolved as a type or namespace name.
194 // the default implementation fails.
196 public virtual TypeSpec ResolveAsType (IMemberContext mc)
198 ResolveContext ec = new ResolveContext (mc);
199 Expression e = Resolve (ec);
201 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
206 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
208 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
211 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
213 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
216 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
218 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
219 name, TypeManager.CSharpName (type));
222 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
224 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
225 "expressions can be used as a statement");
228 public void Error_InvalidExpressionStatement (BlockContext ec)
230 Error_InvalidExpressionStatement (ec.Report, loc);
233 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
235 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
238 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
240 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
243 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
245 // The error was already reported as CS1660
246 if (type == InternalType.AnonymousMethod)
249 string from_type = type.GetSignatureForError ();
250 string to_type = target.GetSignatureForError ();
251 if (from_type == to_type) {
252 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
253 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
257 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
262 ec.Report.DisableReporting ();
263 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
264 ec.Report.EnableReporting ();
267 ec.Report.Error (266, loc,
268 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
271 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
276 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
278 // Better message for possible generic expressions
279 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
280 var report = context.Module.Compiler.Report;
281 report.SymbolRelatedToPreviousError (member);
282 if (member is TypeSpec)
283 member = ((TypeSpec) member).GetDefinition ();
285 member = ((MethodSpec) member).GetGenericMethodDefinition ();
287 string name = member.Kind == MemberKind.Method ? "method" : "type";
288 if (member.IsGeneric) {
289 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
290 name, member.GetSignatureForError (), member.Arity.ToString ());
292 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
293 name, member.GetSignatureForError ());
296 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
300 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
302 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
306 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
308 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
311 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
313 ec.Report.SymbolRelatedToPreviousError (type);
314 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
315 TypeManager.CSharpName (type), name);
318 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
320 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
323 protected void Error_VoidPointerOperation (ResolveContext rc)
325 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
328 public ResolveFlags ExprClassToResolveFlags {
332 case ExprClass.Namespace:
333 return ResolveFlags.Type;
335 case ExprClass.MethodGroup:
336 return ResolveFlags.MethodGroup;
338 case ExprClass.TypeParameter:
339 return ResolveFlags.TypeParameter;
341 case ExprClass.Value:
342 case ExprClass.Variable:
343 case ExprClass.PropertyAccess:
344 case ExprClass.EventAccess:
345 case ExprClass.IndexerAccess:
346 return ResolveFlags.VariableOrValue;
349 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
354 public virtual string GetSignatureForError ()
356 return type.GetDefinition ().GetSignatureForError ();
360 /// Resolves an expression and performs semantic analysis on it.
364 /// Currently Resolve wraps DoResolve to perform sanity
365 /// checking and assertion checking on what we expect from Resolve.
367 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
369 if (eclass != ExprClass.Unresolved)
379 if ((flags & e.ExprClassToResolveFlags) == 0) {
380 e.Error_UnexpectedKind (ec, flags, loc);
385 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
388 } catch (Exception ex) {
389 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
392 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
393 return EmptyExpression.Null; // TODO: Add location
398 /// Resolves an expression and performs semantic analysis on it.
400 public Expression Resolve (ResolveContext rc)
402 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
406 /// Resolves an expression for LValue assignment
410 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
411 /// checking and assertion checking on what we expect from Resolve
413 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
415 int errors = ec.Report.Errors;
416 bool out_access = right_side == EmptyExpression.OutAccess;
418 Expression e = DoResolveLValue (ec, right_side);
420 if (e != null && out_access && !(e is IMemoryLocation)) {
421 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
422 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
424 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
425 // e.GetType () + " " + e.GetSignatureForError ());
430 if (errors == ec.Report.Errors) {
432 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
434 Error_ValueAssignment (ec, loc);
439 if (e.eclass == ExprClass.Unresolved)
440 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
442 if ((e.type == null) && !(e is GenericTypeExpr))
443 throw new Exception ("Expression " + e + " did not set its type after Resolve");
448 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
450 rc.Module.Compiler.Report.Error (182, loc,
451 "An attribute argument must be a constant expression, typeof expression or array creation expression");
455 /// Emits the code for the expression
459 /// The Emit method is invoked to generate the code
460 /// for the expression.
462 public abstract void Emit (EmitContext ec);
465 // Emit code to branch to @target if this expression is equivalent to @on_true.
466 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
467 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
468 // including the use of conditional branches. Note also that a branch MUST be emitted
469 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
472 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
475 // Emit this expression for its side effects, not for its value.
476 // The default implementation is to emit the value, and then throw it away.
477 // Subclasses can provide more efficient implementations, but those MUST be equivalent
478 public virtual void EmitSideEffect (EmitContext ec)
481 ec.Emit (OpCodes.Pop);
485 // Emits the expression into temporary field variable. The method
486 // should be used for await expressions only
488 public virtual Expression EmitToField (EmitContext ec)
491 // This is the await prepare Emit method. When emitting code like
492 // a + b we emit code like
498 // For await a + await b we have to interfere the flow to keep the
499 // stack clean because await yields from the expression. The emit
502 // a = a.EmitToField () // a is changed to temporary field access
503 // b = b.EmitToField ()
509 // The idea is to emit expression and leave the stack empty with
510 // result value still available.
512 // Expressions should override this default implementation when
513 // optimized version can be provided (e.g. FieldExpr)
516 // We can optimize for side-effect free expressions, they can be
517 // emitted out of order
519 if (IsSideEffectFree)
522 // Emit original code
523 EmitToFieldSource (ec);
525 // Create temporary local (we cannot load this before Emit)
526 var temp = ec.GetTemporaryLocal (type);
527 ec.Emit (OpCodes.Stloc, temp);
530 // Store the result to temporary field
532 var field = ec.GetTemporaryField (type);
534 ec.Emit (OpCodes.Ldloc, temp);
535 field.EmitAssignFromStack (ec);
537 ec.FreeTemporaryLocal (temp, type);
542 protected virtual void EmitToFieldSource (EmitContext ec)
545 // Default implementation calls Emit method
550 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
552 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
553 bool contains_await = false;
555 for (int i = 1; i < expressions.Count; ++i) {
556 if (expressions[i].ContainsEmitWithAwait ()) {
557 contains_await = true;
562 if (contains_await) {
563 for (int i = 0; i < expressions.Count; ++i) {
564 expressions[i] = expressions[i].EmitToField (ec);
569 for (int i = 0; i < expressions.Count; ++i) {
570 expressions[i].Emit (ec);
575 /// Protected constructor. Only derivate types should
576 /// be able to be created
579 protected Expression ()
584 /// Returns a fully formed expression after a MemberLookup
587 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
589 if (spec is EventSpec)
590 return new EventExpr ((EventSpec) spec, loc);
591 if (spec is ConstSpec)
592 return new ConstantExpr ((ConstSpec) spec, loc);
593 if (spec is FieldSpec)
594 return new FieldExpr ((FieldSpec) spec, loc);
595 if (spec is PropertySpec)
596 return new PropertyExpr ((PropertySpec) spec, loc);
597 if (spec is TypeSpec)
598 return new TypeExpression (((TypeSpec) spec), loc);
603 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
605 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
607 rc.Report.SymbolRelatedToPreviousError (type);
609 // Report meaningful error for struct as they always have default ctor in C# context
610 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
612 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
613 type.GetSignatureForError ());
619 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
620 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
624 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
625 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
632 public enum MemberLookupRestrictions
641 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
642 // `qualifier_type' or null to lookup members in the current class.
644 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
646 var members = MemberCache.FindMembers (queried_type, name, false);
650 MemberSpec non_method = null;
651 MemberSpec ambig_non_method = null;
653 for (int i = 0; i < members.Count; ++i) {
654 var member = members[i];
656 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
657 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
660 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
664 if (!member.IsAccessible (rc))
668 // With runtime binder we can have a situation where queried type is inaccessible
669 // because it came via dynamic object, the check about inconsisted accessibility
670 // had no effect as the type was unknown during compilation
673 // private class N { }
675 // public dynamic Foo ()
681 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
685 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
686 if (member is MethodSpec)
687 return new MethodGroupExpr (members, queried_type, loc);
689 if (!Invocation.IsMemberInvocable (member))
693 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
695 } else if (!errorMode && !member.IsNotCSharpCompatible) {
696 ambig_non_method = member;
700 if (non_method != null) {
701 if (ambig_non_method != null && rc != null) {
702 var report = rc.Module.Compiler.Report;
703 report.SymbolRelatedToPreviousError (non_method);
704 report.SymbolRelatedToPreviousError (ambig_non_method);
705 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
706 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
709 if (non_method is MethodSpec)
710 return new MethodGroupExpr (members, queried_type, loc);
712 return ExprClassFromMemberInfo (non_method, loc);
715 if (members[0].DeclaringType.BaseType == null)
718 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
720 } while (members != null);
725 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
727 throw new NotImplementedException ();
730 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
732 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
736 /// Returns an expression that can be used to invoke operator true
737 /// on the expression if it exists.
739 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
741 return GetOperatorTrueOrFalse (ec, e, true, loc);
745 /// Returns an expression that can be used to invoke operator false
746 /// on the expression if it exists.
748 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
750 return GetOperatorTrueOrFalse (ec, e, false, loc);
753 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
755 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
756 var methods = MemberCache.GetUserOperator (e.type, op, false);
760 Arguments arguments = new Arguments (1);
761 arguments.Add (new Argument (e));
763 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
764 var oper = res.ResolveOperator (ec, ref arguments);
769 return new UserOperatorCall (oper, arguments, null, loc);
772 public virtual string ExprClassName
776 case ExprClass.Unresolved:
778 case ExprClass.Value:
780 case ExprClass.Variable:
782 case ExprClass.Namespace:
786 case ExprClass.MethodGroup:
787 return "method group";
788 case ExprClass.PropertyAccess:
789 return "property access";
790 case ExprClass.EventAccess:
791 return "event access";
792 case ExprClass.IndexerAccess:
793 return "indexer access";
794 case ExprClass.Nothing:
796 case ExprClass.TypeParameter:
797 return "type parameter";
799 throw new Exception ("Should not happen");
804 /// Reports that we were expecting `expr' to be of class `expected'
806 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
808 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
811 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
815 name = mc.GetSignatureForError ();
817 name = GetSignatureForError ();
819 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
820 name, was, expected);
823 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
825 string [] valid = new string [4];
828 if ((flags & ResolveFlags.VariableOrValue) != 0) {
829 valid [count++] = "variable";
830 valid [count++] = "value";
833 if ((flags & ResolveFlags.Type) != 0)
834 valid [count++] = "type";
836 if ((flags & ResolveFlags.MethodGroup) != 0)
837 valid [count++] = "method group";
840 valid [count++] = "unknown";
842 StringBuilder sb = new StringBuilder (valid [0]);
843 for (int i = 1; i < count - 1; i++) {
845 sb.Append (valid [i]);
848 sb.Append ("' or `");
849 sb.Append (valid [count - 1]);
852 ec.Report.Error (119, loc,
853 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
856 public static void UnsafeError (ResolveContext ec, Location loc)
858 UnsafeError (ec.Report, loc);
861 public static void UnsafeError (Report Report, Location loc)
863 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
866 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
868 ec.Report.SymbolRelatedToPreviousError (type);
869 if (ec.CurrentInitializerVariable != null) {
870 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
871 TypeManager.CSharpName (type), GetSignatureForError ());
873 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
874 GetSignatureForError ());
879 // Converts `source' to an int, uint, long or ulong.
881 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
883 var btypes = ec.BuiltinTypes;
885 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
886 Arguments args = new Arguments (1);
887 args.Add (new Argument (source));
888 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
891 Expression converted;
893 using (ec.Set (ResolveContext.Options.CheckedScope)) {
894 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
895 if (converted == null)
896 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
897 if (converted == null)
898 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
899 if (converted == null)
900 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
902 if (converted == null) {
903 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
909 // Only positive constants are allowed at compile time
911 Constant c = converted as Constant;
912 if (c != null && c.IsNegative)
913 Error_NegativeArrayIndex (ec, source.loc);
915 // No conversion needed to array index
916 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
919 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
923 // Derived classes implement this method by cloning the fields that
924 // could become altered during the Resolve stage
926 // Only expressions that are created for the parser need to implement
929 protected virtual void CloneTo (CloneContext clonectx, Expression target)
931 throw new NotImplementedException (
933 "CloneTo not implemented for expression {0}", this.GetType ()));
937 // Clones an expression created by the parser.
939 // We only support expressions created by the parser so far, not
940 // expressions that have been resolved (many more classes would need
941 // to implement CloneTo).
943 // This infrastructure is here merely for Lambda expressions which
944 // compile the same code using different type values for the same
945 // arguments to find the correct overload
947 public virtual Expression Clone (CloneContext clonectx)
949 Expression cloned = (Expression) MemberwiseClone ();
950 CloneTo (clonectx, cloned);
956 // Implementation of expression to expression tree conversion
958 public abstract Expression CreateExpressionTree (ResolveContext ec);
960 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
962 return CreateExpressionFactoryCall (ec, name, null, args, loc);
965 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
967 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
970 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
972 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
975 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
977 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
981 return new TypeExpression (t, loc);
985 // Implemented by all expressions which support conversion from
986 // compiler expression to invokable runtime expression. Used by
987 // dynamic C# binder.
989 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
991 throw new NotImplementedException ("MakeExpression for " + GetType ());
996 /// This is just a base class for expressions that can
997 /// appear on statements (invocations, object creation,
998 /// assignments, post/pre increment and decrement). The idea
999 /// being that they would support an extra Emition interface that
1000 /// does not leave a result on the stack.
1002 public abstract class ExpressionStatement : Expression {
1004 public ExpressionStatement ResolveStatement (BlockContext ec)
1006 Expression e = Resolve (ec);
1010 ExpressionStatement es = e as ExpressionStatement;
1012 Error_InvalidExpressionStatement (ec);
1018 /// Requests the expression to be emitted in a `statement'
1019 /// context. This means that no new value is left on the
1020 /// stack after invoking this method (constrasted with
1021 /// Emit that will always leave a value on the stack).
1023 public abstract void EmitStatement (EmitContext ec);
1025 public override void EmitSideEffect (EmitContext ec)
1032 /// This kind of cast is used to encapsulate the child
1033 /// whose type is child.Type into an expression that is
1034 /// reported to return "return_type". This is used to encapsulate
1035 /// expressions which have compatible types, but need to be dealt
1036 /// at higher levels with.
1038 /// For example, a "byte" expression could be encapsulated in one
1039 /// of these as an "unsigned int". The type for the expression
1040 /// would be "unsigned int".
1043 public abstract class TypeCast : Expression
1045 protected readonly Expression child;
1047 protected TypeCast (Expression child, TypeSpec return_type)
1049 eclass = child.eclass;
1050 loc = child.Location;
1055 public Expression Child {
1061 public override bool ContainsEmitWithAwait ()
1063 return child.ContainsEmitWithAwait ();
1066 public override Expression CreateExpressionTree (ResolveContext ec)
1068 Arguments args = new Arguments (2);
1069 args.Add (new Argument (child.CreateExpressionTree (ec)));
1070 args.Add (new Argument (new TypeOf (type, loc)));
1072 if (type.IsPointer || child.Type.IsPointer)
1073 Error_PointerInsideExpressionTree (ec);
1075 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1078 protected override Expression DoResolve (ResolveContext ec)
1080 // This should never be invoked, we are born in fully
1081 // initialized state.
1086 public override void Emit (EmitContext ec)
1091 public override SLE.Expression MakeExpression (BuilderContext ctx)
1094 return base.MakeExpression (ctx);
1096 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1097 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1098 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1102 protected override void CloneTo (CloneContext clonectx, Expression t)
1107 public override bool IsNull {
1108 get { return child.IsNull; }
1112 public class EmptyCast : TypeCast {
1113 EmptyCast (Expression child, TypeSpec target_type)
1114 : base (child, target_type)
1118 public static Expression Create (Expression child, TypeSpec type)
1120 Constant c = child as Constant;
1122 return new EmptyConstantCast (c, type);
1124 EmptyCast e = child as EmptyCast;
1126 return new EmptyCast (e.child, type);
1128 return new EmptyCast (child, type);
1131 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1133 child.EmitBranchable (ec, label, on_true);
1136 public override void EmitSideEffect (EmitContext ec)
1138 child.EmitSideEffect (ec);
1143 // Used for predefined type user operator (no obsolete check, etc.)
1145 public class OperatorCast : TypeCast
1147 readonly MethodSpec conversion_operator;
1149 public OperatorCast (Expression expr, TypeSpec target_type)
1150 : this (expr, target_type, target_type, false)
1154 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1155 : this (expr, target_type, target_type, find_explicit)
1159 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1160 : base (expr, returnType)
1162 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1163 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1166 foreach (MethodSpec oper in mi) {
1167 if (oper.ReturnType != returnType)
1170 if (oper.Parameters.Types[0] == expr.Type) {
1171 conversion_operator = oper;
1177 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1178 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1181 public override void Emit (EmitContext ec)
1184 ec.Emit (OpCodes.Call, conversion_operator);
1189 // Constant specialization of EmptyCast.
1190 // We need to special case this since an empty cast of
1191 // a constant is still a constant.
1193 public class EmptyConstantCast : Constant
1195 public readonly Constant child;
1197 public EmptyConstantCast (Constant child, TypeSpec type)
1198 : base (child.Location)
1201 throw new ArgumentNullException ("child");
1204 this.eclass = child.eclass;
1208 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1210 if (child.Type == target_type)
1213 // FIXME: check that 'type' can be converted to 'target_type' first
1214 return child.ConvertExplicitly (in_checked_context, target_type);
1217 public override Expression CreateExpressionTree (ResolveContext ec)
1219 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1220 child.CreateExpressionTree (ec),
1221 new TypeOf (type, loc));
1224 Error_PointerInsideExpressionTree (ec);
1226 return CreateExpressionFactoryCall (ec, "Convert", args);
1229 public override bool IsDefaultValue {
1230 get { return child.IsDefaultValue; }
1233 public override bool IsNegative {
1234 get { return child.IsNegative; }
1237 public override bool IsNull {
1238 get { return child.IsNull; }
1241 public override bool IsOneInteger {
1242 get { return child.IsOneInteger; }
1245 public override bool IsSideEffectFree {
1247 return child.IsSideEffectFree;
1251 public override bool IsZeroInteger {
1252 get { return child.IsZeroInteger; }
1255 public override void Emit (EmitContext ec)
1260 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1262 child.EmitBranchable (ec, label, on_true);
1264 // Only to make verifier happy
1265 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1266 ec.Emit (OpCodes.Unbox_Any, type);
1269 public override void EmitSideEffect (EmitContext ec)
1271 child.EmitSideEffect (ec);
1274 public override object GetValue ()
1276 return child.GetValue ();
1279 public override string GetValueAsLiteral ()
1281 return child.GetValueAsLiteral ();
1284 public override long GetValueAsLong ()
1286 return child.GetValueAsLong ();
1289 public override Constant ConvertImplicitly (TypeSpec target_type)
1291 if (type == target_type)
1294 // FIXME: Do we need to check user conversions?
1295 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1298 return child.ConvertImplicitly (target_type);
1303 /// This class is used to wrap literals which belong inside Enums
1305 public class EnumConstant : Constant
1307 public Constant Child;
1309 public EnumConstant (Constant child, TypeSpec enum_type)
1310 : base (child.Location)
1314 this.eclass = ExprClass.Value;
1315 this.type = enum_type;
1318 protected EnumConstant (Location loc)
1323 public override void Emit (EmitContext ec)
1328 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1330 Child.EncodeAttributeValue (rc, enc, Child.Type);
1333 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1335 Child.EmitBranchable (ec, label, on_true);
1338 public override void EmitSideEffect (EmitContext ec)
1340 Child.EmitSideEffect (ec);
1343 public override string GetSignatureForError()
1345 return TypeManager.CSharpName (Type);
1348 public override object GetValue ()
1350 return Child.GetValue ();
1354 public override object GetTypedValue ()
1357 // The method can be used in dynamic context only (on closed types)
1359 // System.Enum.ToObject cannot be called on dynamic types
1360 // EnumBuilder has to be used, but we cannot use EnumBuilder
1361 // because it does not properly support generics
1363 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1367 public override string GetValueAsLiteral ()
1369 return Child.GetValueAsLiteral ();
1372 public override long GetValueAsLong ()
1374 return Child.GetValueAsLong ();
1377 public EnumConstant Increment()
1379 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1382 public override bool IsDefaultValue {
1384 return Child.IsDefaultValue;
1388 public override bool IsSideEffectFree {
1390 return Child.IsSideEffectFree;
1394 public override bool IsZeroInteger {
1395 get { return Child.IsZeroInteger; }
1398 public override bool IsNegative {
1400 return Child.IsNegative;
1404 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1406 if (Child.Type == target_type)
1409 return Child.ConvertExplicitly (in_checked_context, target_type);
1412 public override Constant ConvertImplicitly (TypeSpec type)
1414 if (this.type == type) {
1418 if (!Convert.ImplicitStandardConversionExists (this, type)){
1422 return Child.ConvertImplicitly (type);
1427 /// This kind of cast is used to encapsulate Value Types in objects.
1429 /// The effect of it is to box the value type emitted by the previous
1432 public class BoxedCast : TypeCast {
1434 public BoxedCast (Expression expr, TypeSpec target_type)
1435 : base (expr, target_type)
1437 eclass = ExprClass.Value;
1440 protected override Expression DoResolve (ResolveContext ec)
1442 // This should never be invoked, we are born in fully
1443 // initialized state.
1448 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1450 // Only boxing to object type is supported
1451 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1452 base.EncodeAttributeValue (rc, enc, targetType);
1456 enc.Encode (child.Type);
1457 child.EncodeAttributeValue (rc, enc, child.Type);
1460 public override void Emit (EmitContext ec)
1464 ec.Emit (OpCodes.Box, child.Type);
1467 public override void EmitSideEffect (EmitContext ec)
1469 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1470 // so, we need to emit the box+pop instructions in most cases
1471 if (child.Type.IsStruct &&
1472 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1473 child.EmitSideEffect (ec);
1475 base.EmitSideEffect (ec);
1479 public class UnboxCast : TypeCast {
1480 public UnboxCast (Expression expr, TypeSpec return_type)
1481 : base (expr, return_type)
1485 protected override Expression DoResolve (ResolveContext ec)
1487 // This should never be invoked, we are born in fully
1488 // initialized state.
1493 public override void Emit (EmitContext ec)
1497 ec.Emit (OpCodes.Unbox_Any, type);
1502 /// This is used to perform explicit numeric conversions.
1504 /// Explicit numeric conversions might trigger exceptions in a checked
1505 /// context, so they should generate the conv.ovf opcodes instead of
1508 public class ConvCast : TypeCast {
1509 public enum Mode : byte {
1510 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1512 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1513 U2_I1, U2_U1, U2_I2, U2_CH,
1514 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1515 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1516 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1517 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1518 CH_I1, CH_U1, CH_I2,
1519 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1520 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1526 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1527 : base (child, return_type)
1532 protected override Expression DoResolve (ResolveContext ec)
1534 // This should never be invoked, we are born in fully
1535 // initialized state.
1540 public override string ToString ()
1542 return String.Format ("ConvCast ({0}, {1})", mode, child);
1545 public override void Emit (EmitContext ec)
1549 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1551 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1552 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1553 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1554 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1555 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1557 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1558 case Mode.U1_CH: /* nothing */ break;
1560 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1561 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1562 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1563 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1564 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1565 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1567 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1568 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1569 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1570 case Mode.U2_CH: /* nothing */ break;
1572 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1573 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1574 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1575 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1576 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1577 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1578 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1580 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1581 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1582 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1583 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1584 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1585 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1587 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1588 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1589 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1590 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1592 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1593 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1594 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1595 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1597 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1598 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1599 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1600 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1601 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1602 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1603 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1604 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1605 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1607 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1608 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1609 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1611 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1612 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1613 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1614 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1615 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1616 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1617 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1618 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1619 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1622 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1623 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1624 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1626 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1627 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1628 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1629 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1632 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1636 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1637 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1638 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1639 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1640 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1642 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1643 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1645 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1646 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1647 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1649 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1650 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1652 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1653 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1654 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1655 case Mode.U2_CH: /* nothing */ break;
1657 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1659 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1660 case Mode.I4_U4: /* nothing */ break;
1661 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1662 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1663 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1665 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1666 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1667 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1668 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.U4_I4: /* nothing */ break;
1670 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1673 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1674 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1675 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1677 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1678 case Mode.I8_U8: /* nothing */ break;
1679 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1682 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1683 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1684 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1685 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1687 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1688 case Mode.U8_I8: /* nothing */ break;
1689 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1692 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1693 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1694 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1697 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1698 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1699 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1700 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1701 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1702 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1703 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1704 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1707 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1708 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1709 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1710 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1711 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1712 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1713 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1714 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1717 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1723 class OpcodeCast : TypeCast
1727 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1728 : base (child, return_type)
1733 protected override Expression DoResolve (ResolveContext ec)
1735 // This should never be invoked, we are born in fully
1736 // initialized state.
1741 public override void Emit (EmitContext ec)
1747 public TypeSpec UnderlyingType {
1748 get { return child.Type; }
1753 // Opcode casts expression with 2 opcodes but only
1754 // single expression tree node
1756 class OpcodeCastDuplex : OpcodeCast
1758 readonly OpCode second;
1760 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1761 : base (child, returnType, first)
1763 this.second = second;
1766 public override void Emit (EmitContext ec)
1774 /// This kind of cast is used to encapsulate a child and cast it
1775 /// to the class requested
1777 public sealed class ClassCast : TypeCast {
1778 readonly bool forced;
1780 public ClassCast (Expression child, TypeSpec return_type)
1781 : base (child, return_type)
1785 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1786 : base (child, return_type)
1788 this.forced = forced;
1791 public override void Emit (EmitContext ec)
1795 bool gen = TypeManager.IsGenericParameter (child.Type);
1797 ec.Emit (OpCodes.Box, child.Type);
1799 if (type.IsGenericParameter) {
1800 ec.Emit (OpCodes.Unbox_Any, type);
1807 ec.Emit (OpCodes.Castclass, type);
1812 // Created during resolving pahse when an expression is wrapped or constantified
1813 // and original expression can be used later (e.g. for expression trees)
1815 public class ReducedExpression : Expression
1817 sealed class ReducedConstantExpression : EmptyConstantCast
1819 readonly Expression orig_expr;
1821 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1822 : base (expr, expr.Type)
1824 this.orig_expr = orig_expr;
1827 public override Constant ConvertImplicitly (TypeSpec target_type)
1829 Constant c = base.ConvertImplicitly (target_type);
1831 c = new ReducedConstantExpression (c, orig_expr);
1836 public override Expression CreateExpressionTree (ResolveContext ec)
1838 return orig_expr.CreateExpressionTree (ec);
1841 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1843 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1845 c = new ReducedConstantExpression (c, orig_expr);
1850 sealed class ReducedExpressionStatement : ExpressionStatement
1852 readonly Expression orig_expr;
1853 readonly ExpressionStatement stm;
1855 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1857 this.orig_expr = orig;
1859 this.eclass = stm.eclass;
1860 this.type = stm.Type;
1862 this.loc = orig.Location;
1865 public override bool ContainsEmitWithAwait ()
1867 return stm.ContainsEmitWithAwait ();
1870 public override Expression CreateExpressionTree (ResolveContext ec)
1872 return orig_expr.CreateExpressionTree (ec);
1875 protected override Expression DoResolve (ResolveContext ec)
1880 public override void Emit (EmitContext ec)
1885 public override void EmitStatement (EmitContext ec)
1887 stm.EmitStatement (ec);
1891 readonly Expression expr, orig_expr;
1893 private ReducedExpression (Expression expr, Expression orig_expr)
1896 this.eclass = expr.eclass;
1897 this.type = expr.Type;
1898 this.orig_expr = orig_expr;
1899 this.loc = orig_expr.Location;
1904 public Expression OriginalExpression {
1912 public override bool ContainsEmitWithAwait ()
1914 return expr.ContainsEmitWithAwait ();
1918 // Creates fully resolved expression switcher
1920 public static Constant Create (Constant expr, Expression original_expr)
1922 if (expr.eclass == ExprClass.Unresolved)
1923 throw new ArgumentException ("Unresolved expression");
1925 return new ReducedConstantExpression (expr, original_expr);
1928 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1930 return new ReducedExpressionStatement (s, orig);
1933 public static Expression Create (Expression expr, Expression original_expr)
1935 return Create (expr, original_expr, true);
1939 // Creates unresolved reduce expression. The original expression has to be
1940 // already resolved. Created expression is constant based based on `expr'
1941 // value unless canBeConstant is used
1943 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1945 if (canBeConstant) {
1946 Constant c = expr as Constant;
1948 return Create (c, original_expr);
1951 ExpressionStatement s = expr as ExpressionStatement;
1953 return Create (s, original_expr);
1955 if (expr.eclass == ExprClass.Unresolved)
1956 throw new ArgumentException ("Unresolved expression");
1958 return new ReducedExpression (expr, original_expr);
1961 public override Expression CreateExpressionTree (ResolveContext ec)
1963 return orig_expr.CreateExpressionTree (ec);
1966 protected override Expression DoResolve (ResolveContext ec)
1971 public override void Emit (EmitContext ec)
1976 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1978 expr.EmitBranchable (ec, target, on_true);
1981 public override SLE.Expression MakeExpression (BuilderContext ctx)
1983 return orig_expr.MakeExpression (ctx);
1988 // Standard composite pattern
1990 public abstract class CompositeExpression : Expression
1992 protected Expression expr;
1994 protected CompositeExpression (Expression expr)
1997 this.loc = expr.Location;
2000 public override bool ContainsEmitWithAwait ()
2002 return expr.ContainsEmitWithAwait ();
2005 public override Expression CreateExpressionTree (ResolveContext rc)
2007 return expr.CreateExpressionTree (rc);
2010 public Expression Child {
2011 get { return expr; }
2014 protected override Expression DoResolve (ResolveContext rc)
2016 expr = expr.Resolve (rc);
2019 eclass = expr.eclass;
2025 public override void Emit (EmitContext ec)
2030 public override bool IsNull {
2031 get { return expr.IsNull; }
2036 // Base of expressions used only to narrow resolve flow
2038 public abstract class ShimExpression : Expression
2040 protected Expression expr;
2042 protected ShimExpression (Expression expr)
2047 public Expression Expr {
2053 protected override void CloneTo (CloneContext clonectx, Expression t)
2058 ShimExpression target = (ShimExpression) t;
2059 target.expr = expr.Clone (clonectx);
2062 public override bool ContainsEmitWithAwait ()
2064 return expr.ContainsEmitWithAwait ();
2067 public override Expression CreateExpressionTree (ResolveContext ec)
2069 throw new NotSupportedException ("ET");
2072 public override void Emit (EmitContext ec)
2074 throw new InternalErrorException ("Missing Resolve call");
2080 // Unresolved type name expressions
2082 public abstract class ATypeNameExpression : FullNamedExpression
2085 protected TypeArguments targs;
2087 protected ATypeNameExpression (string name, Location l)
2093 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2100 protected ATypeNameExpression (string name, int arity, Location l)
2101 : this (name, new UnboundTypeArguments (arity), l)
2107 protected int Arity {
2109 return targs == null ? 0 : targs.Count;
2113 public bool HasTypeArguments {
2115 return targs != null && !targs.IsEmpty;
2119 public string Name {
2128 public TypeArguments TypeArguments {
2136 public override bool Equals (object obj)
2138 ATypeNameExpression atne = obj as ATypeNameExpression;
2139 return atne != null && atne.Name == Name &&
2140 (targs == null || targs.Equals (atne.targs));
2143 public override int GetHashCode ()
2145 return Name.GetHashCode ();
2148 // TODO: Move it to MemberCore
2149 public static string GetMemberType (MemberCore mc)
2155 if (mc is FieldBase)
2157 if (mc is MethodCore)
2159 if (mc is EnumMember)
2167 public override string GetSignatureForError ()
2169 if (targs != null) {
2170 return Name + "<" + targs.GetSignatureForError () + ">";
2176 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2180 /// SimpleName expressions are formed of a single word and only happen at the beginning
2181 /// of a dotted-name.
2183 public class SimpleName : ATypeNameExpression
2185 public SimpleName (string name, Location l)
2190 public SimpleName (string name, TypeArguments args, Location l)
2191 : base (name, args, l)
2195 public SimpleName (string name, int arity, Location l)
2196 : base (name, arity, l)
2200 public SimpleName GetMethodGroup ()
2202 return new SimpleName (Name, targs, loc);
2205 protected override Expression DoResolve (ResolveContext ec)
2207 return SimpleNameResolve (ec, null, false);
2210 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2212 return SimpleNameResolve (ec, right_side, false);
2215 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2217 if (ctx.CurrentType != null) {
2218 if (ctx.CurrentMemberDefinition != null) {
2219 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2221 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2227 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2228 if (retval != null) {
2229 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2230 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2234 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2235 if (retval != null) {
2236 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2240 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2243 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2245 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2248 if (fne.Type != null && Arity > 0) {
2249 if (HasTypeArguments) {
2250 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2251 if (ct.ResolveAsType (ec) == null)
2257 return new GenericOpenTypeExpr (fne.Type, loc);
2261 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2263 if (!(fne is Namespace))
2267 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2268 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2269 ec.Module.Compiler.Report.Error (1980, Location,
2270 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2271 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2274 fne = new DynamicTypeExpr (loc);
2275 fne.ResolveAsType (ec);
2281 Error_TypeOrNamespaceNotFound (ec);
2285 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2287 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2290 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2292 int lookup_arity = Arity;
2293 bool errorMode = false;
2295 Block current_block = rc.CurrentBlock;
2296 INamedBlockVariable variable = null;
2297 bool variable_found = false;
2301 // Stage 1: binding to local variables or parameters
2303 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2305 if (current_block != null && lookup_arity == 0) {
2306 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2307 if (!variable.IsDeclared) {
2308 // We found local name in accessible block but it's not
2309 // initialized yet, maybe the user wanted to bind to something else
2311 variable_found = true;
2313 e = variable.CreateReferenceExpression (rc, loc);
2316 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2325 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2327 TypeSpec member_type = rc.CurrentType;
2328 for (; member_type != null; member_type = member_type.DeclaringType) {
2329 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2333 var me = e as MemberExpr;
2335 // The name matches a type, defer to ResolveAsTypeStep
2343 if (variable != null) {
2344 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2345 rc.Report.Error (844, loc,
2346 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2347 Name, me.GetSignatureForError ());
2351 } else if (me is MethodGroupExpr) {
2352 // Leave it to overload resolution to report correct error
2354 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2355 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2358 // LAMESPEC: again, ignores InvocableOnly
2359 if (variable != null) {
2360 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2361 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2365 // MemberLookup does not check accessors availability, this is actually needed for properties only
2367 var pe = me as PropertyExpr;
2370 // Break as there is no other overload available anyway
2371 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2372 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2375 pe.Getter = pe.PropertyInfo.Get;
2377 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2380 pe.Setter = pe.PropertyInfo.Set;
2385 // TODO: It's used by EventExpr -> FieldExpr transformation only
2386 // TODO: Should go to MemberAccess
2387 me = me.ResolveMemberAccess (rc, null, null);
2391 me.SetTypeArguments (rc, targs);
2398 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2400 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2401 if (IsPossibleTypeOrNamespace (rc)) {
2402 if (variable != null) {
2403 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2404 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2407 return ResolveAsTypeOrNamespace (rc);
2412 if (variable_found) {
2413 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2416 TypeParameter[] tparams = rc.CurrentTypeParameters;
2417 if (tparams != null) {
2418 foreach (var ctp in tparams) {
2419 if (ctp.Name == Name) {
2420 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2426 var ct = rc.CurrentType;
2428 if (ct.MemberDefinition.TypeParametersCount > 0) {
2429 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2430 if (ctp.Name == Name) {
2431 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2437 ct = ct.DeclaringType;
2438 } while (ct != null);
2441 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2442 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2444 rc.Report.SymbolRelatedToPreviousError (e.Type);
2445 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2450 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2452 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2453 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2458 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2461 return ErrorExpression.Instance;
2464 if (rc.Module.Evaluator != null) {
2465 var fi = rc.Module.Evaluator.LookupField (Name);
2467 return new FieldExpr (fi.Item1, loc);
2475 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2477 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2482 if (right_side != null) {
2483 if (e is TypeExpr) {
2484 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2488 e = e.ResolveLValue (ec, right_side);
2493 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2499 /// Represents a namespace or a type. The name of the class was inspired by
2500 /// section 10.8.1 (Fully Qualified Names).
2502 public abstract class FullNamedExpression : Expression
2504 protected override void CloneTo (CloneContext clonectx, Expression target)
2506 // Do nothing, most unresolved type expressions cannot be
2507 // resolved to different type
2510 public override bool ContainsEmitWithAwait ()
2515 public override Expression CreateExpressionTree (ResolveContext ec)
2517 throw new NotSupportedException ("ET");
2520 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2523 // This is used to resolve the expression as a type, a null
2524 // value will be returned if the expression is not a type
2527 public override TypeSpec ResolveAsType (IMemberContext mc)
2529 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2534 TypeExpr te = fne as TypeExpr;
2536 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2544 var dep = type.GetMissingDependencies ();
2546 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2550 // Obsolete checks cannot be done when resolving base context as they
2551 // require type dependencies to be set but we are in process of resolving them
2553 if (!(mc is TypeContainer.BaseContext)) {
2554 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2555 if (obsolete_attr != null && !mc.IsObsolete) {
2556 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2564 public override void Emit (EmitContext ec)
2566 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2567 GetSignatureForError ());
2572 /// Expression that evaluates to a type
2574 public abstract class TypeExpr : FullNamedExpression
2576 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2582 protected sealed override Expression DoResolve (ResolveContext ec)
2588 public override bool Equals (object obj)
2590 TypeExpr tobj = obj as TypeExpr;
2594 return Type == tobj.Type;
2597 public override int GetHashCode ()
2599 return Type.GetHashCode ();
2604 /// Fully resolved Expression that already evaluated to a type
2606 public class TypeExpression : TypeExpr
2608 public TypeExpression (TypeSpec t, Location l)
2611 eclass = ExprClass.Type;
2615 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2622 /// This class denotes an expression which evaluates to a member
2623 /// of a struct or a class.
2625 public abstract class MemberExpr : Expression
2628 // An instance expression associated with this member, if it's a
2629 // non-static member
2631 public Expression InstanceExpression;
2634 /// The name of this member.
2636 public abstract string Name {
2641 // When base.member is used
2643 public bool IsBase {
2644 get { return InstanceExpression is BaseThis; }
2648 /// Whether this is an instance member.
2650 public abstract bool IsInstance {
2655 /// Whether this is a static member.
2657 public abstract bool IsStatic {
2661 protected abstract TypeSpec DeclaringType {
2666 // Converts best base candidate for virtual method starting from QueriedBaseType
2668 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2671 // Only when base.member is used and method is virtual
2677 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2678 // means for base.member access we have to find the closest match after we found best candidate
2680 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2682 // The method could already be what we are looking for
2684 TypeSpec[] targs = null;
2685 if (method.DeclaringType != InstanceExpression.Type) {
2686 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2687 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2688 if (base_override.IsGeneric)
2689 targs = method.TypeArguments;
2691 method = base_override;
2695 // TODO: For now we do it for any hoisted call even if it's needed for
2696 // hoisted stories only but that requires a new expression wrapper
2697 if (rc.CurrentAnonymousMethod != null) {
2698 if (targs == null && method.IsGeneric) {
2699 targs = method.TypeArguments;
2700 method = method.GetGenericMethodDefinition ();
2703 if (method.Parameters.HasArglist)
2704 throw new NotImplementedException ("__arglist base call proxy");
2706 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2708 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2709 // get/set member expressions second call would fail to proxy because left expression
2710 // would be of 'this' and not 'base'
2711 if (rc.CurrentType.IsStruct)
2712 InstanceExpression = new This (loc).Resolve (rc);
2716 method = method.MakeGenericMethod (rc, targs);
2720 // Only base will allow this invocation to happen.
2722 if (method.IsAbstract) {
2723 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2729 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2731 if (InstanceExpression == null)
2734 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2735 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2739 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2741 var ct = rc.CurrentType;
2742 if (ct == qualifier)
2745 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2748 qualifier = qualifier.GetDefinition ();
2749 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2750 rc.Report.SymbolRelatedToPreviousError (member);
2751 rc.Report.Error (1540, loc,
2752 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2753 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2757 public override bool ContainsEmitWithAwait ()
2759 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2762 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2765 type = type.GetDefinition ();
2767 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2770 type = type.DeclaringType;
2771 } while (type != null);
2776 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2778 if (InstanceExpression != null) {
2779 InstanceExpression = InstanceExpression.Resolve (rc);
2780 CheckProtectedMemberAccess (rc, member);
2783 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2784 UnsafeError (rc, loc);
2787 var dep = member.GetMissingDependencies ();
2789 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2792 if (!rc.IsObsolete) {
2793 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2795 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2798 if (!(member is FieldSpec))
2799 member.MemberDefinition.SetIsUsed ();
2802 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2804 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2808 // Implements identicial simple name and type-name
2810 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2813 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2816 // 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
2817 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2819 if (left is MemberExpr || left is VariableReference) {
2820 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2821 if (identical_type != null && identical_type.Type == left.Type)
2822 return identical_type;
2828 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2831 if (InstanceExpression != null) {
2832 if (InstanceExpression is TypeExpr) {
2833 var t = InstanceExpression.Type;
2835 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2836 if (oa != null && !rc.IsObsolete) {
2837 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2840 t = t.DeclaringType;
2841 } while (t != null);
2843 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2844 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2845 rc.Report.Error (176, loc,
2846 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2847 GetSignatureForError ());
2851 InstanceExpression = null;
2857 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2858 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2859 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2860 rc.Report.Error (236, loc,
2861 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2862 GetSignatureForError ());
2864 rc.Report.Error (120, loc,
2865 "An object reference is required to access non-static member `{0}'",
2866 GetSignatureForError ());
2871 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2872 rc.Report.Error (38, loc,
2873 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2874 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2877 InstanceExpression = new This (loc);
2878 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2879 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2880 InstanceExpression = InstanceExpression.Resolve (rc);
2883 InstanceExpression = InstanceExpression.Resolve (rc);
2889 var me = InstanceExpression as MemberExpr;
2891 me.ResolveInstanceExpression (rc, rhs);
2893 var fe = me as FieldExpr;
2894 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2895 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2896 rc.Report.Warning (1690, 1, loc,
2897 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2898 me.GetSignatureForError ());
2905 // Run member-access postponed check once we know that
2906 // the expression is not field expression which is the only
2907 // expression which can use uninitialized this
2909 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2910 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2914 // Additional checks for l-value member access
2918 // TODO: It should be recursive but that would break csc compatibility
2920 if (InstanceExpression is UnboxCast) {
2921 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2928 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2930 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2931 ec.Report.Warning (1720, 1, left.Location,
2932 "Expression will always cause a `{0}'", "System.NullReferenceException");
2935 InstanceExpression = left;
2939 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2941 TypeSpec instance_type = InstanceExpression.Type;
2942 if (TypeSpec.IsValueType (instance_type)) {
2943 if (InstanceExpression is IMemoryLocation) {
2944 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2946 LocalTemporary t = new LocalTemporary (instance_type);
2947 InstanceExpression.Emit (ec);
2949 t.AddressOf (ec, AddressOp.Store);
2952 InstanceExpression.Emit (ec);
2954 // Only to make verifier happy
2955 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2956 ec.Emit (OpCodes.Box, instance_type);
2959 if (prepare_for_load)
2960 ec.Emit (OpCodes.Dup);
2963 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2966 public class ExtensionMethodCandidates
2968 NamespaceContainer container;
2970 IList<MethodSpec> methods;
2972 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
2973 : this (methods, nsContainer, null)
2977 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
2979 this.methods = methods;
2980 this.container = nsContainer;
2984 public NamespaceContainer Container {
2990 public bool HasUninspectedMembers { get; set; }
2992 public Namespace Namespace {
2998 public IList<MethodSpec> Methods {
3006 // Represents a group of extension method candidates for whole namespace
3008 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3010 ExtensionMethodCandidates candidates;
3011 public readonly Expression ExtensionExpression;
3013 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3014 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3016 this.candidates = candidates;
3017 this.ExtensionExpression = extensionExpr;
3020 public override bool IsStatic {
3021 get { return true; }
3025 // For extension methodgroup we are not looking for base members but parent
3026 // namespace extension methods
3028 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3030 // TODO: candidates are null only when doing error reporting, that's
3031 // incorrect. We have to discover same extension methods in error mode
3032 if (candidates == null)
3035 int arity = type_arguments == null ? 0 : type_arguments.Count;
3038 // Here we try to resume the search for extension method at the point
3039 // where the last bunch of candidates was found. It's more tricky than
3040 // it seems as we have to check both namespace containers and namespace
3041 // in correct order.
3047 // namespace B.C.D {
3048 // <our first search found candidates in A.B.C.D
3052 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3053 // checked before we hit A.N1 using
3055 if (candidates.Namespace == null) {
3057 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3058 if (methods != null) {
3059 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3060 return methods.Cast<MemberSpec> ().ToList ();
3064 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3065 if (ns_container == null)
3068 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3069 if (candidates == null)
3072 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3075 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3077 // We are already here
3081 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3083 if (arguments == null)
3084 arguments = new Arguments (1);
3086 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3087 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3089 // Store resolved argument and restore original arguments
3091 // Clean-up modified arguments for error reporting
3092 arguments.RemoveAt (0);
3096 var me = ExtensionExpression as MemberExpr;
3098 me.ResolveInstanceExpression (ec, null);
3100 InstanceExpression = null;
3104 #region IErrorHandler Members
3106 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3111 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3113 rc.Report.SymbolRelatedToPreviousError (best);
3114 rc.Report.Error (1928, loc,
3115 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3116 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3119 rc.Report.Error (1929, loc,
3120 "Extension method instance type `{0}' cannot be converted to `{1}'",
3121 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3127 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3132 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3141 /// MethodGroupExpr represents a group of method candidates which
3142 /// can be resolved to the best method overload
3144 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3146 protected IList<MemberSpec> Methods;
3147 MethodSpec best_candidate;
3148 TypeSpec best_candidate_return;
3149 protected TypeArguments type_arguments;
3151 SimpleName simple_name;
3152 protected TypeSpec queried_type;
3154 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3158 this.type = InternalType.MethodGroup;
3160 eclass = ExprClass.MethodGroup;
3161 queried_type = type;
3164 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3165 : this (new MemberSpec[] { m }, type, loc)
3171 public MethodSpec BestCandidate {
3173 return best_candidate;
3177 public TypeSpec BestCandidateReturnType {
3179 return best_candidate_return;
3183 public IList<MemberSpec> Candidates {
3189 protected override TypeSpec DeclaringType {
3191 return queried_type;
3195 public override bool IsInstance {
3197 if (best_candidate != null)
3198 return !best_candidate.IsStatic;
3204 public override bool IsStatic {
3206 if (best_candidate != null)
3207 return best_candidate.IsStatic;
3213 public override string Name {
3215 if (best_candidate != null)
3216 return best_candidate.Name;
3219 return Methods.First ().Name;
3226 // When best candidate is already know this factory can be used
3227 // to avoid expensive overload resolution to be called
3229 // NOTE: InstanceExpression has to be set manually
3231 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3233 return new MethodGroupExpr (best, queriedType, loc) {
3234 best_candidate = best,
3235 best_candidate_return = best.ReturnType
3239 public override string GetSignatureForError ()
3241 if (best_candidate != null)
3242 return best_candidate.GetSignatureForError ();
3244 return Methods.First ().GetSignatureForError ();
3247 public override Expression CreateExpressionTree (ResolveContext ec)
3249 if (best_candidate == null) {
3250 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3254 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3255 ec.Report.Error (765, loc,
3256 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3258 return new TypeOfMethod (best_candidate, loc);
3261 protected override Expression DoResolve (ResolveContext ec)
3263 this.eclass = ExprClass.MethodGroup;
3265 if (InstanceExpression != null) {
3266 InstanceExpression = InstanceExpression.Resolve (ec);
3267 if (InstanceExpression == null)
3274 public override void Emit (EmitContext ec)
3276 throw new NotSupportedException ();
3279 public void EmitCall (EmitContext ec, Arguments arguments)
3281 var call = new CallEmitter ();
3282 call.InstanceExpression = InstanceExpression;
3283 call.Emit (ec, best_candidate, arguments, loc);
3286 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3288 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3289 Name, TypeManager.CSharpName (target));
3292 public static bool IsExtensionMethodArgument (Expression expr)
3295 // LAMESPEC: No details about which expressions are not allowed
3297 return !(expr is TypeExpr) && !(expr is BaseThis);
3301 /// Find the Applicable Function Members (7.4.2.1)
3303 /// me: Method Group expression with the members to select.
3304 /// it might contain constructors or methods (or anything
3305 /// that maps to a method).
3307 /// Arguments: ArrayList containing resolved Argument objects.
3309 /// loc: The location if we want an error to be reported, or a Null
3310 /// location for "probing" purposes.
3312 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3313 /// that is the best match of me on Arguments.
3316 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3318 // TODO: causes issues with probing mode, remove explicit Kind check
3319 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3322 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3323 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3324 r.BaseMembersProvider = this;
3327 if (cerrors != null)
3328 r.CustomErrors = cerrors;
3330 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3331 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3332 if (best_candidate == null)
3333 return r.BestCandidateIsDynamic ? this : null;
3335 // Overload resolver had to create a new method group, all checks bellow have already been executed
3336 if (r.BestCandidateNewMethodGroup != null)
3337 return r.BestCandidateNewMethodGroup;
3339 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3340 if (InstanceExpression != null) {
3341 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3342 InstanceExpression = null;
3344 if (best_candidate.IsStatic && simple_name != null) {
3345 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3348 InstanceExpression.Resolve (ec);
3352 ResolveInstanceExpression (ec, null);
3353 if (InstanceExpression != null)
3354 CheckProtectedMemberAccess (ec, best_candidate);
3357 var base_override = CandidateToBaseOverride (ec, best_candidate);
3358 if (base_override == best_candidate) {
3359 best_candidate_return = r.BestCandidateReturnType;
3361 best_candidate = base_override;
3362 best_candidate_return = best_candidate.ReturnType;
3368 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3370 simple_name = original;
3371 return base.ResolveMemberAccess (ec, left, original);
3374 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3376 type_arguments = ta;
3379 #region IBaseMembersProvider Members
3381 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3383 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3386 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3388 if (queried_type == member.DeclaringType)
3391 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3392 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3396 // Extension methods lookup after ordinary methods candidates failed to apply
3398 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3400 if (InstanceExpression == null)
3403 InstanceExpression = InstanceExpression.Resolve (rc);
3404 if (!IsExtensionMethodArgument (InstanceExpression))
3407 int arity = type_arguments == null ? 0 : type_arguments.Count;
3408 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3409 if (methods == null)
3412 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3413 emg.SetTypeArguments (rc, type_arguments);
3420 public struct OverloadResolver
3423 public enum Restrictions
3427 ProbingOnly = 1 << 1,
3428 CovariantDelegate = 1 << 2,
3429 NoBaseMembers = 1 << 3,
3430 BaseMembersIncluded = 1 << 4
3433 public interface IBaseMembersProvider
3435 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3436 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3437 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3440 public interface IErrorHandler
3442 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3443 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3444 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3445 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3448 sealed class NoBaseMembers : IBaseMembersProvider
3450 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3452 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3457 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3462 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3468 struct AmbiguousCandidate
3470 public readonly MemberSpec Member;
3471 public readonly bool Expanded;
3472 public readonly AParametersCollection Parameters;
3474 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3477 Parameters = parameters;
3478 Expanded = expanded;
3483 IList<MemberSpec> members;
3484 TypeArguments type_arguments;
3485 IBaseMembersProvider base_provider;
3486 IErrorHandler custom_errors;
3487 Restrictions restrictions;
3488 MethodGroupExpr best_candidate_extension_group;
3489 TypeSpec best_candidate_return_type;
3491 SessionReportPrinter lambda_conv_msgs;
3492 ReportPrinter prev_recorder;
3494 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3495 : this (members, null, restrictions, loc)
3499 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3502 if (members == null || members.Count == 0)
3503 throw new ArgumentException ("empty members set");
3505 this.members = members;
3507 type_arguments = targs;
3508 this.restrictions = restrictions;
3509 if (IsDelegateInvoke)
3510 this.restrictions |= Restrictions.NoBaseMembers;
3512 base_provider = NoBaseMembers.Instance;
3517 public IBaseMembersProvider BaseMembersProvider {
3519 return base_provider;
3522 base_provider = value;
3526 public bool BestCandidateIsDynamic { get; set; }
3529 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3531 public MethodGroupExpr BestCandidateNewMethodGroup {
3533 return best_candidate_extension_group;
3538 // Return type can be different between best candidate and closest override
3540 public TypeSpec BestCandidateReturnType {
3542 return best_candidate_return_type;
3546 public IErrorHandler CustomErrors {
3548 return custom_errors;
3551 custom_errors = value;
3555 TypeSpec DelegateType {
3557 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3558 throw new InternalErrorException ("Not running in delegate mode", loc);
3560 return members [0].DeclaringType;
3564 bool IsProbingOnly {
3566 return (restrictions & Restrictions.ProbingOnly) != 0;
3570 bool IsDelegateInvoke {
3572 return (restrictions & Restrictions.DelegateInvoke) != 0;
3579 // 7.4.3.3 Better conversion from expression
3580 // Returns : 1 if a->p is better,
3581 // 2 if a->q is better,
3582 // 0 if neither is better
3584 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3586 TypeSpec argument_type = a.Type;
3589 // If argument is an anonymous function
3591 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3593 // p and q are delegate types or expression tree types
3595 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3596 if (q.MemberDefinition != p.MemberDefinition) {
3601 // Uwrap delegate from Expression<T>
3603 q = TypeManager.GetTypeArguments (q)[0];
3604 p = TypeManager.GetTypeArguments (p)[0];
3607 var p_m = Delegate.GetInvokeMethod (p);
3608 var q_m = Delegate.GetInvokeMethod (q);
3611 // With identical parameter lists
3613 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3620 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3622 if (p.Kind == MemberKind.Void) {
3623 return q.Kind != MemberKind.Void ? 2 : 0;
3627 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3629 if (q.Kind == MemberKind.Void) {
3630 return p.Kind != MemberKind.Void ? 1: 0;
3634 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3635 // better conversion is performed between underlying types Y1 and Y2
3637 if (p.IsGenericTask || q.IsGenericTask) {
3638 if (p.IsGenericTask != q.IsGenericTask) {
3642 var async_am = a.Expr as AnonymousMethodExpression;
3643 if (async_am == null || !async_am.IsAsync)
3646 q = q.TypeArguments[0];
3647 p = p.TypeArguments[0];
3651 // The parameters are identicial and return type is not void, use better type conversion
3652 // on return type to determine better one
3655 if (argument_type == p)
3658 if (argument_type == q)
3662 return BetterTypeConversion (ec, p, q);
3666 // 7.4.3.4 Better conversion from type
3668 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3670 if (p == null || q == null)
3671 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3673 switch (p.BuiltinType) {
3674 case BuiltinTypeSpec.Type.Int:
3675 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3678 case BuiltinTypeSpec.Type.Long:
3679 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3682 case BuiltinTypeSpec.Type.SByte:
3683 switch (q.BuiltinType) {
3684 case BuiltinTypeSpec.Type.Byte:
3685 case BuiltinTypeSpec.Type.UShort:
3686 case BuiltinTypeSpec.Type.UInt:
3687 case BuiltinTypeSpec.Type.ULong:
3691 case BuiltinTypeSpec.Type.Short:
3692 switch (q.BuiltinType) {
3693 case BuiltinTypeSpec.Type.UShort:
3694 case BuiltinTypeSpec.Type.UInt:
3695 case BuiltinTypeSpec.Type.ULong:
3699 case BuiltinTypeSpec.Type.Dynamic:
3700 // Dynamic is never better
3704 switch (q.BuiltinType) {
3705 case BuiltinTypeSpec.Type.Int:
3706 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3709 case BuiltinTypeSpec.Type.Long:
3710 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3713 case BuiltinTypeSpec.Type.SByte:
3714 switch (p.BuiltinType) {
3715 case BuiltinTypeSpec.Type.Byte:
3716 case BuiltinTypeSpec.Type.UShort:
3717 case BuiltinTypeSpec.Type.UInt:
3718 case BuiltinTypeSpec.Type.ULong:
3722 case BuiltinTypeSpec.Type.Short:
3723 switch (p.BuiltinType) {
3724 case BuiltinTypeSpec.Type.UShort:
3725 case BuiltinTypeSpec.Type.UInt:
3726 case BuiltinTypeSpec.Type.ULong:
3730 case BuiltinTypeSpec.Type.Dynamic:
3731 // Dynamic is never better
3735 // FIXME: handle lifted operators
3737 // TODO: this is expensive
3738 Expression p_tmp = new EmptyExpression (p);
3739 Expression q_tmp = new EmptyExpression (q);
3741 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3742 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3744 if (p_to_q && !q_to_p)
3747 if (q_to_p && !p_to_q)
3754 /// Determines "Better function" between candidate
3755 /// and the current best match
3758 /// Returns a boolean indicating :
3759 /// false if candidate ain't better
3760 /// true if candidate is better than the current best match
3762 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3763 MemberSpec best, AParametersCollection bparam, bool best_params)
3765 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3766 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3768 bool better_at_least_one = false;
3770 int args_count = args == null ? 0 : args.Count;
3774 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3777 // Default arguments are ignored for better decision
3778 if (a.IsDefaultArgument)
3782 // When comparing named argument the parameter type index has to be looked up
3783 // in original parameter set (override version for virtual members)
3785 NamedArgument na = a as NamedArgument;
3787 int idx = cparam.GetParameterIndexByName (na.Name);
3788 ct = candidate_pd.Types[idx];
3789 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3790 ct = TypeManager.GetElementType (ct);
3792 idx = bparam.GetParameterIndexByName (na.Name);
3793 bt = best_pd.Types[idx];
3794 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3795 bt = TypeManager.GetElementType (bt);
3797 ct = candidate_pd.Types[c_idx];
3798 bt = best_pd.Types[b_idx];
3800 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3801 ct = TypeManager.GetElementType (ct);
3805 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3806 bt = TypeManager.GetElementType (bt);
3811 if (TypeSpecComparer.IsEqual (ct, bt))
3815 int result = BetterExpressionConversion (ec, a, ct, bt);
3817 // for each argument, the conversion to 'ct' should be no worse than
3818 // the conversion to 'bt'.
3822 // for at least one argument, the conversion to 'ct' should be better than
3823 // the conversion to 'bt'.
3825 better_at_least_one = true;
3828 if (better_at_least_one)
3832 // This handles the case
3834 // Add (float f1, float f2, float f3);
3835 // Add (params decimal [] foo);
3837 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3838 // first candidate would've chosen as better.
3840 if (!same && !a.IsDefaultArgument)
3844 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3848 // This handles the following cases:
3850 // Foo (int i) is better than Foo (int i, long l = 0)
3851 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3853 // Prefer non-optional version
3855 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3857 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3858 if (candidate_pd.Count >= best_pd.Count)
3861 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3868 // One is a non-generic method and second is a generic method, then non-generic is better
3870 if (best.IsGeneric != candidate.IsGeneric)
3871 return best.IsGeneric;
3874 // This handles the following cases:
3876 // Trim () is better than Trim (params char[] chars)
3877 // Concat (string s1, string s2, string s3) is better than
3878 // Concat (string s1, params string [] srest)
3879 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3881 // Prefer non-expanded version
3883 if (candidate_params != best_params)
3886 int candidate_param_count = candidate_pd.Count;
3887 int best_param_count = best_pd.Count;
3889 if (candidate_param_count != best_param_count)
3890 // can only happen if (candidate_params && best_params)
3891 return candidate_param_count > best_param_count && best_pd.HasParams;
3894 // Both methods have the same number of parameters, and the parameters have equal types
3895 // Pick the "more specific" signature using rules over original (non-inflated) types
3897 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3898 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3900 bool specific_at_least_once = false;
3901 for (j = 0; j < args_count; ++j) {
3902 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3904 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3905 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3907 ct = candidate_def_pd.Types[j];
3908 bt = best_def_pd.Types[j];
3913 TypeSpec specific = MoreSpecific (ct, bt);
3917 specific_at_least_once = true;
3920 if (specific_at_least_once)
3926 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3928 rc.Report.Error (1729, loc,
3929 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3930 type.GetSignatureForError (), argCount.ToString ());
3934 // Determines if the candidate method is applicable to the given set of arguments
3935 // There could be two different set of parameters for same candidate where one
3936 // is the closest override for default values and named arguments checks and second
3937 // one being the virtual base for the parameter types and modifiers.
3939 // A return value rates candidate method compatibility,
3940 // 0 = the best, int.MaxValue = the worst
3942 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
3944 // Parameters of most-derived type used mainly for named and optional parameters
3945 var pd = pm.Parameters;
3947 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3948 // params modifier instead of most-derived type
3949 var cpd = ((IParametersMember) candidate).Parameters;
3950 int param_count = pd.Count;
3951 int optional_count = 0;
3953 Arguments orig_args = arguments;
3955 if (arg_count != param_count) {
3956 for (int i = 0; i < pd.Count; ++i) {
3957 if (pd.FixedParameters[i].HasDefaultValue) {
3958 optional_count = pd.Count - i;
3963 if (optional_count != 0) {
3964 // Readjust expected number when params used
3965 if (cpd.HasParams) {
3967 if (arg_count < param_count)
3969 } else if (arg_count > param_count) {
3970 int args_gap = System.Math.Abs (arg_count - param_count);
3971 return int.MaxValue - 10000 + args_gap;
3973 } else if (arg_count != param_count) {
3974 int args_gap = System.Math.Abs (arg_count - param_count);
3976 return int.MaxValue - 10000 + args_gap;
3977 if (arg_count < param_count - 1)
3978 return int.MaxValue - 10000 + args_gap;
3981 // Resize to fit optional arguments
3982 if (optional_count != 0) {
3983 if (arguments == null) {
3984 arguments = new Arguments (optional_count);
3986 // Have to create a new container, so the next run can do same
3987 var resized = new Arguments (param_count);
3988 resized.AddRange (arguments);
3989 arguments = resized;
3992 for (int i = arg_count; i < param_count; ++i)
3993 arguments.Add (null);
3997 if (arg_count > 0) {
3999 // Shuffle named arguments to the right positions if there are any
4001 if (arguments[arg_count - 1] is NamedArgument) {
4002 arg_count = arguments.Count;
4004 for (int i = 0; i < arg_count; ++i) {
4005 bool arg_moved = false;
4007 NamedArgument na = arguments[i] as NamedArgument;
4011 int index = pd.GetParameterIndexByName (na.Name);
4013 // Named parameter not found
4017 // already reordered
4022 if (index >= param_count) {
4023 // When using parameters which should not be available to the user
4024 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4027 arguments.Add (null);
4031 temp = arguments[index];
4033 // The slot has been taken by positional argument
4034 if (temp != null && !(temp is NamedArgument))
4039 arguments = arguments.MarkOrderedArgument (na);
4043 arguments[index] = arguments[i];
4044 arguments[i] = temp;
4051 arg_count = arguments.Count;
4053 } else if (arguments != null) {
4054 arg_count = arguments.Count;
4058 // 1. Handle generic method using type arguments when specified or type inference
4061 var ms = candidate as MethodSpec;
4062 if (ms != null && ms.IsGeneric) {
4063 // Setup constraint checker for probing only
4064 ConstraintChecker cc = new ConstraintChecker (null);
4066 if (type_arguments != null) {
4067 var g_args_count = ms.Arity;
4068 if (g_args_count != type_arguments.Count)
4069 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4071 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4073 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4074 // for now it simplifies things. I should probably add a callback to ResolveContext
4075 if (lambda_conv_msgs == null) {
4076 lambda_conv_msgs = new SessionReportPrinter ();
4077 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4080 var ti = new TypeInference (arguments);
4081 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4082 lambda_conv_msgs.EndSession ();
4085 return ti.InferenceScore - 20000;
4087 if (i_args.Length != 0) {
4088 ms = ms.MakeGenericMethod (ec, i_args);
4091 cc.IgnoreInferredDynamic = true;
4095 // Type arguments constraints have to match for the method to be applicable
4097 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4099 return int.MaxValue - 25000;
4103 // We have a generic return type and at same time the method is override which
4104 // means we have to also inflate override return type in case the candidate is
4105 // best candidate and override return type is different to base return type.
4107 // virtual Foo<T, object> with override Foo<T, dynamic>
4109 if (candidate != pm) {
4110 MethodSpec override_ms = (MethodSpec) pm;
4111 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4112 returnType = inflator.Inflate (returnType);
4114 returnType = ms.ReturnType;
4118 ptypes = ms.Parameters.Types;
4120 if (type_arguments != null)
4121 return int.MaxValue - 15000;
4127 // 2. Each argument has to be implicitly convertible to method parameter
4129 Parameter.Modifier p_mod = 0;
4132 for (int i = 0; i < arg_count; i++) {
4133 Argument a = arguments[i];
4135 if (!pd.FixedParameters[i].HasDefaultValue) {
4136 arguments = orig_args;
4137 return arg_count * 2 + 2;
4141 // Get the default value expression, we can use the same expression
4142 // if the type matches
4144 Expression e = pd.FixedParameters[i].DefaultValue;
4145 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4147 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4149 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4150 e = new MemberAccess (new MemberAccess (new MemberAccess (
4151 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4153 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4159 arguments[i] = new Argument (e, Argument.AType.Default);
4163 if (p_mod != Parameter.Modifier.PARAMS) {
4164 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4166 } else if (!params_expanded_form) {
4167 params_expanded_form = true;
4168 pt = ((ElementTypeSpec) pt).Element;
4174 if (!params_expanded_form) {
4175 if (a.ArgType == Argument.AType.ExtensionType) {
4177 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4180 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4181 Convert.ImplicitReferenceConversionExists (at, pt) ||
4182 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4187 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4190 dynamicArgument = true;
4195 // It can be applicable in expanded form (when not doing exact match like for delegates)
4197 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4198 if (!params_expanded_form)
4199 pt = ((ElementTypeSpec) pt).Element;
4202 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4205 params_expanded_form = true;
4206 } else if (score < 0) {
4207 params_expanded_form = true;
4208 dynamicArgument = true;
4213 if (params_expanded_form)
4215 return (arg_count - i) * 2 + score;
4220 // When params parameter has no argument it will be provided later if the method is the best candidate
4222 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4223 params_expanded_form = true;
4226 // Restore original arguments for dynamic binder to keep the intention of original source code
4228 if (dynamicArgument)
4229 arguments = orig_args;
4235 // Tests argument compatibility with the parameter
4236 // The possible return values are
4238 // 1 - modifier mismatch
4239 // 2 - type mismatch
4240 // -1 - dynamic binding required
4242 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4245 // Types have to be identical when ref or out modifer
4246 // is used and argument is not of dynamic type
4248 if ((argument.Modifier | param_mod) != 0) {
4249 if (argument.Type != parameter) {
4251 // Do full equality check after quick path
4253 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4255 // Using dynamic for ref/out parameter can still succeed at runtime
4257 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4264 if (argument.Modifier != param_mod) {
4266 // Using dynamic for ref/out parameter can still succeed at runtime
4268 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4275 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4279 // Deploy custom error reporting for lambda methods. When probing lambda methods
4280 // keep all errors reported in separate set and once we are done and no best
4281 // candidate was found, this set is used to report more details about what was wrong
4284 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4285 if (lambda_conv_msgs == null) {
4286 lambda_conv_msgs = new SessionReportPrinter ();
4287 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4292 // Use implicit conversion in all modes to return same candidates when the expression
4293 // is used as argument or delegate conversion
4295 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4296 if (lambda_conv_msgs != null) {
4297 lambda_conv_msgs.EndSession ();
4307 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4309 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4311 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4314 var ac_p = p as ArrayContainer;
4316 var ac_q = ((ArrayContainer) q);
4317 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4318 if (specific == ac_p.Element)
4320 if (specific == ac_q.Element)
4322 } else if (TypeManager.IsGenericType (p)) {
4323 var pargs = TypeManager.GetTypeArguments (p);
4324 var qargs = TypeManager.GetTypeArguments (q);
4326 bool p_specific_at_least_once = false;
4327 bool q_specific_at_least_once = false;
4329 for (int i = 0; i < pargs.Length; i++) {
4330 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4331 if (specific == pargs[i])
4332 p_specific_at_least_once = true;
4333 if (specific == qargs[i])
4334 q_specific_at_least_once = true;
4337 if (p_specific_at_least_once && !q_specific_at_least_once)
4339 if (!p_specific_at_least_once && q_specific_at_least_once)
4347 // Find the best method from candidate list
4349 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4351 List<AmbiguousCandidate> ambiguous_candidates = null;
4353 MemberSpec best_candidate;
4354 Arguments best_candidate_args = null;
4355 bool best_candidate_params = false;
4356 bool best_candidate_dynamic = false;
4357 int best_candidate_rate;
4358 IParametersMember best_parameter_member = null;
4360 int args_count = args != null ? args.Count : 0;
4362 Arguments candidate_args = args;
4363 bool error_mode = false;
4364 MemberSpec invocable_member = null;
4366 // Be careful, cannot return until error reporter is restored
4368 best_candidate = null;
4369 best_candidate_rate = int.MaxValue;
4371 var type_members = members;
4375 for (int i = 0; i < type_members.Count; ++i) {
4376 var member = type_members[i];
4379 // Methods in a base class are not candidates if any method in a derived
4380 // class is applicable
4382 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4386 if (!member.IsAccessible (rc))
4389 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4393 IParametersMember pm = member as IParametersMember;
4396 // Will use it later to report ambiguity between best method and invocable member
4398 if (Invocation.IsMemberInvocable (member))
4399 invocable_member = member;
4405 // Overload resolution is looking for base member but using parameter names
4406 // and default values from the closest member. That means to do expensive lookup
4407 // for the closest override for virtual or abstract members
4409 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4410 var override_params = base_provider.GetOverrideMemberParameters (member);
4411 if (override_params != null)
4412 pm = override_params;
4416 // Check if the member candidate is applicable
4418 bool params_expanded_form = false;
4419 bool dynamic_argument = false;
4420 TypeSpec rt = pm.MemberType;
4421 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4424 // How does it score compare to others
4426 if (candidate_rate < best_candidate_rate) {
4427 best_candidate_rate = candidate_rate;
4428 best_candidate = member;
4429 best_candidate_args = candidate_args;
4430 best_candidate_params = params_expanded_form;
4431 best_candidate_dynamic = dynamic_argument;
4432 best_parameter_member = pm;
4433 best_candidate_return_type = rt;
4434 } else if (candidate_rate == 0) {
4436 // The member look is done per type for most operations but sometimes
4437 // it's not possible like for binary operators overload because they
4438 // are unioned between 2 sides
4440 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4441 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4446 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4448 // We pack all interface members into top level type which makes the overload resolution
4449 // more complicated for interfaces. We compensate it by removing methods with same
4450 // signature when building the cache hence this path should not really be hit often
4453 // interface IA { void Foo (int arg); }
4454 // interface IB : IA { void Foo (params int[] args); }
4456 // IB::Foo is the best overload when calling IB.Foo (1)
4459 if (ambiguous_candidates != null) {
4460 foreach (var amb_cand in ambiguous_candidates) {
4461 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4470 ambiguous_candidates = null;
4473 // Is the new candidate better
4474 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4478 best_candidate = member;
4479 best_candidate_args = candidate_args;
4480 best_candidate_params = params_expanded_form;
4481 best_candidate_dynamic = dynamic_argument;
4482 best_parameter_member = pm;
4483 best_candidate_return_type = rt;
4485 // It's not better but any other found later could be but we are not sure yet
4486 if (ambiguous_candidates == null)
4487 ambiguous_candidates = new List<AmbiguousCandidate> ();
4489 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4493 // Restore expanded arguments
4494 if (candidate_args != args)
4495 candidate_args = args;
4497 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4499 if (prev_recorder != null)
4500 rc.Report.SetPrinter (prev_recorder);
4504 // We've found exact match
4506 if (best_candidate_rate == 0)
4510 // Try extension methods lookup when no ordinary method match was found and provider enables it
4513 var emg = base_provider.LookupExtensionMethod (rc);
4515 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4517 best_candidate_extension_group = emg;
4518 return (T) (MemberSpec) emg.BestCandidate;
4523 // Don't run expensive error reporting mode for probing
4530 lambda_conv_msgs = null;
4535 // No best member match found, report an error
4537 if (best_candidate_rate != 0 || error_mode) {
4538 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4542 if (best_candidate_dynamic) {
4543 if (args[0].ArgType == Argument.AType.ExtensionType) {
4544 rc.Report.Error (1973, loc,
4545 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' cannot be dynamically dispatched. Consider calling the method without the extension method syntax",
4546 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4549 BestCandidateIsDynamic = true;
4554 // These flags indicates we are running delegate probing conversion. No need to
4555 // do more expensive checks
4557 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4558 return (T) best_candidate;
4560 if (ambiguous_candidates != null) {
4562 // Now check that there are no ambiguities i.e the selected method
4563 // should be better than all the others
4565 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4566 var candidate = ambiguous_candidates [ix];
4568 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4569 var ambiguous = candidate.Member;
4570 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4571 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4572 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4573 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4574 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4577 return (T) best_candidate;
4582 if (invocable_member != null) {
4583 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4584 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4585 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4586 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4590 // And now check if the arguments are all
4591 // compatible, perform conversions if
4592 // necessary etc. and return if everything is
4595 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4598 if (best_candidate == null)
4602 // Check ObsoleteAttribute on the best method
4604 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4605 if (oa != null && !rc.IsObsolete)
4606 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4608 var dep = best_candidate.GetMissingDependencies ();
4610 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4613 best_candidate.MemberDefinition.SetIsUsed ();
4615 args = best_candidate_args;
4616 return (T) best_candidate;
4619 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4621 return ResolveMember<MethodSpec> (rc, ref args);
4624 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4625 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4627 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4630 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4631 ec.Report.SymbolRelatedToPreviousError (method);
4632 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4633 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4634 TypeManager.CSharpSignature (method));
4637 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4638 TypeManager.CSharpSignature (method));
4639 } else if (IsDelegateInvoke) {
4640 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4641 DelegateType.GetSignatureForError ());
4643 ec.Report.SymbolRelatedToPreviousError (method);
4644 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4645 method.GetSignatureForError ());
4648 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4650 string index = (idx + 1).ToString ();
4651 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4652 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4653 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4654 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4655 index, Parameter.GetModifierSignature (a.Modifier));
4657 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4658 index, Parameter.GetModifierSignature (mod));
4659 } else if (a.Expr != ErrorExpression.Instance) {
4660 string p1 = a.GetSignatureForError ();
4661 string p2 = TypeManager.CSharpName (paramType);
4664 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4665 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4668 ec.Report.Error (1503, loc,
4669 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4674 // We have failed to find exact match so we return error info about the closest match
4676 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4678 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4679 int arg_count = args == null ? 0 : args.Count;
4681 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4682 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4683 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4687 if (lambda_conv_msgs != null) {
4688 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4693 // For candidates which match on parameters count report more details about incorrect arguments
4696 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4697 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4698 // Reject any inaccessible member
4699 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4700 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4701 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4705 var ms = best_candidate as MethodSpec;
4706 if (ms != null && ms.IsGeneric) {
4707 bool constr_ok = true;
4708 if (ms.TypeArguments != null)
4709 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4711 if (ta_count == 0) {
4712 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4716 rc.Report.Error (411, loc,
4717 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4718 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4725 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4731 // We failed to find any method with correct argument count, report best candidate
4733 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4736 if (best_candidate.Kind == MemberKind.Constructor) {
4737 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4738 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4739 } else if (IsDelegateInvoke) {
4740 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4741 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4742 DelegateType.GetSignatureForError (), arg_count.ToString ());
4744 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4745 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4746 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4747 name, arg_count.ToString ());
4751 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4753 var pd = pm.Parameters;
4754 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4756 Parameter.Modifier p_mod = 0;
4758 int a_idx = 0, a_pos = 0;
4760 ArrayInitializer params_initializers = null;
4761 bool has_unsafe_arg = pm.MemberType.IsPointer;
4762 int arg_count = args == null ? 0 : args.Count;
4764 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4766 if (p_mod != Parameter.Modifier.PARAMS) {
4767 p_mod = pd.FixedParameters[a_idx].ModFlags;
4769 has_unsafe_arg |= pt.IsPointer;
4771 if (p_mod == Parameter.Modifier.PARAMS) {
4772 if (chose_params_expanded) {
4773 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4774 pt = TypeManager.GetElementType (pt);
4780 // Types have to be identical when ref or out modifer is used
4782 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4783 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4786 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4792 NamedArgument na = a as NamedArgument;
4794 int name_index = pd.GetParameterIndexByName (na.Name);
4795 if (name_index < 0 || name_index >= pd.Count) {
4796 if (IsDelegateInvoke) {
4797 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4798 ec.Report.Error (1746, na.Location,
4799 "The delegate `{0}' does not contain a parameter named `{1}'",
4800 DelegateType.GetSignatureForError (), na.Name);
4802 ec.Report.SymbolRelatedToPreviousError (member);
4803 ec.Report.Error (1739, na.Location,
4804 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4805 TypeManager.CSharpSignature (member), na.Name);
4807 } else if (args[name_index] != a) {
4808 if (IsDelegateInvoke)
4809 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4811 ec.Report.SymbolRelatedToPreviousError (member);
4813 ec.Report.Error (1744, na.Location,
4814 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4819 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4822 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4823 custom_errors.NoArgumentMatch (ec, member);
4827 Expression conv = null;
4828 if (a.ArgType == Argument.AType.ExtensionType) {
4829 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4832 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4834 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4837 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4844 // Convert params arguments to an array initializer
4846 if (params_initializers != null) {
4847 // we choose to use 'a.Expr' rather than 'conv' so that
4848 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4849 params_initializers.Add (a.Expr);
4850 args.RemoveAt (a_idx--);
4855 // Update the argument with the implicit conversion
4859 if (a_idx != arg_count) {
4860 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4865 // Fill not provided arguments required by params modifier
4867 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4869 args = new Arguments (1);
4871 pt = ptypes[pd.Count - 1];
4872 pt = TypeManager.GetElementType (pt);
4873 has_unsafe_arg |= pt.IsPointer;
4874 params_initializers = new ArrayInitializer (0, loc);
4878 // Append an array argument with all params arguments
4880 if (params_initializers != null) {
4881 args.Add (new Argument (
4882 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4886 if (has_unsafe_arg && !ec.IsUnsafe) {
4887 Expression.UnsafeError (ec, loc);
4891 // We could infer inaccesible type arguments
4893 if (type_arguments == null && member.IsGeneric) {
4894 var ms = (MethodSpec) member;
4895 foreach (var ta in ms.TypeArguments) {
4896 if (!ta.IsAccessible (ec)) {
4897 ec.Report.SymbolRelatedToPreviousError (ta);
4898 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4908 public class ConstantExpr : MemberExpr
4910 readonly ConstSpec constant;
4912 public ConstantExpr (ConstSpec constant, Location loc)
4914 this.constant = constant;
4918 public override string Name {
4919 get { throw new NotImplementedException (); }
4922 public override bool IsInstance {
4923 get { return !IsStatic; }
4926 public override bool IsStatic {
4927 get { return true; }
4930 protected override TypeSpec DeclaringType {
4931 get { return constant.DeclaringType; }
4934 public override Expression CreateExpressionTree (ResolveContext ec)
4936 throw new NotSupportedException ("ET");
4939 protected override Expression DoResolve (ResolveContext rc)
4941 ResolveInstanceExpression (rc, null);
4942 DoBestMemberChecks (rc, constant);
4944 var c = constant.GetConstant (rc);
4946 // Creates reference expression to the constant value
4947 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4950 public override void Emit (EmitContext ec)
4952 throw new NotSupportedException ();
4955 public override string GetSignatureForError ()
4957 return constant.GetSignatureForError ();
4960 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4962 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4967 // Fully resolved expression that references a Field
4969 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
4971 protected FieldSpec spec;
4972 VariableInfo variable_info;
4974 LocalTemporary temp;
4977 protected FieldExpr (Location l)
4982 public FieldExpr (FieldSpec spec, Location loc)
4987 type = spec.MemberType;
4990 public FieldExpr (FieldBase fi, Location l)
4997 public override string Name {
5003 public bool IsHoisted {
5005 IVariableReference hv = InstanceExpression as IVariableReference;
5006 return hv != null && hv.IsHoisted;
5010 public override bool IsInstance {
5012 return !spec.IsStatic;
5016 public override bool IsStatic {
5018 return spec.IsStatic;
5022 public FieldSpec Spec {
5028 protected override TypeSpec DeclaringType {
5030 return spec.DeclaringType;
5034 public VariableInfo VariableInfo {
5036 return variable_info;
5042 public override string GetSignatureForError ()
5044 return TypeManager.GetFullNameSignature (spec);
5047 public bool IsMarshalByRefAccess (ResolveContext rc)
5049 // Checks possible ldflda of field access expression
5050 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5051 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5052 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5055 public void SetHasAddressTaken ()
5057 IVariableReference vr = InstanceExpression as IVariableReference;
5059 vr.SetHasAddressTaken ();
5062 public override Expression CreateExpressionTree (ResolveContext ec)
5064 Expression instance;
5065 if (InstanceExpression == null) {
5066 instance = new NullLiteral (loc);
5068 instance = InstanceExpression.CreateExpressionTree (ec);
5071 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5073 CreateTypeOfExpression ());
5075 return CreateExpressionFactoryCall (ec, "Field", args);
5078 public Expression CreateTypeOfExpression ()
5080 return new TypeOfField (spec, loc);
5083 protected override Expression DoResolve (ResolveContext ec)
5085 return DoResolve (ec, null);
5088 Expression DoResolve (ResolveContext ec, Expression rhs)
5090 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5093 if (ResolveInstanceExpression (ec, rhs)) {
5094 // Resolve the field's instance expression while flow analysis is turned
5095 // off: when accessing a field "a.b", we must check whether the field
5096 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5098 if (lvalue_instance) {
5099 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5100 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5102 Expression right_side =
5103 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5105 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5108 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5109 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5113 if (InstanceExpression == null)
5117 DoBestMemberChecks (ec, spec);
5120 var fb = spec as FixedFieldSpec;
5121 IVariableReference var = InstanceExpression as IVariableReference;
5123 if (lvalue_instance && var != null && var.VariableInfo != null) {
5124 var.VariableInfo.SetFieldAssigned (ec, Name);
5128 IFixedExpression fe = InstanceExpression as IFixedExpression;
5129 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5130 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5133 if (InstanceExpression.eclass != ExprClass.Variable) {
5134 ec.Report.SymbolRelatedToPreviousError (spec);
5135 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5136 TypeManager.GetFullNameSignature (spec));
5137 } else if (var != null && var.IsHoisted) {
5138 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5141 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5144 eclass = ExprClass.Variable;
5146 // If the instance expression is a local variable or parameter.
5147 if (var == null || var.VariableInfo == null)
5150 VariableInfo vi = var.VariableInfo;
5151 if (!vi.IsFieldAssigned (ec, Name, loc))
5154 variable_info = vi.GetSubStruct (Name);
5158 static readonly int [] codes = {
5159 191, // instance, write access
5160 192, // instance, out access
5161 198, // static, write access
5162 199, // static, out access
5163 1648, // member of value instance, write access
5164 1649, // member of value instance, out access
5165 1650, // member of value static, write access
5166 1651 // member of value static, out access
5169 static readonly string [] msgs = {
5170 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5171 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5172 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5173 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5174 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5175 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5176 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5177 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5180 // The return value is always null. Returning a value simplifies calling code.
5181 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5184 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5188 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5190 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5195 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5197 Expression e = DoResolve (ec, right_side);
5202 spec.MemberDefinition.SetIsAssigned ();
5204 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5205 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5206 ec.Report.Warning (420, 1, loc,
5207 "`{0}': A volatile field references will not be treated as volatile",
5208 spec.GetSignatureForError ());
5211 if (spec.IsReadOnly) {
5212 // InitOnly fields can only be assigned in constructors or initializers
5213 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5214 return Report_AssignToReadonly (ec, right_side);
5216 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5218 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5219 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5220 return Report_AssignToReadonly (ec, right_side);
5221 // static InitOnly fields cannot be assigned-to in an instance constructor
5222 if (IsStatic && !ec.IsStatic)
5223 return Report_AssignToReadonly (ec, right_side);
5224 // instance constructors can't modify InitOnly fields of other instances of the same type
5225 if (!IsStatic && !(InstanceExpression is This))
5226 return Report_AssignToReadonly (ec, right_side);
5230 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5231 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5232 ec.Report.Warning (197, 1, loc,
5233 "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",
5234 GetSignatureForError ());
5237 eclass = ExprClass.Variable;
5241 public override int GetHashCode ()
5243 return spec.GetHashCode ();
5246 public bool IsFixed {
5249 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5251 IVariableReference variable = InstanceExpression as IVariableReference;
5252 if (variable != null)
5253 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5255 IFixedExpression fe = InstanceExpression as IFixedExpression;
5256 return fe != null && fe.IsFixed;
5260 public override bool Equals (object obj)
5262 FieldExpr fe = obj as FieldExpr;
5266 if (spec != fe.spec)
5269 if (InstanceExpression == null || fe.InstanceExpression == null)
5272 return InstanceExpression.Equals (fe.InstanceExpression);
5275 public void Emit (EmitContext ec, bool leave_copy)
5277 bool is_volatile = false;
5279 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5282 spec.MemberDefinition.SetIsUsed ();
5286 ec.Emit (OpCodes.Volatile);
5288 ec.Emit (OpCodes.Ldsfld, spec);
5291 EmitInstance (ec, false);
5293 // Optimization for build-in types
5294 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5295 ec.EmitLoadFromPtr (type);
5297 var ff = spec as FixedFieldSpec;
5299 ec.Emit (OpCodes.Ldflda, spec);
5300 ec.Emit (OpCodes.Ldflda, ff.Element);
5303 ec.Emit (OpCodes.Volatile);
5305 ec.Emit (OpCodes.Ldfld, spec);
5311 ec.Emit (OpCodes.Dup);
5313 temp = new LocalTemporary (this.Type);
5319 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5321 if (ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ()) {
5322 source = source.EmitToField (ec);
5325 prepared = isCompound && !(source is DynamicExpressionStatement);
5327 EmitInstance (ec, prepared);
5332 ec.Emit (OpCodes.Dup);
5334 temp = new LocalTemporary (this.Type);
5339 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5340 ec.Emit (OpCodes.Volatile);
5342 spec.MemberDefinition.SetIsAssigned ();
5345 ec.Emit (OpCodes.Stsfld, spec);
5347 ec.Emit (OpCodes.Stfld, spec);
5357 // Emits store to field with prepared values on stack
5359 public void EmitAssignFromStack (EmitContext ec)
5362 ec.Emit (OpCodes.Stsfld, spec);
5364 ec.Emit (OpCodes.Stfld, spec);
5368 public override void Emit (EmitContext ec)
5373 public override void EmitSideEffect (EmitContext ec)
5375 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5377 if (is_volatile) // || is_marshal_by_ref ())
5378 base.EmitSideEffect (ec);
5381 public void AddressOf (EmitContext ec, AddressOp mode)
5383 if ((mode & AddressOp.Store) != 0)
5384 spec.MemberDefinition.SetIsAssigned ();
5385 if ((mode & AddressOp.Load) != 0)
5386 spec.MemberDefinition.SetIsUsed ();
5389 // Handle initonly fields specially: make a copy and then
5390 // get the address of the copy.
5393 if (spec.IsReadOnly){
5395 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5407 var temp = ec.GetTemporaryLocal (type);
5408 ec.Emit (OpCodes.Stloc, temp);
5409 ec.Emit (OpCodes.Ldloca, temp);
5410 ec.FreeTemporaryLocal (temp, type);
5416 ec.Emit (OpCodes.Ldsflda, spec);
5419 EmitInstance (ec, false);
5420 ec.Emit (OpCodes.Ldflda, spec);
5424 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5426 return MakeExpression (ctx);
5429 public override SLE.Expression MakeExpression (BuilderContext ctx)
5432 return base.MakeExpression (ctx);
5434 return SLE.Expression.Field (
5435 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5436 spec.GetMetaInfo ());
5440 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5442 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5448 // Expression that evaluates to a Property.
5450 // This is not an LValue because we need to re-write the expression. We
5451 // can not take data from the stack and store it.
5453 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5455 public PropertyExpr (PropertySpec spec, Location l)
5458 best_candidate = spec;
5459 type = spec.MemberType;
5464 protected override Arguments Arguments {
5472 protected override TypeSpec DeclaringType {
5474 return best_candidate.DeclaringType;
5478 public override string Name {
5480 return best_candidate.Name;
5484 public override bool IsInstance {
5490 public override bool IsStatic {
5492 return best_candidate.IsStatic;
5496 public PropertySpec PropertyInfo {
5498 return best_candidate;
5504 public override Expression CreateExpressionTree (ResolveContext ec)
5507 if (IsSingleDimensionalArrayLength ()) {
5508 args = new Arguments (1);
5509 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5510 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5513 args = new Arguments (2);
5514 if (InstanceExpression == null)
5515 args.Add (new Argument (new NullLiteral (loc)));
5517 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5518 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5519 return CreateExpressionFactoryCall (ec, "Property", args);
5522 public Expression CreateSetterTypeOfExpression ()
5524 return new TypeOfMethod (Setter, loc);
5527 public override string GetSignatureForError ()
5529 return best_candidate.GetSignatureForError ();
5532 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5535 return base.MakeExpression (ctx);
5537 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5541 public override SLE.Expression MakeExpression (BuilderContext ctx)
5544 return base.MakeExpression (ctx);
5546 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5550 void Error_PropertyNotValid (ResolveContext ec)
5552 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5553 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5554 GetSignatureForError ());
5557 bool IsSingleDimensionalArrayLength ()
5559 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5562 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5563 return ac != null && ac.Rank == 1;
5566 public override void Emit (EmitContext ec, bool leave_copy)
5569 // Special case: length of single dimension array property is turned into ldlen
5571 if (IsSingleDimensionalArrayLength ()) {
5572 EmitInstance (ec, false);
5573 ec.Emit (OpCodes.Ldlen);
5574 ec.Emit (OpCodes.Conv_I4);
5578 base.Emit (ec, leave_copy);
5581 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5584 LocalTemporary await_source_arg = null;
5586 if (isCompound && !(source is DynamicExpressionStatement)) {
5587 emitting_compound_assignment = true;
5590 if (has_await_arguments) {
5591 await_source_arg = new LocalTemporary (Type);
5592 await_source_arg.Store (ec);
5594 args = new Arguments (1);
5595 args.Add (new Argument (await_source_arg));
5598 temp = await_source_arg;
5601 has_await_arguments = false;
5606 ec.Emit (OpCodes.Dup);
5607 temp = new LocalTemporary (this.Type);
5612 args = new Arguments (1);
5616 temp = new LocalTemporary (this.Type);
5618 args.Add (new Argument (temp));
5620 args.Add (new Argument (source));
5624 emitting_compound_assignment = false;
5626 var call = new CallEmitter ();
5627 call.InstanceExpression = InstanceExpression;
5629 call.InstanceExpressionOnStack = true;
5631 call.Emit (ec, Setter, args, loc);
5638 if (await_source_arg != null) {
5639 await_source_arg.Release (ec);
5643 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5645 eclass = ExprClass.PropertyAccess;
5647 if (best_candidate.IsNotCSharpCompatible) {
5648 Error_PropertyNotValid (rc);
5651 ResolveInstanceExpression (rc, right_side);
5653 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5654 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5655 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5657 type = p.MemberType;
5661 DoBestMemberChecks (rc, best_candidate);
5665 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5667 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5671 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5673 // getter and setter can be different for base calls
5674 MethodSpec getter, setter;
5675 protected T best_candidate;
5677 protected LocalTemporary temp;
5678 protected bool emitting_compound_assignment;
5679 protected bool has_await_arguments;
5681 protected PropertyOrIndexerExpr (Location l)
5688 protected abstract Arguments Arguments { get; set; }
5690 public MethodSpec Getter {
5699 public MethodSpec Setter {
5710 protected override Expression DoResolve (ResolveContext ec)
5712 if (eclass == ExprClass.Unresolved) {
5713 var expr = OverloadResolve (ec, null);
5718 return expr.Resolve (ec);
5721 if (!ResolveGetter (ec))
5727 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5729 if (right_side == EmptyExpression.OutAccess) {
5730 // TODO: best_candidate can be null at this point
5731 INamedBlockVariable variable = null;
5732 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5733 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5734 best_candidate.Name);
5736 right_side.DoResolveLValue (ec, this);
5741 // if the property/indexer returns a value type, and we try to set a field in it
5742 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5743 Error_CannotModifyIntermediateExpressionValue (ec);
5746 if (eclass == ExprClass.Unresolved) {
5747 var expr = OverloadResolve (ec, right_side);
5752 return expr.ResolveLValue (ec, right_side);
5755 if (!ResolveSetter (ec))
5762 // Implements the IAssignMethod interface for assignments
5764 public virtual void Emit (EmitContext ec, bool leave_copy)
5766 var call = new CallEmitter ();
5767 call.InstanceExpression = InstanceExpression;
5768 if (has_await_arguments)
5769 call.HasAwaitArguments = true;
5771 call.DuplicateArguments = emitting_compound_assignment;
5773 call.Emit (ec, Getter, Arguments, loc);
5775 if (call.HasAwaitArguments) {
5776 InstanceExpression = call.InstanceExpression;
5777 Arguments = call.EmittedArguments;
5778 has_await_arguments = true;
5782 ec.Emit (OpCodes.Dup);
5783 temp = new LocalTemporary (Type);
5788 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5790 public override void Emit (EmitContext ec)
5795 protected override void EmitToFieldSource (EmitContext ec)
5797 has_await_arguments = true;
5801 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5803 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5805 bool ResolveGetter (ResolveContext rc)
5807 if (!best_candidate.HasGet) {
5808 if (InstanceExpression != EmptyExpression.Null) {
5809 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5810 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5811 best_candidate.GetSignatureForError ());
5814 } else if (!best_candidate.Get.IsAccessible (rc)) {
5815 if (best_candidate.HasDifferentAccessibility) {
5816 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5817 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5818 TypeManager.CSharpSignature (best_candidate));
5820 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5821 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5825 if (best_candidate.HasDifferentAccessibility) {
5826 CheckProtectedMemberAccess (rc, best_candidate.Get);
5829 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5833 bool ResolveSetter (ResolveContext rc)
5835 if (!best_candidate.HasSet) {
5836 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5837 GetSignatureForError ());
5841 if (!best_candidate.Set.IsAccessible (rc)) {
5842 if (best_candidate.HasDifferentAccessibility) {
5843 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5844 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5845 GetSignatureForError ());
5847 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5848 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5852 if (best_candidate.HasDifferentAccessibility)
5853 CheckProtectedMemberAccess (rc, best_candidate.Set);
5855 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5861 /// Fully resolved expression that evaluates to an Event
5863 public class EventExpr : MemberExpr, IAssignMethod
5865 readonly EventSpec spec;
5868 public EventExpr (EventSpec spec, Location loc)
5876 protected override TypeSpec DeclaringType {
5878 return spec.DeclaringType;
5882 public override string Name {
5888 public override bool IsInstance {
5890 return !spec.IsStatic;
5894 public override bool IsStatic {
5896 return spec.IsStatic;
5900 public MethodSpec Operator {
5908 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5911 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5913 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5914 if (spec.BackingField != null &&
5915 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5917 spec.MemberDefinition.SetIsUsed ();
5919 if (!ec.IsObsolete) {
5920 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5922 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5925 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5926 Error_AssignmentEventOnly (ec);
5928 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5930 InstanceExpression = null;
5932 return ml.ResolveMemberAccess (ec, left, original);
5936 return base.ResolveMemberAccess (ec, left, original);
5939 public override Expression CreateExpressionTree (ResolveContext ec)
5941 throw new NotSupportedException ("ET");
5944 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5946 if (right_side == EmptyExpression.EventAddition) {
5947 op = spec.AccessorAdd;
5948 } else if (right_side == EmptyExpression.EventSubtraction) {
5949 op = spec.AccessorRemove;
5953 Error_AssignmentEventOnly (ec);
5957 op = CandidateToBaseOverride (ec, op);
5961 protected override Expression DoResolve (ResolveContext ec)
5963 eclass = ExprClass.EventAccess;
5964 type = spec.MemberType;
5966 ResolveInstanceExpression (ec, null);
5968 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5969 Error_AssignmentEventOnly (ec);
5972 DoBestMemberChecks (ec, spec);
5976 public override void Emit (EmitContext ec)
5978 throw new NotSupportedException ();
5979 //Error_CannotAssign ();
5982 #region IAssignMethod Members
5984 public void Emit (EmitContext ec, bool leave_copy)
5986 throw new NotImplementedException ();
5989 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5991 if (leave_copy || !isCompound)
5992 throw new NotImplementedException ("EventExpr::EmitAssign");
5994 Arguments args = new Arguments (1);
5995 args.Add (new Argument (source));
5997 var call = new CallEmitter ();
5998 call.InstanceExpression = InstanceExpression;
5999 call.Emit (ec, op, args, loc);
6004 void Error_AssignmentEventOnly (ResolveContext ec)
6006 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6007 ec.Report.Error (79, loc,
6008 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6009 GetSignatureForError ());
6011 ec.Report.Error (70, loc,
6012 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6013 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6017 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6019 name = name.Substring (0, name.LastIndexOf ('.'));
6020 base.Error_CannotCallAbstractBase (rc, name);
6023 public override string GetSignatureForError ()
6025 return TypeManager.CSharpSignature (spec);
6028 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6030 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6034 public class TemporaryVariableReference : VariableReference
6036 public class Declarator : Statement
6038 TemporaryVariableReference variable;
6040 public Declarator (TemporaryVariableReference variable)
6042 this.variable = variable;
6046 protected override void DoEmit (EmitContext ec)
6048 variable.li.CreateBuilder (ec);
6051 protected override void CloneTo (CloneContext clonectx, Statement target)
6059 public TemporaryVariableReference (LocalVariable li, Location loc)
6062 this.type = li.Type;
6066 public override bool IsLockedByStatement {
6074 public LocalVariable LocalInfo {
6080 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6082 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6083 return new TemporaryVariableReference (li, loc);
6086 public override Expression CreateExpressionTree (ResolveContext ec)
6088 throw new NotSupportedException ("ET");
6091 protected override Expression DoResolve (ResolveContext ec)
6093 eclass = ExprClass.Variable;
6096 // Don't capture temporary variables except when using
6097 // iterator redirection
6099 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6100 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6101 storey.CaptureLocalVariable (ec, li);
6107 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6109 return Resolve (ec);
6112 public override void Emit (EmitContext ec)
6114 li.CreateBuilder (ec);
6119 public void EmitAssign (EmitContext ec, Expression source)
6121 li.CreateBuilder (ec);
6123 EmitAssign (ec, source, false, false);
6126 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6128 return li.HoistedVariant;
6131 public override bool IsFixed {
6132 get { return true; }
6135 public override bool IsRef {
6136 get { return false; }
6139 public override string Name {
6140 get { throw new NotImplementedException (); }
6143 public override void SetHasAddressTaken ()
6145 throw new NotImplementedException ();
6148 protected override ILocalVariable Variable {
6152 public override VariableInfo VariableInfo {
6153 get { throw new NotImplementedException (); }
6158 /// Handles `var' contextual keyword; var becomes a keyword only
6159 /// if no type called var exists in a variable scope
6161 class VarExpr : SimpleName
6163 public VarExpr (Location loc)
6168 public bool InferType (ResolveContext ec, Expression right_side)
6171 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6173 type = right_side.Type;
6174 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6175 ec.Report.Error (815, loc,
6176 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6177 type.GetSignatureForError ());
6181 eclass = ExprClass.Variable;
6185 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6187 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6188 base.Error_TypeOrNamespaceNotFound (ec);
6190 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");