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 bool needs_temporary = ContainsEmitWithAwait ();
523 if (!needs_temporary)
526 // Emit original code
527 EmitToFieldSource (ec);
530 // Store the result to temporary field when we
531 // cannot load this directly
533 var field = ec.GetTemporaryField (type);
534 if (needs_temporary) {
536 // Create temporary local (we cannot load this before Emit)
538 var temp = ec.GetTemporaryLocal (type);
539 ec.Emit (OpCodes.Stloc, temp);
542 ec.Emit (OpCodes.Ldloc, temp);
543 field.EmitAssignFromStack (ec);
545 ec.FreeTemporaryLocal (temp, type);
547 field.EmitAssignFromStack (ec);
553 protected virtual void EmitToFieldSource (EmitContext ec)
556 // Default implementation calls Emit method
561 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
563 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
564 bool contains_await = false;
566 for (int i = 1; i < expressions.Count; ++i) {
567 if (expressions[i].ContainsEmitWithAwait ()) {
568 contains_await = true;
573 if (contains_await) {
574 for (int i = 0; i < expressions.Count; ++i) {
575 expressions[i] = expressions[i].EmitToField (ec);
580 for (int i = 0; i < expressions.Count; ++i) {
581 expressions[i].Emit (ec);
586 /// Protected constructor. Only derivate types should
587 /// be able to be created
590 protected Expression ()
595 /// Returns a fully formed expression after a MemberLookup
598 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
600 if (spec is EventSpec)
601 return new EventExpr ((EventSpec) spec, loc);
602 if (spec is ConstSpec)
603 return new ConstantExpr ((ConstSpec) spec, loc);
604 if (spec is FieldSpec)
605 return new FieldExpr ((FieldSpec) spec, loc);
606 if (spec is PropertySpec)
607 return new PropertyExpr ((PropertySpec) spec, loc);
608 if (spec is TypeSpec)
609 return new TypeExpression (((TypeSpec) spec), loc);
614 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
616 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
618 rc.Report.SymbolRelatedToPreviousError (type);
620 // Report meaningful error for struct as they always have default ctor in C# context
621 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
623 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
624 type.GetSignatureForError ());
630 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
631 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
635 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
636 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
643 public enum MemberLookupRestrictions
652 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
653 // `qualifier_type' or null to lookup members in the current class.
655 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
657 var members = MemberCache.FindMembers (queried_type, name, false);
661 MemberSpec non_method = null;
662 MemberSpec ambig_non_method = null;
664 for (int i = 0; i < members.Count; ++i) {
665 var member = members[i];
667 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
668 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
671 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
675 if (!member.IsAccessible (rc))
679 // With runtime binder we can have a situation where queried type is inaccessible
680 // because it came via dynamic object, the check about inconsisted accessibility
681 // had no effect as the type was unknown during compilation
684 // private class N { }
686 // public dynamic Foo ()
692 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
696 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
697 if (member is MethodSpec)
698 return new MethodGroupExpr (members, queried_type, loc);
700 if (!Invocation.IsMemberInvocable (member))
704 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
706 } else if (!errorMode && !member.IsNotCSharpCompatible) {
707 ambig_non_method = member;
711 if (non_method != null) {
712 if (ambig_non_method != null && rc != null) {
713 var report = rc.Module.Compiler.Report;
714 report.SymbolRelatedToPreviousError (non_method);
715 report.SymbolRelatedToPreviousError (ambig_non_method);
716 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
717 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
720 if (non_method is MethodSpec)
721 return new MethodGroupExpr (members, queried_type, loc);
723 return ExprClassFromMemberInfo (non_method, loc);
726 if (members[0].DeclaringType.BaseType == null)
729 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
731 } while (members != null);
736 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
738 throw new NotImplementedException ();
741 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
743 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
747 /// Returns an expression that can be used to invoke operator true
748 /// on the expression if it exists.
750 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
752 return GetOperatorTrueOrFalse (ec, e, true, loc);
756 /// Returns an expression that can be used to invoke operator false
757 /// on the expression if it exists.
759 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
761 return GetOperatorTrueOrFalse (ec, e, false, loc);
764 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
766 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
767 var methods = MemberCache.GetUserOperator (e.type, op, false);
771 Arguments arguments = new Arguments (1);
772 arguments.Add (new Argument (e));
774 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
775 var oper = res.ResolveOperator (ec, ref arguments);
780 return new UserOperatorCall (oper, arguments, null, loc);
783 public virtual string ExprClassName
787 case ExprClass.Unresolved:
789 case ExprClass.Value:
791 case ExprClass.Variable:
793 case ExprClass.Namespace:
797 case ExprClass.MethodGroup:
798 return "method group";
799 case ExprClass.PropertyAccess:
800 return "property access";
801 case ExprClass.EventAccess:
802 return "event access";
803 case ExprClass.IndexerAccess:
804 return "indexer access";
805 case ExprClass.Nothing:
807 case ExprClass.TypeParameter:
808 return "type parameter";
810 throw new Exception ("Should not happen");
815 /// Reports that we were expecting `expr' to be of class `expected'
817 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
819 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
822 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
826 name = mc.GetSignatureForError ();
828 name = GetSignatureForError ();
830 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
831 name, was, expected);
834 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
836 string [] valid = new string [4];
839 if ((flags & ResolveFlags.VariableOrValue) != 0) {
840 valid [count++] = "variable";
841 valid [count++] = "value";
844 if ((flags & ResolveFlags.Type) != 0)
845 valid [count++] = "type";
847 if ((flags & ResolveFlags.MethodGroup) != 0)
848 valid [count++] = "method group";
851 valid [count++] = "unknown";
853 StringBuilder sb = new StringBuilder (valid [0]);
854 for (int i = 1; i < count - 1; i++) {
856 sb.Append (valid [i]);
859 sb.Append ("' or `");
860 sb.Append (valid [count - 1]);
863 ec.Report.Error (119, loc,
864 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
867 public static void UnsafeError (ResolveContext ec, Location loc)
869 UnsafeError (ec.Report, loc);
872 public static void UnsafeError (Report Report, Location loc)
874 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
877 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
879 ec.Report.SymbolRelatedToPreviousError (type);
880 if (ec.CurrentInitializerVariable != null) {
881 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
882 TypeManager.CSharpName (type), GetSignatureForError ());
884 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
885 GetSignatureForError ());
890 // Converts `source' to an int, uint, long or ulong.
892 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
894 var btypes = ec.BuiltinTypes;
896 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
897 Arguments args = new Arguments (1);
898 args.Add (new Argument (source));
899 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
902 Expression converted;
904 using (ec.Set (ResolveContext.Options.CheckedScope)) {
905 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
906 if (converted == null)
907 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
908 if (converted == null)
909 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
910 if (converted == null)
911 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
913 if (converted == null) {
914 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
920 // Only positive constants are allowed at compile time
922 Constant c = converted as Constant;
923 if (c != null && c.IsNegative)
924 Error_NegativeArrayIndex (ec, source.loc);
926 // No conversion needed to array index
927 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
930 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
934 // Derived classes implement this method by cloning the fields that
935 // could become altered during the Resolve stage
937 // Only expressions that are created for the parser need to implement
940 protected virtual void CloneTo (CloneContext clonectx, Expression target)
942 throw new NotImplementedException (
944 "CloneTo not implemented for expression {0}", this.GetType ()));
948 // Clones an expression created by the parser.
950 // We only support expressions created by the parser so far, not
951 // expressions that have been resolved (many more classes would need
952 // to implement CloneTo).
954 // This infrastructure is here merely for Lambda expressions which
955 // compile the same code using different type values for the same
956 // arguments to find the correct overload
958 public virtual Expression Clone (CloneContext clonectx)
960 Expression cloned = (Expression) MemberwiseClone ();
961 CloneTo (clonectx, cloned);
967 // Implementation of expression to expression tree conversion
969 public abstract Expression CreateExpressionTree (ResolveContext ec);
971 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
973 return CreateExpressionFactoryCall (ec, name, null, args, loc);
976 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
978 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
981 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
983 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
986 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
988 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
992 return new TypeExpression (t, loc);
996 // Implemented by all expressions which support conversion from
997 // compiler expression to invokable runtime expression. Used by
998 // dynamic C# binder.
1000 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1002 throw new NotImplementedException ("MakeExpression for " + GetType ());
1007 /// This is just a base class for expressions that can
1008 /// appear on statements (invocations, object creation,
1009 /// assignments, post/pre increment and decrement). The idea
1010 /// being that they would support an extra Emition interface that
1011 /// does not leave a result on the stack.
1013 public abstract class ExpressionStatement : Expression {
1015 public ExpressionStatement ResolveStatement (BlockContext ec)
1017 Expression e = Resolve (ec);
1021 ExpressionStatement es = e as ExpressionStatement;
1023 Error_InvalidExpressionStatement (ec);
1029 /// Requests the expression to be emitted in a `statement'
1030 /// context. This means that no new value is left on the
1031 /// stack after invoking this method (constrasted with
1032 /// Emit that will always leave a value on the stack).
1034 public abstract void EmitStatement (EmitContext ec);
1036 public override void EmitSideEffect (EmitContext ec)
1043 /// This kind of cast is used to encapsulate the child
1044 /// whose type is child.Type into an expression that is
1045 /// reported to return "return_type". This is used to encapsulate
1046 /// expressions which have compatible types, but need to be dealt
1047 /// at higher levels with.
1049 /// For example, a "byte" expression could be encapsulated in one
1050 /// of these as an "unsigned int". The type for the expression
1051 /// would be "unsigned int".
1054 public abstract class TypeCast : Expression
1056 protected readonly Expression child;
1058 protected TypeCast (Expression child, TypeSpec return_type)
1060 eclass = child.eclass;
1061 loc = child.Location;
1066 public Expression Child {
1072 public override bool ContainsEmitWithAwait ()
1074 return child.ContainsEmitWithAwait ();
1077 public override Expression CreateExpressionTree (ResolveContext ec)
1079 Arguments args = new Arguments (2);
1080 args.Add (new Argument (child.CreateExpressionTree (ec)));
1081 args.Add (new Argument (new TypeOf (type, loc)));
1083 if (type.IsPointer || child.Type.IsPointer)
1084 Error_PointerInsideExpressionTree (ec);
1086 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1089 protected override Expression DoResolve (ResolveContext ec)
1091 // This should never be invoked, we are born in fully
1092 // initialized state.
1097 public override void Emit (EmitContext ec)
1102 public override SLE.Expression MakeExpression (BuilderContext ctx)
1105 return base.MakeExpression (ctx);
1107 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1108 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1109 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1113 protected override void CloneTo (CloneContext clonectx, Expression t)
1118 public override bool IsNull {
1119 get { return child.IsNull; }
1123 public class EmptyCast : TypeCast {
1124 EmptyCast (Expression child, TypeSpec target_type)
1125 : base (child, target_type)
1129 public static Expression Create (Expression child, TypeSpec type)
1131 Constant c = child as Constant;
1133 return new EmptyConstantCast (c, type);
1135 EmptyCast e = child as EmptyCast;
1137 return new EmptyCast (e.child, type);
1139 return new EmptyCast (child, type);
1142 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1144 child.EmitBranchable (ec, label, on_true);
1147 public override void EmitSideEffect (EmitContext ec)
1149 child.EmitSideEffect (ec);
1154 // Used for predefined type user operator (no obsolete check, etc.)
1156 public class OperatorCast : TypeCast
1158 readonly MethodSpec conversion_operator;
1160 public OperatorCast (Expression expr, TypeSpec target_type)
1161 : this (expr, target_type, target_type, false)
1165 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1166 : this (expr, target_type, target_type, find_explicit)
1170 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1171 : base (expr, returnType)
1173 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1174 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1177 foreach (MethodSpec oper in mi) {
1178 if (oper.ReturnType != returnType)
1181 if (oper.Parameters.Types[0] == expr.Type) {
1182 conversion_operator = oper;
1188 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1189 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1192 public override void Emit (EmitContext ec)
1195 ec.Emit (OpCodes.Call, conversion_operator);
1200 // Constant specialization of EmptyCast.
1201 // We need to special case this since an empty cast of
1202 // a constant is still a constant.
1204 public class EmptyConstantCast : Constant
1206 public readonly Constant child;
1208 public EmptyConstantCast (Constant child, TypeSpec type)
1209 : base (child.Location)
1212 throw new ArgumentNullException ("child");
1215 this.eclass = child.eclass;
1219 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1221 if (child.Type == target_type)
1224 // FIXME: check that 'type' can be converted to 'target_type' first
1225 return child.ConvertExplicitly (in_checked_context, target_type);
1228 public override Expression CreateExpressionTree (ResolveContext ec)
1230 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1231 child.CreateExpressionTree (ec),
1232 new TypeOf (type, loc));
1235 Error_PointerInsideExpressionTree (ec);
1237 return CreateExpressionFactoryCall (ec, "Convert", args);
1240 public override bool IsDefaultValue {
1241 get { return child.IsDefaultValue; }
1244 public override bool IsNegative {
1245 get { return child.IsNegative; }
1248 public override bool IsNull {
1249 get { return child.IsNull; }
1252 public override bool IsOneInteger {
1253 get { return child.IsOneInteger; }
1256 public override bool IsSideEffectFree {
1258 return child.IsSideEffectFree;
1262 public override bool IsZeroInteger {
1263 get { return child.IsZeroInteger; }
1266 public override void Emit (EmitContext ec)
1271 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1273 child.EmitBranchable (ec, label, on_true);
1275 // Only to make verifier happy
1276 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1277 ec.Emit (OpCodes.Unbox_Any, type);
1280 public override void EmitSideEffect (EmitContext ec)
1282 child.EmitSideEffect (ec);
1285 public override object GetValue ()
1287 return child.GetValue ();
1290 public override string GetValueAsLiteral ()
1292 return child.GetValueAsLiteral ();
1295 public override long GetValueAsLong ()
1297 return child.GetValueAsLong ();
1300 public override Constant ConvertImplicitly (TypeSpec target_type)
1302 if (type == target_type)
1305 // FIXME: Do we need to check user conversions?
1306 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1309 return child.ConvertImplicitly (target_type);
1314 /// This class is used to wrap literals which belong inside Enums
1316 public class EnumConstant : Constant
1318 public Constant Child;
1320 public EnumConstant (Constant child, TypeSpec enum_type)
1321 : base (child.Location)
1325 this.eclass = ExprClass.Value;
1326 this.type = enum_type;
1329 protected EnumConstant (Location loc)
1334 public override void Emit (EmitContext ec)
1339 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1341 Child.EncodeAttributeValue (rc, enc, Child.Type);
1344 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1346 Child.EmitBranchable (ec, label, on_true);
1349 public override void EmitSideEffect (EmitContext ec)
1351 Child.EmitSideEffect (ec);
1354 public override string GetSignatureForError()
1356 return TypeManager.CSharpName (Type);
1359 public override object GetValue ()
1361 return Child.GetValue ();
1365 public override object GetTypedValue ()
1368 // The method can be used in dynamic context only (on closed types)
1370 // System.Enum.ToObject cannot be called on dynamic types
1371 // EnumBuilder has to be used, but we cannot use EnumBuilder
1372 // because it does not properly support generics
1374 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1378 public override string GetValueAsLiteral ()
1380 return Child.GetValueAsLiteral ();
1383 public override long GetValueAsLong ()
1385 return Child.GetValueAsLong ();
1388 public EnumConstant Increment()
1390 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1393 public override bool IsDefaultValue {
1395 return Child.IsDefaultValue;
1399 public override bool IsSideEffectFree {
1401 return Child.IsSideEffectFree;
1405 public override bool IsZeroInteger {
1406 get { return Child.IsZeroInteger; }
1409 public override bool IsNegative {
1411 return Child.IsNegative;
1415 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1417 if (Child.Type == target_type)
1420 return Child.ConvertExplicitly (in_checked_context, target_type);
1423 public override Constant ConvertImplicitly (TypeSpec type)
1425 if (this.type == type) {
1429 if (!Convert.ImplicitStandardConversionExists (this, type)){
1433 return Child.ConvertImplicitly (type);
1438 /// This kind of cast is used to encapsulate Value Types in objects.
1440 /// The effect of it is to box the value type emitted by the previous
1443 public class BoxedCast : TypeCast {
1445 public BoxedCast (Expression expr, TypeSpec target_type)
1446 : base (expr, target_type)
1448 eclass = ExprClass.Value;
1451 protected override Expression DoResolve (ResolveContext ec)
1453 // This should never be invoked, we are born in fully
1454 // initialized state.
1459 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1461 // Only boxing to object type is supported
1462 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1463 base.EncodeAttributeValue (rc, enc, targetType);
1467 enc.Encode (child.Type);
1468 child.EncodeAttributeValue (rc, enc, child.Type);
1471 public override void Emit (EmitContext ec)
1475 ec.Emit (OpCodes.Box, child.Type);
1478 public override void EmitSideEffect (EmitContext ec)
1480 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1481 // so, we need to emit the box+pop instructions in most cases
1482 if (child.Type.IsStruct &&
1483 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1484 child.EmitSideEffect (ec);
1486 base.EmitSideEffect (ec);
1490 public class UnboxCast : TypeCast {
1491 public UnboxCast (Expression expr, TypeSpec return_type)
1492 : base (expr, return_type)
1496 protected override Expression DoResolve (ResolveContext ec)
1498 // This should never be invoked, we are born in fully
1499 // initialized state.
1504 public override void Emit (EmitContext ec)
1508 ec.Emit (OpCodes.Unbox_Any, type);
1513 /// This is used to perform explicit numeric conversions.
1515 /// Explicit numeric conversions might trigger exceptions in a checked
1516 /// context, so they should generate the conv.ovf opcodes instead of
1519 public class ConvCast : TypeCast {
1520 public enum Mode : byte {
1521 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1523 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1524 U2_I1, U2_U1, U2_I2, U2_CH,
1525 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1526 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1527 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1528 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1529 CH_I1, CH_U1, CH_I2,
1530 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1531 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1537 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1538 : base (child, return_type)
1543 protected override Expression DoResolve (ResolveContext ec)
1545 // This should never be invoked, we are born in fully
1546 // initialized state.
1551 public override string ToString ()
1553 return String.Format ("ConvCast ({0}, {1})", mode, child);
1556 public override void Emit (EmitContext ec)
1560 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1562 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1563 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1564 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1565 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1566 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1568 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1569 case Mode.U1_CH: /* nothing */ break;
1571 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1572 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1573 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1574 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1575 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1576 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1578 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1579 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1580 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1581 case Mode.U2_CH: /* nothing */ break;
1583 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1584 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1585 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1586 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1587 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1588 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1589 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1592 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1593 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1594 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1595 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1596 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1598 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1599 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1600 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1601 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1602 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1603 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1604 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1605 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1608 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1609 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1610 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1611 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1612 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1613 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1614 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1615 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1616 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1618 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1619 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1620 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1622 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1623 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1624 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1625 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1626 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1627 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1628 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1629 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1630 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1632 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1633 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1634 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1635 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1637 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1638 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1639 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1640 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1641 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1643 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1647 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1648 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1649 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1650 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1651 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1653 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1654 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1656 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1657 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1658 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1659 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1660 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1661 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1663 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1664 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1665 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1666 case Mode.U2_CH: /* nothing */ break;
1668 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1670 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1671 case Mode.I4_U4: /* nothing */ break;
1672 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1673 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1674 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1677 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1678 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1679 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.U4_I4: /* nothing */ break;
1681 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1683 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1684 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1685 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1686 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1687 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1688 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1689 case Mode.I8_U8: /* nothing */ break;
1690 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1693 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1694 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1695 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1697 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1698 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1699 case Mode.U8_I8: /* nothing */ break;
1700 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1701 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1703 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1704 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1705 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1707 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1708 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1709 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1710 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1711 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1712 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1713 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1714 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1715 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1717 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1718 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1719 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1720 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1722 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1723 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1724 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1725 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1726 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1728 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1734 class OpcodeCast : TypeCast
1738 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1739 : base (child, return_type)
1744 protected override Expression DoResolve (ResolveContext ec)
1746 // This should never be invoked, we are born in fully
1747 // initialized state.
1752 public override void Emit (EmitContext ec)
1758 public TypeSpec UnderlyingType {
1759 get { return child.Type; }
1764 // Opcode casts expression with 2 opcodes but only
1765 // single expression tree node
1767 class OpcodeCastDuplex : OpcodeCast
1769 readonly OpCode second;
1771 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1772 : base (child, returnType, first)
1774 this.second = second;
1777 public override void Emit (EmitContext ec)
1785 /// This kind of cast is used to encapsulate a child and cast it
1786 /// to the class requested
1788 public sealed class ClassCast : TypeCast {
1789 readonly bool forced;
1791 public ClassCast (Expression child, TypeSpec return_type)
1792 : base (child, return_type)
1796 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1797 : base (child, return_type)
1799 this.forced = forced;
1802 public override void Emit (EmitContext ec)
1806 bool gen = TypeManager.IsGenericParameter (child.Type);
1808 ec.Emit (OpCodes.Box, child.Type);
1810 if (type.IsGenericParameter) {
1811 ec.Emit (OpCodes.Unbox_Any, type);
1818 ec.Emit (OpCodes.Castclass, type);
1823 // Created during resolving pahse when an expression is wrapped or constantified
1824 // and original expression can be used later (e.g. for expression trees)
1826 public class ReducedExpression : Expression
1828 sealed class ReducedConstantExpression : EmptyConstantCast
1830 readonly Expression orig_expr;
1832 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1833 : base (expr, expr.Type)
1835 this.orig_expr = orig_expr;
1838 public override Constant ConvertImplicitly (TypeSpec target_type)
1840 Constant c = base.ConvertImplicitly (target_type);
1842 c = new ReducedConstantExpression (c, orig_expr);
1847 public override Expression CreateExpressionTree (ResolveContext ec)
1849 return orig_expr.CreateExpressionTree (ec);
1852 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1854 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1856 c = new ReducedConstantExpression (c, orig_expr);
1861 sealed class ReducedExpressionStatement : ExpressionStatement
1863 readonly Expression orig_expr;
1864 readonly ExpressionStatement stm;
1866 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1868 this.orig_expr = orig;
1870 this.eclass = stm.eclass;
1871 this.type = stm.Type;
1873 this.loc = orig.Location;
1876 public override bool ContainsEmitWithAwait ()
1878 return stm.ContainsEmitWithAwait ();
1881 public override Expression CreateExpressionTree (ResolveContext ec)
1883 return orig_expr.CreateExpressionTree (ec);
1886 protected override Expression DoResolve (ResolveContext ec)
1891 public override void Emit (EmitContext ec)
1896 public override void EmitStatement (EmitContext ec)
1898 stm.EmitStatement (ec);
1902 readonly Expression expr, orig_expr;
1904 private ReducedExpression (Expression expr, Expression orig_expr)
1907 this.eclass = expr.eclass;
1908 this.type = expr.Type;
1909 this.orig_expr = orig_expr;
1910 this.loc = orig_expr.Location;
1915 public Expression OriginalExpression {
1923 public override bool ContainsEmitWithAwait ()
1925 return expr.ContainsEmitWithAwait ();
1929 // Creates fully resolved expression switcher
1931 public static Constant Create (Constant expr, Expression original_expr)
1933 if (expr.eclass == ExprClass.Unresolved)
1934 throw new ArgumentException ("Unresolved expression");
1936 return new ReducedConstantExpression (expr, original_expr);
1939 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1941 return new ReducedExpressionStatement (s, orig);
1944 public static Expression Create (Expression expr, Expression original_expr)
1946 return Create (expr, original_expr, true);
1950 // Creates unresolved reduce expression. The original expression has to be
1951 // already resolved. Created expression is constant based based on `expr'
1952 // value unless canBeConstant is used
1954 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1956 if (canBeConstant) {
1957 Constant c = expr as Constant;
1959 return Create (c, original_expr);
1962 ExpressionStatement s = expr as ExpressionStatement;
1964 return Create (s, original_expr);
1966 if (expr.eclass == ExprClass.Unresolved)
1967 throw new ArgumentException ("Unresolved expression");
1969 return new ReducedExpression (expr, original_expr);
1972 public override Expression CreateExpressionTree (ResolveContext ec)
1974 return orig_expr.CreateExpressionTree (ec);
1977 protected override Expression DoResolve (ResolveContext ec)
1982 public override void Emit (EmitContext ec)
1987 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1989 expr.EmitBranchable (ec, target, on_true);
1992 public override SLE.Expression MakeExpression (BuilderContext ctx)
1994 return orig_expr.MakeExpression (ctx);
1999 // Standard composite pattern
2001 public abstract class CompositeExpression : Expression
2003 protected Expression expr;
2005 protected CompositeExpression (Expression expr)
2008 this.loc = expr.Location;
2011 public override bool ContainsEmitWithAwait ()
2013 return expr.ContainsEmitWithAwait ();
2016 public override Expression CreateExpressionTree (ResolveContext rc)
2018 return expr.CreateExpressionTree (rc);
2021 public Expression Child {
2022 get { return expr; }
2025 protected override Expression DoResolve (ResolveContext rc)
2027 expr = expr.Resolve (rc);
2030 eclass = expr.eclass;
2036 public override void Emit (EmitContext ec)
2041 public override bool IsNull {
2042 get { return expr.IsNull; }
2047 // Base of expressions used only to narrow resolve flow
2049 public abstract class ShimExpression : Expression
2051 protected Expression expr;
2053 protected ShimExpression (Expression expr)
2058 public Expression Expr {
2064 protected override void CloneTo (CloneContext clonectx, Expression t)
2069 ShimExpression target = (ShimExpression) t;
2070 target.expr = expr.Clone (clonectx);
2073 public override bool ContainsEmitWithAwait ()
2075 return expr.ContainsEmitWithAwait ();
2078 public override Expression CreateExpressionTree (ResolveContext ec)
2080 throw new NotSupportedException ("ET");
2083 public override void Emit (EmitContext ec)
2085 throw new InternalErrorException ("Missing Resolve call");
2091 // Unresolved type name expressions
2093 public abstract class ATypeNameExpression : FullNamedExpression
2096 protected TypeArguments targs;
2098 protected ATypeNameExpression (string name, Location l)
2104 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2111 protected ATypeNameExpression (string name, int arity, Location l)
2112 : this (name, new UnboundTypeArguments (arity), l)
2118 protected int Arity {
2120 return targs == null ? 0 : targs.Count;
2124 public bool HasTypeArguments {
2126 return targs != null && !targs.IsEmpty;
2130 public string Name {
2139 public TypeArguments TypeArguments {
2147 public override bool Equals (object obj)
2149 ATypeNameExpression atne = obj as ATypeNameExpression;
2150 return atne != null && atne.Name == Name &&
2151 (targs == null || targs.Equals (atne.targs));
2154 public override int GetHashCode ()
2156 return Name.GetHashCode ();
2159 // TODO: Move it to MemberCore
2160 public static string GetMemberType (MemberCore mc)
2166 if (mc is FieldBase)
2168 if (mc is MethodCore)
2170 if (mc is EnumMember)
2178 public override string GetSignatureForError ()
2180 if (targs != null) {
2181 return Name + "<" + targs.GetSignatureForError () + ">";
2187 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2191 /// SimpleName expressions are formed of a single word and only happen at the beginning
2192 /// of a dotted-name.
2194 public class SimpleName : ATypeNameExpression
2196 public SimpleName (string name, Location l)
2201 public SimpleName (string name, TypeArguments args, Location l)
2202 : base (name, args, l)
2206 public SimpleName (string name, int arity, Location l)
2207 : base (name, arity, l)
2211 public SimpleName GetMethodGroup ()
2213 return new SimpleName (Name, targs, loc);
2216 protected override Expression DoResolve (ResolveContext ec)
2218 return SimpleNameResolve (ec, null, false);
2221 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2223 return SimpleNameResolve (ec, right_side, false);
2226 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2228 if (ctx.CurrentType != null) {
2229 if (ctx.CurrentMemberDefinition != null) {
2230 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2232 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2238 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2239 if (retval != null) {
2240 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2241 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2245 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2246 if (retval != null) {
2247 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2251 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2254 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2256 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2259 if (fne.Type != null && Arity > 0) {
2260 if (HasTypeArguments) {
2261 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2262 if (ct.ResolveAsType (ec) == null)
2268 return new GenericOpenTypeExpr (fne.Type, loc);
2272 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2274 if (!(fne is Namespace))
2278 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2279 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2280 ec.Module.Compiler.Report.Error (1980, Location,
2281 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2282 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2285 fne = new DynamicTypeExpr (loc);
2286 fne.ResolveAsType (ec);
2292 Error_TypeOrNamespaceNotFound (ec);
2296 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2298 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2301 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2303 int lookup_arity = Arity;
2304 bool errorMode = false;
2306 Block current_block = rc.CurrentBlock;
2307 INamedBlockVariable variable = null;
2308 bool variable_found = false;
2312 // Stage 1: binding to local variables or parameters
2314 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2316 if (current_block != null && lookup_arity == 0) {
2317 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2318 if (!variable.IsDeclared) {
2319 // We found local name in accessible block but it's not
2320 // initialized yet, maybe the user wanted to bind to something else
2322 variable_found = true;
2324 e = variable.CreateReferenceExpression (rc, loc);
2327 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2336 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2338 TypeSpec member_type = rc.CurrentType;
2339 for (; member_type != null; member_type = member_type.DeclaringType) {
2340 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2344 var me = e as MemberExpr;
2346 // The name matches a type, defer to ResolveAsTypeStep
2354 if (variable != null) {
2355 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2356 rc.Report.Error (844, loc,
2357 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2358 Name, me.GetSignatureForError ());
2362 } else if (me is MethodGroupExpr) {
2363 // Leave it to overload resolution to report correct error
2365 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2366 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2369 // LAMESPEC: again, ignores InvocableOnly
2370 if (variable != null) {
2371 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2372 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2376 // MemberLookup does not check accessors availability, this is actually needed for properties only
2378 var pe = me as PropertyExpr;
2381 // Break as there is no other overload available anyway
2382 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2383 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2386 pe.Getter = pe.PropertyInfo.Get;
2388 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2391 pe.Setter = pe.PropertyInfo.Set;
2396 // TODO: It's used by EventExpr -> FieldExpr transformation only
2397 // TODO: Should go to MemberAccess
2398 me = me.ResolveMemberAccess (rc, null, null);
2402 me.SetTypeArguments (rc, targs);
2409 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2411 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2412 if (IsPossibleTypeOrNamespace (rc)) {
2413 if (variable != null) {
2414 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2415 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2418 return ResolveAsTypeOrNamespace (rc);
2423 if (variable_found) {
2424 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2427 TypeParameter[] tparams = rc.CurrentTypeParameters;
2428 if (tparams != null) {
2429 foreach (var ctp in tparams) {
2430 if (ctp.Name == Name) {
2431 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2437 var ct = rc.CurrentType;
2439 if (ct.MemberDefinition.TypeParametersCount > 0) {
2440 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2441 if (ctp.Name == Name) {
2442 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2448 ct = ct.DeclaringType;
2449 } while (ct != null);
2452 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2453 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2455 rc.Report.SymbolRelatedToPreviousError (e.Type);
2456 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2461 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2463 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2464 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2469 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2472 return ErrorExpression.Instance;
2475 if (rc.Module.Evaluator != null) {
2476 var fi = rc.Module.Evaluator.LookupField (Name);
2478 return new FieldExpr (fi.Item1, loc);
2486 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2488 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2493 if (right_side != null) {
2494 if (e is TypeExpr) {
2495 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2499 e = e.ResolveLValue (ec, right_side);
2504 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2510 /// Represents a namespace or a type. The name of the class was inspired by
2511 /// section 10.8.1 (Fully Qualified Names).
2513 public abstract class FullNamedExpression : Expression
2515 protected override void CloneTo (CloneContext clonectx, Expression target)
2517 // Do nothing, most unresolved type expressions cannot be
2518 // resolved to different type
2521 public override bool ContainsEmitWithAwait ()
2526 public override Expression CreateExpressionTree (ResolveContext ec)
2528 throw new NotSupportedException ("ET");
2531 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2534 // This is used to resolve the expression as a type, a null
2535 // value will be returned if the expression is not a type
2538 public override TypeSpec ResolveAsType (IMemberContext mc)
2540 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2545 TypeExpr te = fne as TypeExpr;
2547 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2555 var dep = type.GetMissingDependencies ();
2557 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2561 // Obsolete checks cannot be done when resolving base context as they
2562 // require type dependencies to be set but we are in process of resolving them
2564 if (!(mc is TypeContainer.BaseContext)) {
2565 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2566 if (obsolete_attr != null && !mc.IsObsolete) {
2567 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2575 public override void Emit (EmitContext ec)
2577 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2578 GetSignatureForError ());
2583 /// Expression that evaluates to a type
2585 public abstract class TypeExpr : FullNamedExpression
2587 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2593 protected sealed override Expression DoResolve (ResolveContext ec)
2599 public override bool Equals (object obj)
2601 TypeExpr tobj = obj as TypeExpr;
2605 return Type == tobj.Type;
2608 public override int GetHashCode ()
2610 return Type.GetHashCode ();
2615 /// Fully resolved Expression that already evaluated to a type
2617 public class TypeExpression : TypeExpr
2619 public TypeExpression (TypeSpec t, Location l)
2622 eclass = ExprClass.Type;
2626 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2633 /// This class denotes an expression which evaluates to a member
2634 /// of a struct or a class.
2636 public abstract class MemberExpr : Expression
2639 // An instance expression associated with this member, if it's a
2640 // non-static member
2642 public Expression InstanceExpression;
2645 /// The name of this member.
2647 public abstract string Name {
2652 // When base.member is used
2654 public bool IsBase {
2655 get { return InstanceExpression is BaseThis; }
2659 /// Whether this is an instance member.
2661 public abstract bool IsInstance {
2666 /// Whether this is a static member.
2668 public abstract bool IsStatic {
2672 protected abstract TypeSpec DeclaringType {
2677 // Converts best base candidate for virtual method starting from QueriedBaseType
2679 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2682 // Only when base.member is used and method is virtual
2688 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2689 // means for base.member access we have to find the closest match after we found best candidate
2691 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2693 // The method could already be what we are looking for
2695 TypeSpec[] targs = null;
2696 if (method.DeclaringType != InstanceExpression.Type) {
2697 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2698 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2699 if (base_override.IsGeneric)
2700 targs = method.TypeArguments;
2702 method = base_override;
2706 // TODO: For now we do it for any hoisted call even if it's needed for
2707 // hoisted stories only but that requires a new expression wrapper
2708 if (rc.CurrentAnonymousMethod != null) {
2709 if (targs == null && method.IsGeneric) {
2710 targs = method.TypeArguments;
2711 method = method.GetGenericMethodDefinition ();
2714 if (method.Parameters.HasArglist)
2715 throw new NotImplementedException ("__arglist base call proxy");
2717 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2719 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2720 // get/set member expressions second call would fail to proxy because left expression
2721 // would be of 'this' and not 'base'
2722 if (rc.CurrentType.IsStruct)
2723 InstanceExpression = new This (loc).Resolve (rc);
2727 method = method.MakeGenericMethod (rc, targs);
2731 // Only base will allow this invocation to happen.
2733 if (method.IsAbstract) {
2734 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2740 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2742 if (InstanceExpression == null)
2745 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2746 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2750 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2752 var ct = rc.CurrentType;
2753 if (ct == qualifier)
2756 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2759 qualifier = qualifier.GetDefinition ();
2760 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2761 rc.Report.SymbolRelatedToPreviousError (member);
2762 rc.Report.Error (1540, loc,
2763 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2764 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2768 public override bool ContainsEmitWithAwait ()
2770 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2773 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2776 type = type.GetDefinition ();
2778 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2781 type = type.DeclaringType;
2782 } while (type != null);
2787 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2789 if (InstanceExpression != null) {
2790 InstanceExpression = InstanceExpression.Resolve (rc);
2791 CheckProtectedMemberAccess (rc, member);
2794 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2795 UnsafeError (rc, loc);
2798 var dep = member.GetMissingDependencies ();
2800 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2803 if (!rc.IsObsolete) {
2804 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2806 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2809 if (!(member is FieldSpec))
2810 member.MemberDefinition.SetIsUsed ();
2813 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2815 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2819 // Implements identicial simple name and type-name
2821 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2824 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2827 // 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
2828 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2830 if (left is MemberExpr || left is VariableReference) {
2831 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2832 if (identical_type != null && identical_type.Type == left.Type)
2833 return identical_type;
2839 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2842 if (InstanceExpression != null) {
2843 if (InstanceExpression is TypeExpr) {
2844 var t = InstanceExpression.Type;
2846 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2847 if (oa != null && !rc.IsObsolete) {
2848 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2851 t = t.DeclaringType;
2852 } while (t != null);
2854 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2855 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2856 rc.Report.Error (176, loc,
2857 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2858 GetSignatureForError ());
2862 InstanceExpression = null;
2868 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2869 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2870 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2871 rc.Report.Error (236, loc,
2872 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2873 GetSignatureForError ());
2875 rc.Report.Error (120, loc,
2876 "An object reference is required to access non-static member `{0}'",
2877 GetSignatureForError ());
2882 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2883 rc.Report.Error (38, loc,
2884 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2885 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2888 InstanceExpression = new This (loc);
2889 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2890 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2891 InstanceExpression = InstanceExpression.Resolve (rc);
2894 InstanceExpression = InstanceExpression.Resolve (rc);
2900 var me = InstanceExpression as MemberExpr;
2902 me.ResolveInstanceExpression (rc, rhs);
2904 var fe = me as FieldExpr;
2905 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2906 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2907 rc.Report.Warning (1690, 1, loc,
2908 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2909 me.GetSignatureForError ());
2916 // Run member-access postponed check once we know that
2917 // the expression is not field expression which is the only
2918 // expression which can use uninitialized this
2920 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2921 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2925 // Additional checks for l-value member access
2929 // TODO: It should be recursive but that would break csc compatibility
2931 if (InstanceExpression is UnboxCast) {
2932 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2939 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2941 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2942 ec.Report.Warning (1720, 1, left.Location,
2943 "Expression will always cause a `{0}'", "System.NullReferenceException");
2946 InstanceExpression = left;
2950 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2952 TypeSpec instance_type = InstanceExpression.Type;
2953 if (TypeSpec.IsValueType (instance_type)) {
2954 if (InstanceExpression is IMemoryLocation) {
2955 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2957 LocalTemporary t = new LocalTemporary (instance_type);
2958 InstanceExpression.Emit (ec);
2960 t.AddressOf (ec, AddressOp.Store);
2964 InstanceExpression.Emit (ec);
2966 // Only to make verifier happy
2967 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2968 ec.Emit (OpCodes.Box, instance_type);
2971 if (prepare_for_load)
2972 ec.Emit (OpCodes.Dup);
2975 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2978 public class ExtensionMethodCandidates
2980 NamespaceContainer container;
2982 IList<MethodSpec> methods;
2984 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
2985 : this (methods, nsContainer, null)
2989 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
2991 this.methods = methods;
2992 this.container = nsContainer;
2996 public NamespaceContainer Container {
3002 public bool HasUninspectedMembers { get; set; }
3004 public Namespace Namespace {
3010 public IList<MethodSpec> Methods {
3018 // Represents a group of extension method candidates for whole namespace
3020 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3022 ExtensionMethodCandidates candidates;
3023 public readonly Expression ExtensionExpression;
3025 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3026 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3028 this.candidates = candidates;
3029 this.ExtensionExpression = extensionExpr;
3032 public override bool IsStatic {
3033 get { return true; }
3037 // For extension methodgroup we are not looking for base members but parent
3038 // namespace extension methods
3040 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3042 // TODO: candidates are null only when doing error reporting, that's
3043 // incorrect. We have to discover same extension methods in error mode
3044 if (candidates == null)
3047 int arity = type_arguments == null ? 0 : type_arguments.Count;
3050 // Here we try to resume the search for extension method at the point
3051 // where the last bunch of candidates was found. It's more tricky than
3052 // it seems as we have to check both namespace containers and namespace
3053 // in correct order.
3059 // namespace B.C.D {
3060 // <our first search found candidates in A.B.C.D
3064 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3065 // checked before we hit A.N1 using
3067 if (candidates.Namespace == null) {
3069 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3070 if (methods != null) {
3071 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3072 return methods.Cast<MemberSpec> ().ToList ();
3076 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3077 if (ns_container == null)
3080 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3081 if (candidates == null)
3084 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3087 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3089 // We are already here
3093 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3095 if (arguments == null)
3096 arguments = new Arguments (1);
3098 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3099 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3101 // Store resolved argument and restore original arguments
3103 // Clean-up modified arguments for error reporting
3104 arguments.RemoveAt (0);
3108 var me = ExtensionExpression as MemberExpr;
3110 me.ResolveInstanceExpression (ec, null);
3112 InstanceExpression = null;
3116 #region IErrorHandler Members
3118 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3123 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3125 rc.Report.SymbolRelatedToPreviousError (best);
3126 rc.Report.Error (1928, loc,
3127 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3128 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3131 rc.Report.Error (1929, loc,
3132 "Extension method instance type `{0}' cannot be converted to `{1}'",
3133 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3139 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3144 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3153 /// MethodGroupExpr represents a group of method candidates which
3154 /// can be resolved to the best method overload
3156 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3158 protected IList<MemberSpec> Methods;
3159 MethodSpec best_candidate;
3160 TypeSpec best_candidate_return;
3161 protected TypeArguments type_arguments;
3163 SimpleName simple_name;
3164 protected TypeSpec queried_type;
3166 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3170 this.type = InternalType.MethodGroup;
3172 eclass = ExprClass.MethodGroup;
3173 queried_type = type;
3176 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3177 : this (new MemberSpec[] { m }, type, loc)
3183 public MethodSpec BestCandidate {
3185 return best_candidate;
3189 public TypeSpec BestCandidateReturnType {
3191 return best_candidate_return;
3195 public IList<MemberSpec> Candidates {
3201 protected override TypeSpec DeclaringType {
3203 return queried_type;
3207 public override bool IsInstance {
3209 if (best_candidate != null)
3210 return !best_candidate.IsStatic;
3216 public override bool IsStatic {
3218 if (best_candidate != null)
3219 return best_candidate.IsStatic;
3225 public override string Name {
3227 if (best_candidate != null)
3228 return best_candidate.Name;
3231 return Methods.First ().Name;
3238 // When best candidate is already know this factory can be used
3239 // to avoid expensive overload resolution to be called
3241 // NOTE: InstanceExpression has to be set manually
3243 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3245 return new MethodGroupExpr (best, queriedType, loc) {
3246 best_candidate = best,
3247 best_candidate_return = best.ReturnType
3251 public override string GetSignatureForError ()
3253 if (best_candidate != null)
3254 return best_candidate.GetSignatureForError ();
3256 return Methods.First ().GetSignatureForError ();
3259 public override Expression CreateExpressionTree (ResolveContext ec)
3261 if (best_candidate == null) {
3262 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3266 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3267 ec.Report.Error (765, loc,
3268 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3270 return new TypeOfMethod (best_candidate, loc);
3273 protected override Expression DoResolve (ResolveContext ec)
3275 this.eclass = ExprClass.MethodGroup;
3277 if (InstanceExpression != null) {
3278 InstanceExpression = InstanceExpression.Resolve (ec);
3279 if (InstanceExpression == null)
3286 public override void Emit (EmitContext ec)
3288 throw new NotSupportedException ();
3291 public void EmitCall (EmitContext ec, Arguments arguments)
3293 var call = new CallEmitter ();
3294 call.InstanceExpression = InstanceExpression;
3295 call.Emit (ec, best_candidate, arguments, loc);
3298 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3300 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3301 Name, TypeManager.CSharpName (target));
3304 public static bool IsExtensionMethodArgument (Expression expr)
3307 // LAMESPEC: No details about which expressions are not allowed
3309 return !(expr is TypeExpr) && !(expr is BaseThis);
3313 /// Find the Applicable Function Members (7.4.2.1)
3315 /// me: Method Group expression with the members to select.
3316 /// it might contain constructors or methods (or anything
3317 /// that maps to a method).
3319 /// Arguments: ArrayList containing resolved Argument objects.
3321 /// loc: The location if we want an error to be reported, or a Null
3322 /// location for "probing" purposes.
3324 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3325 /// that is the best match of me on Arguments.
3328 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3330 // TODO: causes issues with probing mode, remove explicit Kind check
3331 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3334 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3335 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3336 r.BaseMembersProvider = this;
3339 if (cerrors != null)
3340 r.CustomErrors = cerrors;
3342 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3343 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3344 if (best_candidate == null)
3345 return r.BestCandidateIsDynamic ? this : null;
3347 // Overload resolver had to create a new method group, all checks bellow have already been executed
3348 if (r.BestCandidateNewMethodGroup != null)
3349 return r.BestCandidateNewMethodGroup;
3351 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3352 if (InstanceExpression != null) {
3353 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3354 InstanceExpression = null;
3356 if (best_candidate.IsStatic && simple_name != null) {
3357 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3360 InstanceExpression.Resolve (ec);
3364 ResolveInstanceExpression (ec, null);
3365 if (InstanceExpression != null)
3366 CheckProtectedMemberAccess (ec, best_candidate);
3369 var base_override = CandidateToBaseOverride (ec, best_candidate);
3370 if (base_override == best_candidate) {
3371 best_candidate_return = r.BestCandidateReturnType;
3373 best_candidate = base_override;
3374 best_candidate_return = best_candidate.ReturnType;
3380 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3382 simple_name = original;
3383 return base.ResolveMemberAccess (ec, left, original);
3386 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3388 type_arguments = ta;
3391 #region IBaseMembersProvider Members
3393 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3395 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3398 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3400 if (queried_type == member.DeclaringType)
3403 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3404 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3408 // Extension methods lookup after ordinary methods candidates failed to apply
3410 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3412 if (InstanceExpression == null)
3415 InstanceExpression = InstanceExpression.Resolve (rc);
3416 if (!IsExtensionMethodArgument (InstanceExpression))
3419 int arity = type_arguments == null ? 0 : type_arguments.Count;
3420 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3421 if (methods == null)
3424 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3425 emg.SetTypeArguments (rc, type_arguments);
3432 public struct OverloadResolver
3435 public enum Restrictions
3439 ProbingOnly = 1 << 1,
3440 CovariantDelegate = 1 << 2,
3441 NoBaseMembers = 1 << 3,
3442 BaseMembersIncluded = 1 << 4
3445 public interface IBaseMembersProvider
3447 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3448 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3449 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3452 public interface IErrorHandler
3454 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3455 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3456 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3457 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3460 sealed class NoBaseMembers : IBaseMembersProvider
3462 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3464 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3469 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3474 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3480 struct AmbiguousCandidate
3482 public readonly MemberSpec Member;
3483 public readonly bool Expanded;
3484 public readonly AParametersCollection Parameters;
3486 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3489 Parameters = parameters;
3490 Expanded = expanded;
3495 IList<MemberSpec> members;
3496 TypeArguments type_arguments;
3497 IBaseMembersProvider base_provider;
3498 IErrorHandler custom_errors;
3499 Restrictions restrictions;
3500 MethodGroupExpr best_candidate_extension_group;
3501 TypeSpec best_candidate_return_type;
3503 SessionReportPrinter lambda_conv_msgs;
3504 ReportPrinter prev_recorder;
3506 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3507 : this (members, null, restrictions, loc)
3511 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3514 if (members == null || members.Count == 0)
3515 throw new ArgumentException ("empty members set");
3517 this.members = members;
3519 type_arguments = targs;
3520 this.restrictions = restrictions;
3521 if (IsDelegateInvoke)
3522 this.restrictions |= Restrictions.NoBaseMembers;
3524 base_provider = NoBaseMembers.Instance;
3529 public IBaseMembersProvider BaseMembersProvider {
3531 return base_provider;
3534 base_provider = value;
3538 public bool BestCandidateIsDynamic { get; set; }
3541 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3543 public MethodGroupExpr BestCandidateNewMethodGroup {
3545 return best_candidate_extension_group;
3550 // Return type can be different between best candidate and closest override
3552 public TypeSpec BestCandidateReturnType {
3554 return best_candidate_return_type;
3558 public IErrorHandler CustomErrors {
3560 return custom_errors;
3563 custom_errors = value;
3567 TypeSpec DelegateType {
3569 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3570 throw new InternalErrorException ("Not running in delegate mode", loc);
3572 return members [0].DeclaringType;
3576 bool IsProbingOnly {
3578 return (restrictions & Restrictions.ProbingOnly) != 0;
3582 bool IsDelegateInvoke {
3584 return (restrictions & Restrictions.DelegateInvoke) != 0;
3591 // 7.4.3.3 Better conversion from expression
3592 // Returns : 1 if a->p is better,
3593 // 2 if a->q is better,
3594 // 0 if neither is better
3596 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3598 TypeSpec argument_type = a.Type;
3601 // If argument is an anonymous function
3603 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3605 // p and q are delegate types or expression tree types
3607 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3608 if (q.MemberDefinition != p.MemberDefinition) {
3613 // Uwrap delegate from Expression<T>
3615 q = TypeManager.GetTypeArguments (q)[0];
3616 p = TypeManager.GetTypeArguments (p)[0];
3619 var p_m = Delegate.GetInvokeMethod (p);
3620 var q_m = Delegate.GetInvokeMethod (q);
3623 // With identical parameter lists
3625 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3632 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3634 if (p.Kind == MemberKind.Void) {
3635 return q.Kind != MemberKind.Void ? 2 : 0;
3639 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3641 if (q.Kind == MemberKind.Void) {
3642 return p.Kind != MemberKind.Void ? 1: 0;
3646 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3647 // better conversion is performed between underlying types Y1 and Y2
3649 if (p.IsGenericTask || q.IsGenericTask) {
3650 if (p.IsGenericTask != q.IsGenericTask) {
3654 var async_am = a.Expr as AnonymousMethodExpression;
3655 if (async_am == null || !async_am.IsAsync)
3658 q = q.TypeArguments[0];
3659 p = p.TypeArguments[0];
3663 // The parameters are identicial and return type is not void, use better type conversion
3664 // on return type to determine better one
3667 if (argument_type == p)
3670 if (argument_type == q)
3674 return BetterTypeConversion (ec, p, q);
3678 // 7.4.3.4 Better conversion from type
3680 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3682 if (p == null || q == null)
3683 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3685 switch (p.BuiltinType) {
3686 case BuiltinTypeSpec.Type.Int:
3687 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3690 case BuiltinTypeSpec.Type.Long:
3691 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3694 case BuiltinTypeSpec.Type.SByte:
3695 switch (q.BuiltinType) {
3696 case BuiltinTypeSpec.Type.Byte:
3697 case BuiltinTypeSpec.Type.UShort:
3698 case BuiltinTypeSpec.Type.UInt:
3699 case BuiltinTypeSpec.Type.ULong:
3703 case BuiltinTypeSpec.Type.Short:
3704 switch (q.BuiltinType) {
3705 case BuiltinTypeSpec.Type.UShort:
3706 case BuiltinTypeSpec.Type.UInt:
3707 case BuiltinTypeSpec.Type.ULong:
3711 case BuiltinTypeSpec.Type.Dynamic:
3712 // Dynamic is never better
3716 switch (q.BuiltinType) {
3717 case BuiltinTypeSpec.Type.Int:
3718 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3721 case BuiltinTypeSpec.Type.Long:
3722 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3725 case BuiltinTypeSpec.Type.SByte:
3726 switch (p.BuiltinType) {
3727 case BuiltinTypeSpec.Type.Byte:
3728 case BuiltinTypeSpec.Type.UShort:
3729 case BuiltinTypeSpec.Type.UInt:
3730 case BuiltinTypeSpec.Type.ULong:
3734 case BuiltinTypeSpec.Type.Short:
3735 switch (p.BuiltinType) {
3736 case BuiltinTypeSpec.Type.UShort:
3737 case BuiltinTypeSpec.Type.UInt:
3738 case BuiltinTypeSpec.Type.ULong:
3742 case BuiltinTypeSpec.Type.Dynamic:
3743 // Dynamic is never better
3747 // FIXME: handle lifted operators
3749 // TODO: this is expensive
3750 Expression p_tmp = new EmptyExpression (p);
3751 Expression q_tmp = new EmptyExpression (q);
3753 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3754 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3756 if (p_to_q && !q_to_p)
3759 if (q_to_p && !p_to_q)
3766 /// Determines "Better function" between candidate
3767 /// and the current best match
3770 /// Returns a boolean indicating :
3771 /// false if candidate ain't better
3772 /// true if candidate is better than the current best match
3774 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3775 MemberSpec best, AParametersCollection bparam, bool best_params)
3777 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3778 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3780 bool better_at_least_one = false;
3782 int args_count = args == null ? 0 : args.Count;
3786 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3789 // Default arguments are ignored for better decision
3790 if (a.IsDefaultArgument)
3794 // When comparing named argument the parameter type index has to be looked up
3795 // in original parameter set (override version for virtual members)
3797 NamedArgument na = a as NamedArgument;
3799 int idx = cparam.GetParameterIndexByName (na.Name);
3800 ct = candidate_pd.Types[idx];
3801 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3802 ct = TypeManager.GetElementType (ct);
3804 idx = bparam.GetParameterIndexByName (na.Name);
3805 bt = best_pd.Types[idx];
3806 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3807 bt = TypeManager.GetElementType (bt);
3809 ct = candidate_pd.Types[c_idx];
3810 bt = best_pd.Types[b_idx];
3812 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3813 ct = TypeManager.GetElementType (ct);
3817 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3818 bt = TypeManager.GetElementType (bt);
3823 if (TypeSpecComparer.IsEqual (ct, bt))
3827 int result = BetterExpressionConversion (ec, a, ct, bt);
3829 // for each argument, the conversion to 'ct' should be no worse than
3830 // the conversion to 'bt'.
3834 // for at least one argument, the conversion to 'ct' should be better than
3835 // the conversion to 'bt'.
3837 better_at_least_one = true;
3840 if (better_at_least_one)
3844 // This handles the case
3846 // Add (float f1, float f2, float f3);
3847 // Add (params decimal [] foo);
3849 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3850 // first candidate would've chosen as better.
3852 if (!same && !a.IsDefaultArgument)
3856 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3860 // This handles the following cases:
3862 // Foo (int i) is better than Foo (int i, long l = 0)
3863 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3865 // Prefer non-optional version
3867 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3869 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3870 if (candidate_pd.Count >= best_pd.Count)
3873 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3880 // One is a non-generic method and second is a generic method, then non-generic is better
3882 if (best.IsGeneric != candidate.IsGeneric)
3883 return best.IsGeneric;
3886 // This handles the following cases:
3888 // Trim () is better than Trim (params char[] chars)
3889 // Concat (string s1, string s2, string s3) is better than
3890 // Concat (string s1, params string [] srest)
3891 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3893 // Prefer non-expanded version
3895 if (candidate_params != best_params)
3898 int candidate_param_count = candidate_pd.Count;
3899 int best_param_count = best_pd.Count;
3901 if (candidate_param_count != best_param_count)
3902 // can only happen if (candidate_params && best_params)
3903 return candidate_param_count > best_param_count && best_pd.HasParams;
3906 // Both methods have the same number of parameters, and the parameters have equal types
3907 // Pick the "more specific" signature using rules over original (non-inflated) types
3909 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3910 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3912 bool specific_at_least_once = false;
3913 for (j = 0; j < args_count; ++j) {
3914 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3916 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3917 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3919 ct = candidate_def_pd.Types[j];
3920 bt = best_def_pd.Types[j];
3925 TypeSpec specific = MoreSpecific (ct, bt);
3929 specific_at_least_once = true;
3932 if (specific_at_least_once)
3938 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3940 rc.Report.Error (1729, loc,
3941 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3942 type.GetSignatureForError (), argCount.ToString ());
3946 // Determines if the candidate method is applicable to the given set of arguments
3947 // There could be two different set of parameters for same candidate where one
3948 // is the closest override for default values and named arguments checks and second
3949 // one being the virtual base for the parameter types and modifiers.
3951 // A return value rates candidate method compatibility,
3952 // 0 = the best, int.MaxValue = the worst
3954 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)
3956 // Parameters of most-derived type used mainly for named and optional parameters
3957 var pd = pm.Parameters;
3959 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3960 // params modifier instead of most-derived type
3961 var cpd = ((IParametersMember) candidate).Parameters;
3962 int param_count = pd.Count;
3963 int optional_count = 0;
3965 Arguments orig_args = arguments;
3967 if (arg_count != param_count) {
3968 for (int i = 0; i < pd.Count; ++i) {
3969 if (pd.FixedParameters[i].HasDefaultValue) {
3970 optional_count = pd.Count - i;
3975 if (optional_count != 0) {
3976 // Readjust expected number when params used
3977 if (cpd.HasParams) {
3979 if (arg_count < param_count)
3981 } else if (arg_count > param_count) {
3982 int args_gap = System.Math.Abs (arg_count - param_count);
3983 return int.MaxValue - 10000 + args_gap;
3985 } else if (arg_count != param_count) {
3986 int args_gap = System.Math.Abs (arg_count - param_count);
3988 return int.MaxValue - 10000 + args_gap;
3989 if (arg_count < param_count - 1)
3990 return int.MaxValue - 10000 + args_gap;
3993 // Resize to fit optional arguments
3994 if (optional_count != 0) {
3995 if (arguments == null) {
3996 arguments = new Arguments (optional_count);
3998 // Have to create a new container, so the next run can do same
3999 var resized = new Arguments (param_count);
4000 resized.AddRange (arguments);
4001 arguments = resized;
4004 for (int i = arg_count; i < param_count; ++i)
4005 arguments.Add (null);
4009 if (arg_count > 0) {
4011 // Shuffle named arguments to the right positions if there are any
4013 if (arguments[arg_count - 1] is NamedArgument) {
4014 arg_count = arguments.Count;
4016 for (int i = 0; i < arg_count; ++i) {
4017 bool arg_moved = false;
4019 NamedArgument na = arguments[i] as NamedArgument;
4023 int index = pd.GetParameterIndexByName (na.Name);
4025 // Named parameter not found
4029 // already reordered
4034 if (index >= param_count) {
4035 // When using parameters which should not be available to the user
4036 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4039 arguments.Add (null);
4043 temp = arguments[index];
4045 // The slot has been taken by positional argument
4046 if (temp != null && !(temp is NamedArgument))
4051 arguments = arguments.MarkOrderedArgument (na);
4055 arguments[index] = arguments[i];
4056 arguments[i] = temp;
4063 arg_count = arguments.Count;
4065 } else if (arguments != null) {
4066 arg_count = arguments.Count;
4070 // 1. Handle generic method using type arguments when specified or type inference
4073 var ms = candidate as MethodSpec;
4074 if (ms != null && ms.IsGeneric) {
4075 // Setup constraint checker for probing only
4076 ConstraintChecker cc = new ConstraintChecker (null);
4078 if (type_arguments != null) {
4079 var g_args_count = ms.Arity;
4080 if (g_args_count != type_arguments.Count)
4081 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4083 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4085 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4086 // for now it simplifies things. I should probably add a callback to ResolveContext
4087 if (lambda_conv_msgs == null) {
4088 lambda_conv_msgs = new SessionReportPrinter ();
4089 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4092 var ti = new TypeInference (arguments);
4093 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4094 lambda_conv_msgs.EndSession ();
4097 return ti.InferenceScore - 20000;
4099 if (i_args.Length != 0) {
4100 ms = ms.MakeGenericMethod (ec, i_args);
4103 cc.IgnoreInferredDynamic = true;
4107 // Type arguments constraints have to match for the method to be applicable
4109 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4111 return int.MaxValue - 25000;
4115 // We have a generic return type and at same time the method is override which
4116 // means we have to also inflate override return type in case the candidate is
4117 // best candidate and override return type is different to base return type.
4119 // virtual Foo<T, object> with override Foo<T, dynamic>
4121 if (candidate != pm) {
4122 MethodSpec override_ms = (MethodSpec) pm;
4123 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4124 returnType = inflator.Inflate (returnType);
4126 returnType = ms.ReturnType;
4130 ptypes = ms.Parameters.Types;
4132 if (type_arguments != null)
4133 return int.MaxValue - 15000;
4139 // 2. Each argument has to be implicitly convertible to method parameter
4141 Parameter.Modifier p_mod = 0;
4144 for (int i = 0; i < arg_count; i++) {
4145 Argument a = arguments[i];
4147 if (!pd.FixedParameters[i].HasDefaultValue) {
4148 arguments = orig_args;
4149 return arg_count * 2 + 2;
4153 // Get the default value expression, we can use the same expression
4154 // if the type matches
4156 Expression e = pd.FixedParameters[i].DefaultValue;
4157 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4159 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4161 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4162 e = new MemberAccess (new MemberAccess (new MemberAccess (
4163 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4165 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4171 arguments[i] = new Argument (e, Argument.AType.Default);
4175 if (p_mod != Parameter.Modifier.PARAMS) {
4176 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4178 } else if (!params_expanded_form) {
4179 params_expanded_form = true;
4180 pt = ((ElementTypeSpec) pt).Element;
4186 if (!params_expanded_form) {
4187 if (a.ArgType == Argument.AType.ExtensionType) {
4189 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4191 // LAMESPEC: or implicit type parameter conversion
4194 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4195 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4196 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4201 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4204 dynamicArgument = true;
4209 // It can be applicable in expanded form (when not doing exact match like for delegates)
4211 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4212 if (!params_expanded_form)
4213 pt = ((ElementTypeSpec) pt).Element;
4216 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4219 params_expanded_form = true;
4220 } else if (score < 0) {
4221 params_expanded_form = true;
4222 dynamicArgument = true;
4227 if (params_expanded_form)
4229 return (arg_count - i) * 2 + score;
4234 // When params parameter has no argument it will be provided later if the method is the best candidate
4236 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4237 params_expanded_form = true;
4240 // Restore original arguments for dynamic binder to keep the intention of original source code
4242 if (dynamicArgument)
4243 arguments = orig_args;
4249 // Tests argument compatibility with the parameter
4250 // The possible return values are
4252 // 1 - modifier mismatch
4253 // 2 - type mismatch
4254 // -1 - dynamic binding required
4256 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4259 // Types have to be identical when ref or out modifer
4260 // is used and argument is not of dynamic type
4262 if ((argument.Modifier | param_mod) != 0) {
4263 if (argument.Type != parameter) {
4265 // Do full equality check after quick path
4267 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4269 // Using dynamic for ref/out parameter can still succeed at runtime
4271 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4278 if (argument.Modifier != param_mod) {
4280 // Using dynamic for ref/out parameter can still succeed at runtime
4282 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4289 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4293 // Deploy custom error reporting for lambda methods. When probing lambda methods
4294 // keep all errors reported in separate set and once we are done and no best
4295 // candidate was found, this set is used to report more details about what was wrong
4298 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4299 if (lambda_conv_msgs == null) {
4300 lambda_conv_msgs = new SessionReportPrinter ();
4301 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4306 // Use implicit conversion in all modes to return same candidates when the expression
4307 // is used as argument or delegate conversion
4309 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4310 if (lambda_conv_msgs != null) {
4311 lambda_conv_msgs.EndSession ();
4321 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4323 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4325 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4328 var ac_p = p as ArrayContainer;
4330 var ac_q = ((ArrayContainer) q);
4331 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4332 if (specific == ac_p.Element)
4334 if (specific == ac_q.Element)
4336 } else if (TypeManager.IsGenericType (p)) {
4337 var pargs = TypeManager.GetTypeArguments (p);
4338 var qargs = TypeManager.GetTypeArguments (q);
4340 bool p_specific_at_least_once = false;
4341 bool q_specific_at_least_once = false;
4343 for (int i = 0; i < pargs.Length; i++) {
4344 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4345 if (specific == pargs[i])
4346 p_specific_at_least_once = true;
4347 if (specific == qargs[i])
4348 q_specific_at_least_once = true;
4351 if (p_specific_at_least_once && !q_specific_at_least_once)
4353 if (!p_specific_at_least_once && q_specific_at_least_once)
4361 // Find the best method from candidate list
4363 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4365 List<AmbiguousCandidate> ambiguous_candidates = null;
4367 MemberSpec best_candidate;
4368 Arguments best_candidate_args = null;
4369 bool best_candidate_params = false;
4370 bool best_candidate_dynamic = false;
4371 int best_candidate_rate;
4372 IParametersMember best_parameter_member = null;
4374 int args_count = args != null ? args.Count : 0;
4376 Arguments candidate_args = args;
4377 bool error_mode = false;
4378 MemberSpec invocable_member = null;
4380 // Be careful, cannot return until error reporter is restored
4382 best_candidate = null;
4383 best_candidate_rate = int.MaxValue;
4385 var type_members = members;
4389 for (int i = 0; i < type_members.Count; ++i) {
4390 var member = type_members[i];
4393 // Methods in a base class are not candidates if any method in a derived
4394 // class is applicable
4396 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4400 if (!member.IsAccessible (rc))
4403 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4407 IParametersMember pm = member as IParametersMember;
4410 // Will use it later to report ambiguity between best method and invocable member
4412 if (Invocation.IsMemberInvocable (member))
4413 invocable_member = member;
4419 // Overload resolution is looking for base member but using parameter names
4420 // and default values from the closest member. That means to do expensive lookup
4421 // for the closest override for virtual or abstract members
4423 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4424 var override_params = base_provider.GetOverrideMemberParameters (member);
4425 if (override_params != null)
4426 pm = override_params;
4430 // Check if the member candidate is applicable
4432 bool params_expanded_form = false;
4433 bool dynamic_argument = false;
4434 TypeSpec rt = pm.MemberType;
4435 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4438 // How does it score compare to others
4440 if (candidate_rate < best_candidate_rate) {
4441 best_candidate_rate = candidate_rate;
4442 best_candidate = member;
4443 best_candidate_args = candidate_args;
4444 best_candidate_params = params_expanded_form;
4445 best_candidate_dynamic = dynamic_argument;
4446 best_parameter_member = pm;
4447 best_candidate_return_type = rt;
4448 } else if (candidate_rate == 0) {
4450 // The member look is done per type for most operations but sometimes
4451 // it's not possible like for binary operators overload because they
4452 // are unioned between 2 sides
4454 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4455 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4460 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4462 // We pack all interface members into top level type which makes the overload resolution
4463 // more complicated for interfaces. We compensate it by removing methods with same
4464 // signature when building the cache hence this path should not really be hit often
4467 // interface IA { void Foo (int arg); }
4468 // interface IB : IA { void Foo (params int[] args); }
4470 // IB::Foo is the best overload when calling IB.Foo (1)
4473 if (ambiguous_candidates != null) {
4474 foreach (var amb_cand in ambiguous_candidates) {
4475 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4484 ambiguous_candidates = null;
4487 // Is the new candidate better
4488 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4492 best_candidate = member;
4493 best_candidate_args = candidate_args;
4494 best_candidate_params = params_expanded_form;
4495 best_candidate_dynamic = dynamic_argument;
4496 best_parameter_member = pm;
4497 best_candidate_return_type = rt;
4499 // It's not better but any other found later could be but we are not sure yet
4500 if (ambiguous_candidates == null)
4501 ambiguous_candidates = new List<AmbiguousCandidate> ();
4503 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4507 // Restore expanded arguments
4508 if (candidate_args != args)
4509 candidate_args = args;
4511 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4513 if (prev_recorder != null)
4514 rc.Report.SetPrinter (prev_recorder);
4518 // We've found exact match
4520 if (best_candidate_rate == 0)
4524 // Try extension methods lookup when no ordinary method match was found and provider enables it
4527 var emg = base_provider.LookupExtensionMethod (rc);
4529 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4531 best_candidate_extension_group = emg;
4532 return (T) (MemberSpec) emg.BestCandidate;
4537 // Don't run expensive error reporting mode for probing
4544 lambda_conv_msgs = null;
4549 // No best member match found, report an error
4551 if (best_candidate_rate != 0 || error_mode) {
4552 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4556 if (best_candidate_dynamic) {
4557 if (args[0].ArgType == Argument.AType.ExtensionType) {
4558 rc.Report.Error (1973, loc,
4559 "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",
4560 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4563 BestCandidateIsDynamic = true;
4568 // These flags indicates we are running delegate probing conversion. No need to
4569 // do more expensive checks
4571 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4572 return (T) best_candidate;
4574 if (ambiguous_candidates != null) {
4576 // Now check that there are no ambiguities i.e the selected method
4577 // should be better than all the others
4579 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4580 var candidate = ambiguous_candidates [ix];
4582 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4583 var ambiguous = candidate.Member;
4584 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4585 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4586 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4587 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4588 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4591 return (T) best_candidate;
4596 if (invocable_member != null) {
4597 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4598 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4599 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4600 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4604 // And now check if the arguments are all
4605 // compatible, perform conversions if
4606 // necessary etc. and return if everything is
4609 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4612 if (best_candidate == null)
4616 // Check ObsoleteAttribute on the best method
4618 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4619 if (oa != null && !rc.IsObsolete)
4620 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4622 var dep = best_candidate.GetMissingDependencies ();
4624 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4627 best_candidate.MemberDefinition.SetIsUsed ();
4629 args = best_candidate_args;
4630 return (T) best_candidate;
4633 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4635 return ResolveMember<MethodSpec> (rc, ref args);
4638 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4639 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4641 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4644 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4645 ec.Report.SymbolRelatedToPreviousError (method);
4646 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4647 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4648 TypeManager.CSharpSignature (method));
4651 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4652 TypeManager.CSharpSignature (method));
4653 } else if (IsDelegateInvoke) {
4654 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4655 DelegateType.GetSignatureForError ());
4657 ec.Report.SymbolRelatedToPreviousError (method);
4658 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4659 method.GetSignatureForError ());
4662 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4664 string index = (idx + 1).ToString ();
4665 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4666 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4667 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4668 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4669 index, Parameter.GetModifierSignature (a.Modifier));
4671 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4672 index, Parameter.GetModifierSignature (mod));
4673 } else if (a.Expr != ErrorExpression.Instance) {
4674 string p1 = a.GetSignatureForError ();
4675 string p2 = TypeManager.CSharpName (paramType);
4678 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4679 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4682 ec.Report.Error (1503, loc,
4683 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4688 // We have failed to find exact match so we return error info about the closest match
4690 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4692 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4693 int arg_count = args == null ? 0 : args.Count;
4695 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4696 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4697 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4701 if (lambda_conv_msgs != null) {
4702 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4707 // For candidates which match on parameters count report more details about incorrect arguments
4710 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4711 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4712 // Reject any inaccessible member
4713 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4714 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4715 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4719 var ms = best_candidate as MethodSpec;
4720 if (ms != null && ms.IsGeneric) {
4721 bool constr_ok = true;
4722 if (ms.TypeArguments != null)
4723 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4725 if (ta_count == 0) {
4726 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4730 rc.Report.Error (411, loc,
4731 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4732 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4739 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4745 // We failed to find any method with correct argument count, report best candidate
4747 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4750 if (best_candidate.Kind == MemberKind.Constructor) {
4751 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4752 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4753 } else if (IsDelegateInvoke) {
4754 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4755 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4756 DelegateType.GetSignatureForError (), arg_count.ToString ());
4758 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4759 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4760 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4761 name, arg_count.ToString ());
4765 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4767 var pd = pm.Parameters;
4768 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4770 Parameter.Modifier p_mod = 0;
4772 int a_idx = 0, a_pos = 0;
4774 ArrayInitializer params_initializers = null;
4775 bool has_unsafe_arg = pm.MemberType.IsPointer;
4776 int arg_count = args == null ? 0 : args.Count;
4778 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4780 if (p_mod != Parameter.Modifier.PARAMS) {
4781 p_mod = pd.FixedParameters[a_idx].ModFlags;
4783 has_unsafe_arg |= pt.IsPointer;
4785 if (p_mod == Parameter.Modifier.PARAMS) {
4786 if (chose_params_expanded) {
4787 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4788 pt = TypeManager.GetElementType (pt);
4794 // Types have to be identical when ref or out modifer is used
4796 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4797 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4800 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4806 NamedArgument na = a as NamedArgument;
4808 int name_index = pd.GetParameterIndexByName (na.Name);
4809 if (name_index < 0 || name_index >= pd.Count) {
4810 if (IsDelegateInvoke) {
4811 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4812 ec.Report.Error (1746, na.Location,
4813 "The delegate `{0}' does not contain a parameter named `{1}'",
4814 DelegateType.GetSignatureForError (), na.Name);
4816 ec.Report.SymbolRelatedToPreviousError (member);
4817 ec.Report.Error (1739, na.Location,
4818 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4819 TypeManager.CSharpSignature (member), na.Name);
4821 } else if (args[name_index] != a) {
4822 if (IsDelegateInvoke)
4823 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4825 ec.Report.SymbolRelatedToPreviousError (member);
4827 ec.Report.Error (1744, na.Location,
4828 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4833 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4836 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4837 custom_errors.NoArgumentMatch (ec, member);
4841 Expression conv = null;
4842 if (a.ArgType == Argument.AType.ExtensionType) {
4843 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4846 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4848 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4851 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4858 // Convert params arguments to an array initializer
4860 if (params_initializers != null) {
4861 // we choose to use 'a.Expr' rather than 'conv' so that
4862 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4863 params_initializers.Add (a.Expr);
4864 args.RemoveAt (a_idx--);
4869 // Update the argument with the implicit conversion
4873 if (a_idx != arg_count) {
4874 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4879 // Fill not provided arguments required by params modifier
4881 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4883 args = new Arguments (1);
4885 pt = ptypes[pd.Count - 1];
4886 pt = TypeManager.GetElementType (pt);
4887 has_unsafe_arg |= pt.IsPointer;
4888 params_initializers = new ArrayInitializer (0, loc);
4892 // Append an array argument with all params arguments
4894 if (params_initializers != null) {
4895 args.Add (new Argument (
4896 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4900 if (has_unsafe_arg && !ec.IsUnsafe) {
4901 Expression.UnsafeError (ec, loc);
4905 // We could infer inaccesible type arguments
4907 if (type_arguments == null && member.IsGeneric) {
4908 var ms = (MethodSpec) member;
4909 foreach (var ta in ms.TypeArguments) {
4910 if (!ta.IsAccessible (ec)) {
4911 ec.Report.SymbolRelatedToPreviousError (ta);
4912 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4922 public class ConstantExpr : MemberExpr
4924 readonly ConstSpec constant;
4926 public ConstantExpr (ConstSpec constant, Location loc)
4928 this.constant = constant;
4932 public override string Name {
4933 get { throw new NotImplementedException (); }
4936 public override bool IsInstance {
4937 get { return !IsStatic; }
4940 public override bool IsStatic {
4941 get { return true; }
4944 protected override TypeSpec DeclaringType {
4945 get { return constant.DeclaringType; }
4948 public override Expression CreateExpressionTree (ResolveContext ec)
4950 throw new NotSupportedException ("ET");
4953 protected override Expression DoResolve (ResolveContext rc)
4955 ResolveInstanceExpression (rc, null);
4956 DoBestMemberChecks (rc, constant);
4958 var c = constant.GetConstant (rc);
4960 // Creates reference expression to the constant value
4961 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4964 public override void Emit (EmitContext ec)
4966 throw new NotSupportedException ();
4969 public override string GetSignatureForError ()
4971 return constant.GetSignatureForError ();
4974 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4976 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4981 // Fully resolved expression that references a Field
4983 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
4985 protected FieldSpec spec;
4986 VariableInfo variable_info;
4988 LocalTemporary temp;
4991 protected FieldExpr (Location l)
4996 public FieldExpr (FieldSpec spec, Location loc)
5001 type = spec.MemberType;
5004 public FieldExpr (FieldBase fi, Location l)
5011 public override string Name {
5017 public bool IsHoisted {
5019 IVariableReference hv = InstanceExpression as IVariableReference;
5020 return hv != null && hv.IsHoisted;
5024 public override bool IsInstance {
5026 return !spec.IsStatic;
5030 public override bool IsStatic {
5032 return spec.IsStatic;
5036 public FieldSpec Spec {
5042 protected override TypeSpec DeclaringType {
5044 return spec.DeclaringType;
5048 public VariableInfo VariableInfo {
5050 return variable_info;
5056 public override string GetSignatureForError ()
5058 return TypeManager.GetFullNameSignature (spec);
5061 public bool IsMarshalByRefAccess (ResolveContext rc)
5063 // Checks possible ldflda of field access expression
5064 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5065 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5066 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5069 public void SetHasAddressTaken ()
5071 IVariableReference vr = InstanceExpression as IVariableReference;
5073 vr.SetHasAddressTaken ();
5076 public override Expression CreateExpressionTree (ResolveContext ec)
5078 Expression instance;
5079 if (InstanceExpression == null) {
5080 instance = new NullLiteral (loc);
5082 instance = InstanceExpression.CreateExpressionTree (ec);
5085 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5087 CreateTypeOfExpression ());
5089 return CreateExpressionFactoryCall (ec, "Field", args);
5092 public Expression CreateTypeOfExpression ()
5094 return new TypeOfField (spec, loc);
5097 protected override Expression DoResolve (ResolveContext ec)
5099 return DoResolve (ec, null);
5102 Expression DoResolve (ResolveContext ec, Expression rhs)
5104 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5107 if (ResolveInstanceExpression (ec, rhs)) {
5108 // Resolve the field's instance expression while flow analysis is turned
5109 // off: when accessing a field "a.b", we must check whether the field
5110 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5112 if (lvalue_instance) {
5113 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5114 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5116 Expression right_side =
5117 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5119 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5122 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5123 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5127 if (InstanceExpression == null)
5131 DoBestMemberChecks (ec, spec);
5134 var fb = spec as FixedFieldSpec;
5135 IVariableReference var = InstanceExpression as IVariableReference;
5137 if (lvalue_instance && var != null && var.VariableInfo != null) {
5138 var.VariableInfo.SetFieldAssigned (ec, Name);
5142 IFixedExpression fe = InstanceExpression as IFixedExpression;
5143 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5144 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5147 if (InstanceExpression.eclass != ExprClass.Variable) {
5148 ec.Report.SymbolRelatedToPreviousError (spec);
5149 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5150 TypeManager.GetFullNameSignature (spec));
5151 } else if (var != null && var.IsHoisted) {
5152 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5155 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5158 eclass = ExprClass.Variable;
5160 // If the instance expression is a local variable or parameter.
5161 if (var == null || var.VariableInfo == null)
5164 VariableInfo vi = var.VariableInfo;
5165 if (!vi.IsFieldAssigned (ec, Name, loc))
5168 variable_info = vi.GetSubStruct (Name);
5172 static readonly int [] codes = {
5173 191, // instance, write access
5174 192, // instance, out access
5175 198, // static, write access
5176 199, // static, out access
5177 1648, // member of value instance, write access
5178 1649, // member of value instance, out access
5179 1650, // member of value static, write access
5180 1651 // member of value static, out access
5183 static readonly string [] msgs = {
5184 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5185 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5186 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5187 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5188 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5189 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5190 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5191 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5194 // The return value is always null. Returning a value simplifies calling code.
5195 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5198 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5202 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5204 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5209 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5211 Expression e = DoResolve (ec, right_side);
5216 spec.MemberDefinition.SetIsAssigned ();
5218 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5219 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5220 ec.Report.Warning (420, 1, loc,
5221 "`{0}': A volatile field references will not be treated as volatile",
5222 spec.GetSignatureForError ());
5225 if (spec.IsReadOnly) {
5226 // InitOnly fields can only be assigned in constructors or initializers
5227 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5228 return Report_AssignToReadonly (ec, right_side);
5230 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5232 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5233 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5234 return Report_AssignToReadonly (ec, right_side);
5235 // static InitOnly fields cannot be assigned-to in an instance constructor
5236 if (IsStatic && !ec.IsStatic)
5237 return Report_AssignToReadonly (ec, right_side);
5238 // instance constructors can't modify InitOnly fields of other instances of the same type
5239 if (!IsStatic && !(InstanceExpression is This))
5240 return Report_AssignToReadonly (ec, right_side);
5244 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5245 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5246 ec.Report.Warning (197, 1, loc,
5247 "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",
5248 GetSignatureForError ());
5251 eclass = ExprClass.Variable;
5255 public override int GetHashCode ()
5257 return spec.GetHashCode ();
5260 public bool IsFixed {
5263 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5265 IVariableReference variable = InstanceExpression as IVariableReference;
5266 if (variable != null)
5267 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5269 IFixedExpression fe = InstanceExpression as IFixedExpression;
5270 return fe != null && fe.IsFixed;
5274 public override bool Equals (object obj)
5276 FieldExpr fe = obj as FieldExpr;
5280 if (spec != fe.spec)
5283 if (InstanceExpression == null || fe.InstanceExpression == null)
5286 return InstanceExpression.Equals (fe.InstanceExpression);
5289 public void Emit (EmitContext ec, bool leave_copy)
5291 bool is_volatile = false;
5293 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5296 spec.MemberDefinition.SetIsUsed ();
5300 ec.Emit (OpCodes.Volatile);
5302 ec.Emit (OpCodes.Ldsfld, spec);
5305 EmitInstance (ec, false);
5307 // Optimization for build-in types
5308 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5309 ec.EmitLoadFromPtr (type);
5311 var ff = spec as FixedFieldSpec;
5313 ec.Emit (OpCodes.Ldflda, spec);
5314 ec.Emit (OpCodes.Ldflda, ff.Element);
5317 ec.Emit (OpCodes.Volatile);
5319 ec.Emit (OpCodes.Ldfld, spec);
5325 ec.Emit (OpCodes.Dup);
5327 temp = new LocalTemporary (this.Type);
5333 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5335 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5336 if (isCompound && !(source is DynamicExpressionStatement)) {
5337 if (has_await_source) {
5339 InstanceExpression = InstanceExpression.EmitToField (ec);
5346 if (has_await_source)
5347 source = source.EmitToField (ec);
5349 EmitInstance (ec, prepared);
5355 ec.Emit (OpCodes.Dup);
5357 temp = new LocalTemporary (this.Type);
5362 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5363 ec.Emit (OpCodes.Volatile);
5365 spec.MemberDefinition.SetIsAssigned ();
5368 ec.Emit (OpCodes.Stsfld, spec);
5370 ec.Emit (OpCodes.Stfld, spec);
5380 // Emits store to field with prepared values on stack
5382 public void EmitAssignFromStack (EmitContext ec)
5385 ec.Emit (OpCodes.Stsfld, spec);
5387 ec.Emit (OpCodes.Stfld, spec);
5391 public override void Emit (EmitContext ec)
5396 public override void EmitSideEffect (EmitContext ec)
5398 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5400 if (is_volatile) // || is_marshal_by_ref ())
5401 base.EmitSideEffect (ec);
5404 public void AddressOf (EmitContext ec, AddressOp mode)
5406 if ((mode & AddressOp.Store) != 0)
5407 spec.MemberDefinition.SetIsAssigned ();
5408 if ((mode & AddressOp.Load) != 0)
5409 spec.MemberDefinition.SetIsUsed ();
5412 // Handle initonly fields specially: make a copy and then
5413 // get the address of the copy.
5416 if (spec.IsReadOnly){
5418 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5430 var temp = ec.GetTemporaryLocal (type);
5431 ec.Emit (OpCodes.Stloc, temp);
5432 ec.Emit (OpCodes.Ldloca, temp);
5433 ec.FreeTemporaryLocal (temp, type);
5439 ec.Emit (OpCodes.Ldsflda, spec);
5442 EmitInstance (ec, false);
5443 ec.Emit (OpCodes.Ldflda, spec);
5447 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5449 return MakeExpression (ctx);
5452 public override SLE.Expression MakeExpression (BuilderContext ctx)
5455 return base.MakeExpression (ctx);
5457 return SLE.Expression.Field (
5458 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5459 spec.GetMetaInfo ());
5463 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5465 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5471 // Expression that evaluates to a Property.
5473 // This is not an LValue because we need to re-write the expression. We
5474 // can not take data from the stack and store it.
5476 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5478 public PropertyExpr (PropertySpec spec, Location l)
5481 best_candidate = spec;
5482 type = spec.MemberType;
5487 protected override Arguments Arguments {
5495 protected override TypeSpec DeclaringType {
5497 return best_candidate.DeclaringType;
5501 public override string Name {
5503 return best_candidate.Name;
5507 public override bool IsInstance {
5513 public override bool IsStatic {
5515 return best_candidate.IsStatic;
5519 public PropertySpec PropertyInfo {
5521 return best_candidate;
5527 public override Expression CreateExpressionTree (ResolveContext ec)
5530 if (IsSingleDimensionalArrayLength ()) {
5531 args = new Arguments (1);
5532 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5533 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5536 args = new Arguments (2);
5537 if (InstanceExpression == null)
5538 args.Add (new Argument (new NullLiteral (loc)));
5540 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5541 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5542 return CreateExpressionFactoryCall (ec, "Property", args);
5545 public Expression CreateSetterTypeOfExpression ()
5547 return new TypeOfMethod (Setter, loc);
5550 public override string GetSignatureForError ()
5552 return best_candidate.GetSignatureForError ();
5555 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5558 return base.MakeExpression (ctx);
5560 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5564 public override SLE.Expression MakeExpression (BuilderContext ctx)
5567 return base.MakeExpression (ctx);
5569 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5573 void Error_PropertyNotValid (ResolveContext ec)
5575 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5576 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5577 GetSignatureForError ());
5580 bool IsSingleDimensionalArrayLength ()
5582 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5585 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5586 return ac != null && ac.Rank == 1;
5589 public override void Emit (EmitContext ec, bool leave_copy)
5592 // Special case: length of single dimension array property is turned into ldlen
5594 if (IsSingleDimensionalArrayLength ()) {
5595 EmitInstance (ec, false);
5596 ec.Emit (OpCodes.Ldlen);
5597 ec.Emit (OpCodes.Conv_I4);
5601 base.Emit (ec, leave_copy);
5604 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5607 LocalTemporary await_source_arg = null;
5609 if (isCompound && !(source is DynamicExpressionStatement)) {
5610 emitting_compound_assignment = true;
5613 if (has_await_arguments) {
5614 await_source_arg = new LocalTemporary (Type);
5615 await_source_arg.Store (ec);
5617 args = new Arguments (1);
5618 args.Add (new Argument (await_source_arg));
5621 temp = await_source_arg;
5624 has_await_arguments = false;
5629 ec.Emit (OpCodes.Dup);
5630 temp = new LocalTemporary (this.Type);
5635 args = new Arguments (1);
5639 temp = new LocalTemporary (this.Type);
5641 args.Add (new Argument (temp));
5643 args.Add (new Argument (source));
5647 emitting_compound_assignment = false;
5649 var call = new CallEmitter ();
5650 call.InstanceExpression = InstanceExpression;
5652 call.InstanceExpressionOnStack = true;
5654 call.Emit (ec, Setter, args, loc);
5661 if (await_source_arg != null) {
5662 await_source_arg.Release (ec);
5666 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5668 eclass = ExprClass.PropertyAccess;
5670 if (best_candidate.IsNotCSharpCompatible) {
5671 Error_PropertyNotValid (rc);
5674 ResolveInstanceExpression (rc, right_side);
5676 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5677 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5678 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5680 type = p.MemberType;
5684 DoBestMemberChecks (rc, best_candidate);
5688 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5690 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5694 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5696 // getter and setter can be different for base calls
5697 MethodSpec getter, setter;
5698 protected T best_candidate;
5700 protected LocalTemporary temp;
5701 protected bool emitting_compound_assignment;
5702 protected bool has_await_arguments;
5704 protected PropertyOrIndexerExpr (Location l)
5711 protected abstract Arguments Arguments { get; set; }
5713 public MethodSpec Getter {
5722 public MethodSpec Setter {
5733 protected override Expression DoResolve (ResolveContext ec)
5735 if (eclass == ExprClass.Unresolved) {
5736 var expr = OverloadResolve (ec, null);
5741 return expr.Resolve (ec);
5744 if (!ResolveGetter (ec))
5750 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5752 if (right_side == EmptyExpression.OutAccess) {
5753 // TODO: best_candidate can be null at this point
5754 INamedBlockVariable variable = null;
5755 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5756 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5757 best_candidate.Name);
5759 right_side.DoResolveLValue (ec, this);
5764 // if the property/indexer returns a value type, and we try to set a field in it
5765 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5766 Error_CannotModifyIntermediateExpressionValue (ec);
5769 if (eclass == ExprClass.Unresolved) {
5770 var expr = OverloadResolve (ec, right_side);
5775 return expr.ResolveLValue (ec, right_side);
5778 if (!ResolveSetter (ec))
5785 // Implements the IAssignMethod interface for assignments
5787 public virtual void Emit (EmitContext ec, bool leave_copy)
5789 var call = new CallEmitter ();
5790 call.InstanceExpression = InstanceExpression;
5791 if (has_await_arguments)
5792 call.HasAwaitArguments = true;
5794 call.DuplicateArguments = emitting_compound_assignment;
5796 call.Emit (ec, Getter, Arguments, loc);
5798 if (call.HasAwaitArguments) {
5799 InstanceExpression = call.InstanceExpression;
5800 Arguments = call.EmittedArguments;
5801 has_await_arguments = true;
5805 ec.Emit (OpCodes.Dup);
5806 temp = new LocalTemporary (Type);
5811 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5813 public override void Emit (EmitContext ec)
5818 protected override void EmitToFieldSource (EmitContext ec)
5820 has_await_arguments = true;
5824 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5826 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5828 bool ResolveGetter (ResolveContext rc)
5830 if (!best_candidate.HasGet) {
5831 if (InstanceExpression != EmptyExpression.Null) {
5832 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5833 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5834 best_candidate.GetSignatureForError ());
5837 } else if (!best_candidate.Get.IsAccessible (rc)) {
5838 if (best_candidate.HasDifferentAccessibility) {
5839 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5840 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5841 TypeManager.CSharpSignature (best_candidate));
5843 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5844 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5848 if (best_candidate.HasDifferentAccessibility) {
5849 CheckProtectedMemberAccess (rc, best_candidate.Get);
5852 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5856 bool ResolveSetter (ResolveContext rc)
5858 if (!best_candidate.HasSet) {
5859 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5860 GetSignatureForError ());
5864 if (!best_candidate.Set.IsAccessible (rc)) {
5865 if (best_candidate.HasDifferentAccessibility) {
5866 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5867 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5868 GetSignatureForError ());
5870 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5871 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5875 if (best_candidate.HasDifferentAccessibility)
5876 CheckProtectedMemberAccess (rc, best_candidate.Set);
5878 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5884 /// Fully resolved expression that evaluates to an Event
5886 public class EventExpr : MemberExpr, IAssignMethod
5888 readonly EventSpec spec;
5891 public EventExpr (EventSpec spec, Location loc)
5899 protected override TypeSpec DeclaringType {
5901 return spec.DeclaringType;
5905 public override string Name {
5911 public override bool IsInstance {
5913 return !spec.IsStatic;
5917 public override bool IsStatic {
5919 return spec.IsStatic;
5923 public MethodSpec Operator {
5931 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5934 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5936 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5937 if (spec.BackingField != null &&
5938 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5940 spec.MemberDefinition.SetIsUsed ();
5942 if (!ec.IsObsolete) {
5943 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5945 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5948 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5949 Error_AssignmentEventOnly (ec);
5951 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5953 InstanceExpression = null;
5955 return ml.ResolveMemberAccess (ec, left, original);
5959 return base.ResolveMemberAccess (ec, left, original);
5962 public override Expression CreateExpressionTree (ResolveContext ec)
5964 throw new NotSupportedException ("ET");
5967 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5969 if (right_side == EmptyExpression.EventAddition) {
5970 op = spec.AccessorAdd;
5971 } else if (right_side == EmptyExpression.EventSubtraction) {
5972 op = spec.AccessorRemove;
5976 Error_AssignmentEventOnly (ec);
5980 op = CandidateToBaseOverride (ec, op);
5984 protected override Expression DoResolve (ResolveContext ec)
5986 eclass = ExprClass.EventAccess;
5987 type = spec.MemberType;
5989 ResolveInstanceExpression (ec, null);
5991 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5992 Error_AssignmentEventOnly (ec);
5995 DoBestMemberChecks (ec, spec);
5999 public override void Emit (EmitContext ec)
6001 throw new NotSupportedException ();
6002 //Error_CannotAssign ();
6005 #region IAssignMethod Members
6007 public void Emit (EmitContext ec, bool leave_copy)
6009 throw new NotImplementedException ();
6012 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6014 if (leave_copy || !isCompound)
6015 throw new NotImplementedException ("EventExpr::EmitAssign");
6017 Arguments args = new Arguments (1);
6018 args.Add (new Argument (source));
6020 var call = new CallEmitter ();
6021 call.InstanceExpression = InstanceExpression;
6022 call.Emit (ec, op, args, loc);
6027 void Error_AssignmentEventOnly (ResolveContext ec)
6029 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6030 ec.Report.Error (79, loc,
6031 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6032 GetSignatureForError ());
6034 ec.Report.Error (70, loc,
6035 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6036 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6040 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6042 name = name.Substring (0, name.LastIndexOf ('.'));
6043 base.Error_CannotCallAbstractBase (rc, name);
6046 public override string GetSignatureForError ()
6048 return TypeManager.CSharpSignature (spec);
6051 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6053 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6057 public class TemporaryVariableReference : VariableReference
6059 public class Declarator : Statement
6061 TemporaryVariableReference variable;
6063 public Declarator (TemporaryVariableReference variable)
6065 this.variable = variable;
6069 protected override void DoEmit (EmitContext ec)
6071 variable.li.CreateBuilder (ec);
6074 protected override void CloneTo (CloneContext clonectx, Statement target)
6082 public TemporaryVariableReference (LocalVariable li, Location loc)
6085 this.type = li.Type;
6089 public override bool IsLockedByStatement {
6097 public LocalVariable LocalInfo {
6103 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6105 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6106 return new TemporaryVariableReference (li, loc);
6109 public override Expression CreateExpressionTree (ResolveContext ec)
6111 throw new NotSupportedException ("ET");
6114 protected override Expression DoResolve (ResolveContext ec)
6116 eclass = ExprClass.Variable;
6119 // Don't capture temporary variables except when using
6120 // iterator redirection
6122 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6123 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6124 storey.CaptureLocalVariable (ec, li);
6130 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6132 return Resolve (ec);
6135 public override void Emit (EmitContext ec)
6137 li.CreateBuilder (ec);
6142 public void EmitAssign (EmitContext ec, Expression source)
6144 li.CreateBuilder (ec);
6146 EmitAssign (ec, source, false, false);
6149 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6151 return li.HoistedVariant;
6154 public override bool IsFixed {
6155 get { return true; }
6158 public override bool IsRef {
6159 get { return false; }
6162 public override string Name {
6163 get { throw new NotImplementedException (); }
6166 public override void SetHasAddressTaken ()
6168 throw new NotImplementedException ();
6171 protected override ILocalVariable Variable {
6175 public override VariableInfo VariableInfo {
6176 get { throw new NotImplementedException (); }
6181 /// Handles `var' contextual keyword; var becomes a keyword only
6182 /// if no type called var exists in a variable scope
6184 class VarExpr : SimpleName
6186 public VarExpr (Location loc)
6191 public bool InferType (ResolveContext ec, Expression right_side)
6194 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6196 type = right_side.Type;
6197 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6198 ec.Report.Error (815, loc,
6199 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6200 type.GetSignatureForError ());
6204 eclass = ExprClass.Variable;
6208 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6210 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6211 base.Error_TypeOrNamespaceNotFound (ec);
6213 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");