2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// The ExprClass class contains the is used to pass the
31 /// classification of an expression (value, variable, namespace,
32 /// type, method group, property access, event access, indexer access,
35 public enum ExprClass : byte {
51 /// This is used to tell Resolve in which types of expressions we're
55 public enum ResolveFlags {
56 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
59 // Returns a type expression.
62 // Returns a method group.
65 TypeParameter = 1 << 3,
67 // Mask of all the expression class flags.
68 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 // An expressions resolved as a direct variable reference
102 public interface IVariableReference : IFixedExpression
104 bool IsHoisted { get; }
106 VariableInfo VariableInfo { get; }
108 void SetHasAddressTaken ();
112 // Implemented by an expression which could be or is always
115 public interface IFixedExpression
117 bool IsFixed { get; }
121 /// Base class for expressions
123 public abstract class Expression {
124 public ExprClass eclass;
125 protected TypeSpec type;
126 protected Location loc;
128 public TypeSpec Type {
130 set { type = value; }
133 public virtual bool IsSideEffectFree {
139 public Location Location {
143 public virtual bool IsNull {
150 // Returns true when the expression during Emit phase breaks stack
151 // by using await expression
153 public virtual bool ContainsEmitWithAwait ()
159 /// Performs semantic analysis on the Expression
163 /// The Resolve method is invoked to perform the semantic analysis
166 /// The return value is an expression (it can be the
167 /// same expression in some cases) or a new
168 /// expression that better represents this node.
170 /// For example, optimizations of Unary (LiteralInt)
171 /// would return a new LiteralInt with a negated
174 /// If there is an error during semantic analysis,
175 /// then an error should be reported (using Report)
176 /// and a null value should be returned.
178 /// There are two side effects expected from calling
179 /// Resolve(): the the field variable "eclass" should
180 /// be set to any value of the enumeration
181 /// `ExprClass' and the type variable should be set
182 /// to a valid type (this is the type of the
185 protected abstract Expression DoResolve (ResolveContext rc);
187 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
193 // This is used if the expression should be resolved as a type or namespace name.
194 // the default implementation fails.
196 public virtual TypeSpec ResolveAsType (IMemberContext mc)
198 ResolveContext ec = new ResolveContext (mc);
199 Expression e = Resolve (ec);
201 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
206 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
208 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
211 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
213 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
216 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
218 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
219 name, TypeManager.CSharpName (type));
222 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
224 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
225 "expressions can be used as a statement");
228 public void Error_InvalidExpressionStatement (BlockContext ec)
230 Error_InvalidExpressionStatement (ec.Report, loc);
233 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
235 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
238 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
240 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
243 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
245 // The error was already reported as CS1660
246 if (type == InternalType.AnonymousMethod)
249 string from_type = type.GetSignatureForError ();
250 string to_type = target.GetSignatureForError ();
251 if (from_type == to_type) {
252 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
253 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
257 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
262 ec.Report.DisableReporting ();
263 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
264 ec.Report.EnableReporting ();
267 ec.Report.Error (266, loc,
268 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
271 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
276 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
278 // Better message for possible generic expressions
279 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
280 var report = context.Module.Compiler.Report;
281 report.SymbolRelatedToPreviousError (member);
282 if (member is TypeSpec)
283 member = ((TypeSpec) member).GetDefinition ();
285 member = ((MethodSpec) member).GetGenericMethodDefinition ();
287 string name = member.Kind == MemberKind.Method ? "method" : "type";
288 if (member.IsGeneric) {
289 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
290 name, member.GetSignatureForError (), member.Arity.ToString ());
292 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
293 name, member.GetSignatureForError ());
296 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
300 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
302 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
306 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
308 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
311 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
313 ec.Report.SymbolRelatedToPreviousError (type);
314 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
315 TypeManager.CSharpName (type), name);
318 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
320 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
323 protected void Error_VoidPointerOperation (ResolveContext rc)
325 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
328 public ResolveFlags ExprClassToResolveFlags {
332 case ExprClass.Namespace:
333 return ResolveFlags.Type;
335 case ExprClass.MethodGroup:
336 return ResolveFlags.MethodGroup;
338 case ExprClass.TypeParameter:
339 return ResolveFlags.TypeParameter;
341 case ExprClass.Value:
342 case ExprClass.Variable:
343 case ExprClass.PropertyAccess:
344 case ExprClass.EventAccess:
345 case ExprClass.IndexerAccess:
346 return ResolveFlags.VariableOrValue;
349 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
354 public virtual string GetSignatureForError ()
356 return type.GetDefinition ().GetSignatureForError ();
360 /// Resolves an expression and performs semantic analysis on it.
364 /// Currently Resolve wraps DoResolve to perform sanity
365 /// checking and assertion checking on what we expect from Resolve.
367 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
369 if (eclass != ExprClass.Unresolved)
379 if ((flags & e.ExprClassToResolveFlags) == 0) {
380 e.Error_UnexpectedKind (ec, flags, loc);
385 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
388 } catch (Exception ex) {
389 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
392 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
393 return EmptyExpression.Null; // TODO: Add location
398 /// Resolves an expression and performs semantic analysis on it.
400 public Expression Resolve (ResolveContext rc)
402 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
406 /// Resolves an expression for LValue assignment
410 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
411 /// checking and assertion checking on what we expect from Resolve
413 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
415 int errors = ec.Report.Errors;
416 bool out_access = right_side == EmptyExpression.OutAccess;
418 Expression e = DoResolveLValue (ec, right_side);
420 if (e != null && out_access && !(e is IMemoryLocation)) {
421 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
422 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
424 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
425 // e.GetType () + " " + e.GetSignatureForError ());
430 if (errors == ec.Report.Errors) {
432 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
434 Error_ValueAssignment (ec, loc);
439 if (e.eclass == ExprClass.Unresolved)
440 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
442 if ((e.type == null) && !(e is GenericTypeExpr))
443 throw new Exception ("Expression " + e + " did not set its type after Resolve");
448 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
450 rc.Module.Compiler.Report.Error (182, loc,
451 "An attribute argument must be a constant expression, typeof expression or array creation expression");
455 /// Emits the code for the expression
459 /// The Emit method is invoked to generate the code
460 /// for the expression.
462 public abstract void Emit (EmitContext ec);
465 // Emit code to branch to @target if this expression is equivalent to @on_true.
466 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
467 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
468 // including the use of conditional branches. Note also that a branch MUST be emitted
469 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
472 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
475 // Emit this expression for its side effects, not for its value.
476 // The default implementation is to emit the value, and then throw it away.
477 // Subclasses can provide more efficient implementations, but those MUST be equivalent
478 public virtual void EmitSideEffect (EmitContext ec)
481 ec.Emit (OpCodes.Pop);
485 // Emits the expression into temporary field variable. The method
486 // should be used for await expressions only
488 public virtual Expression EmitToField (EmitContext ec)
491 // This is the await prepare Emit method. When emitting code like
492 // a + b we emit code like
498 // For await a + await b we have to interfere the flow to keep the
499 // stack clean because await yields from the expression. The emit
502 // a = a.EmitToField () // a is changed to temporary field access
503 // b = b.EmitToField ()
509 // The idea is to emit expression and leave the stack empty with
510 // result value still available.
512 // Expressions should override this default implementation when
513 // optimized version can be provided (e.g. FieldExpr)
516 // We can optimize for side-effect free expressions, they can be
517 // emitted out of order
519 if (IsSideEffectFree)
522 // Emit original code
523 EmitToFieldSource (ec);
525 // Create temporary local (we cannot load this before Emit)
526 var temp = ec.GetTemporaryLocal (type);
527 ec.Emit (OpCodes.Stloc, temp, type);
530 // Store the result to temporary field
532 var field = ec.GetTemporaryField (type);
534 ec.Emit (OpCodes.Ldloc, temp, type);
535 field.EmitAssignFromStack (ec);
537 ec.FreeTemporaryLocal (temp, type);
542 protected virtual void EmitToFieldSource (EmitContext ec)
545 // Default implementation calls Emit method
550 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
552 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
553 bool contains_await = false;
555 for (int i = 1; i < expressions.Count; ++i) {
556 if (expressions[i].ContainsEmitWithAwait ()) {
557 contains_await = true;
562 if (contains_await) {
563 for (int i = 0; i < expressions.Count; ++i) {
564 expressions[i] = expressions[i].EmitToField (ec);
569 for (int i = 0; i < expressions.Count; ++i) {
570 expressions[i].Emit (ec);
575 /// Protected constructor. Only derivate types should
576 /// be able to be created
579 protected Expression ()
584 /// Returns a fully formed expression after a MemberLookup
587 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
589 if (spec is EventSpec)
590 return new EventExpr ((EventSpec) spec, loc);
591 if (spec is ConstSpec)
592 return new ConstantExpr ((ConstSpec) spec, loc);
593 if (spec is FieldSpec)
594 return new FieldExpr ((FieldSpec) spec, loc);
595 if (spec is PropertySpec)
596 return new PropertyExpr ((PropertySpec) spec, loc);
597 if (spec is TypeSpec)
598 return new TypeExpression (((TypeSpec) spec), loc);
603 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
605 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
607 rc.Report.SymbolRelatedToPreviousError (type);
609 // Report meaningful error for struct as they always have default ctor in C# context
610 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
612 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
613 type.GetSignatureForError ());
619 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
620 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
624 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
625 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
632 public enum MemberLookupRestrictions
641 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
642 // `qualifier_type' or null to lookup members in the current class.
644 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
646 var members = MemberCache.FindMembers (queried_type, name, false);
650 MemberSpec non_method = null;
651 MemberSpec ambig_non_method = null;
653 for (int i = 0; i < members.Count; ++i) {
654 var member = members[i];
656 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
657 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
660 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
664 if (!member.IsAccessible (rc))
668 // With runtime binder we can have a situation where queried type is inaccessible
669 // because it came via dynamic object, the check about inconsisted accessibility
670 // had no effect as the type was unknown during compilation
673 // private class N { }
675 // public dynamic Foo ()
681 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
685 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
686 if (member is MethodSpec)
687 return new MethodGroupExpr (members, queried_type, loc);
689 if (!Invocation.IsMemberInvocable (member))
693 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
695 } else if (!errorMode && !member.IsNotCSharpCompatible) {
696 ambig_non_method = member;
700 if (non_method != null) {
701 if (ambig_non_method != null && rc != null) {
702 var report = rc.Module.Compiler.Report;
703 report.SymbolRelatedToPreviousError (non_method);
704 report.SymbolRelatedToPreviousError (ambig_non_method);
705 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
706 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
709 if (non_method is MethodSpec)
710 return new MethodGroupExpr (members, queried_type, loc);
712 return ExprClassFromMemberInfo (non_method, loc);
715 if (members[0].DeclaringType.BaseType == null)
718 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
720 } while (members != null);
725 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
727 throw new NotImplementedException ();
730 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
732 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
736 /// Returns an expression that can be used to invoke operator true
737 /// on the expression if it exists.
739 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
741 return GetOperatorTrueOrFalse (ec, e, true, loc);
745 /// Returns an expression that can be used to invoke operator false
746 /// on the expression if it exists.
748 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
750 return GetOperatorTrueOrFalse (ec, e, false, loc);
753 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
755 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
756 var methods = MemberCache.GetUserOperator (e.type, op, false);
760 Arguments arguments = new Arguments (1);
761 arguments.Add (new Argument (e));
763 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
764 var oper = res.ResolveOperator (ec, ref arguments);
769 return new UserOperatorCall (oper, arguments, null, loc);
772 public virtual string ExprClassName
776 case ExprClass.Unresolved:
778 case ExprClass.Value:
780 case ExprClass.Variable:
782 case ExprClass.Namespace:
786 case ExprClass.MethodGroup:
787 return "method group";
788 case ExprClass.PropertyAccess:
789 return "property access";
790 case ExprClass.EventAccess:
791 return "event access";
792 case ExprClass.IndexerAccess:
793 return "indexer access";
794 case ExprClass.Nothing:
796 case ExprClass.TypeParameter:
797 return "type parameter";
799 throw new Exception ("Should not happen");
804 /// Reports that we were expecting `expr' to be of class `expected'
806 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
808 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
811 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
815 name = mc.GetSignatureForError ();
817 name = GetSignatureForError ();
819 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
820 name, was, expected);
823 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
825 string [] valid = new string [4];
828 if ((flags & ResolveFlags.VariableOrValue) != 0) {
829 valid [count++] = "variable";
830 valid [count++] = "value";
833 if ((flags & ResolveFlags.Type) != 0)
834 valid [count++] = "type";
836 if ((flags & ResolveFlags.MethodGroup) != 0)
837 valid [count++] = "method group";
840 valid [count++] = "unknown";
842 StringBuilder sb = new StringBuilder (valid [0]);
843 for (int i = 1; i < count - 1; i++) {
845 sb.Append (valid [i]);
848 sb.Append ("' or `");
849 sb.Append (valid [count - 1]);
852 ec.Report.Error (119, loc,
853 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
856 public static void UnsafeError (ResolveContext ec, Location loc)
858 UnsafeError (ec.Report, loc);
861 public static void UnsafeError (Report Report, Location loc)
863 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
866 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
868 ec.Report.SymbolRelatedToPreviousError (type);
869 if (ec.CurrentInitializerVariable != null) {
870 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
871 TypeManager.CSharpName (type), GetSignatureForError ());
873 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
874 GetSignatureForError ());
879 // Converts `source' to an int, uint, long or ulong.
881 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
883 var btypes = ec.BuiltinTypes;
885 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
886 Arguments args = new Arguments (1);
887 args.Add (new Argument (source));
888 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
891 Expression converted;
893 using (ec.Set (ResolveContext.Options.CheckedScope)) {
894 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
895 if (converted == null)
896 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
897 if (converted == null)
898 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
899 if (converted == null)
900 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
902 if (converted == null) {
903 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
909 // Only positive constants are allowed at compile time
911 Constant c = converted as Constant;
912 if (c != null && c.IsNegative)
913 Error_NegativeArrayIndex (ec, source.loc);
915 // No conversion needed to array index
916 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
919 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
923 // Derived classes implement this method by cloning the fields that
924 // could become altered during the Resolve stage
926 // Only expressions that are created for the parser need to implement
929 protected virtual void CloneTo (CloneContext clonectx, Expression target)
931 throw new NotImplementedException (
933 "CloneTo not implemented for expression {0}", this.GetType ()));
937 // Clones an expression created by the parser.
939 // We only support expressions created by the parser so far, not
940 // expressions that have been resolved (many more classes would need
941 // to implement CloneTo).
943 // This infrastructure is here merely for Lambda expressions which
944 // compile the same code using different type values for the same
945 // arguments to find the correct overload
947 public virtual Expression Clone (CloneContext clonectx)
949 Expression cloned = (Expression) MemberwiseClone ();
950 CloneTo (clonectx, cloned);
956 // Implementation of expression to expression tree conversion
958 public abstract Expression CreateExpressionTree (ResolveContext ec);
960 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
962 return CreateExpressionFactoryCall (ec, name, null, args, loc);
965 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
967 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
970 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
972 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
975 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
977 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
981 return new TypeExpression (t, loc);
985 // Implemented by all expressions which support conversion from
986 // compiler expression to invokable runtime expression. Used by
987 // dynamic C# binder.
989 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
991 throw new NotImplementedException ("MakeExpression for " + GetType ());
996 /// This is just a base class for expressions that can
997 /// appear on statements (invocations, object creation,
998 /// assignments, post/pre increment and decrement). The idea
999 /// being that they would support an extra Emition interface that
1000 /// does not leave a result on the stack.
1002 public abstract class ExpressionStatement : Expression {
1004 public ExpressionStatement ResolveStatement (BlockContext ec)
1006 Expression e = Resolve (ec);
1010 ExpressionStatement es = e as ExpressionStatement;
1012 Error_InvalidExpressionStatement (ec);
1018 /// Requests the expression to be emitted in a `statement'
1019 /// context. This means that no new value is left on the
1020 /// stack after invoking this method (constrasted with
1021 /// Emit that will always leave a value on the stack).
1023 public abstract void EmitStatement (EmitContext ec);
1025 public override void EmitSideEffect (EmitContext ec)
1032 /// This kind of cast is used to encapsulate the child
1033 /// whose type is child.Type into an expression that is
1034 /// reported to return "return_type". This is used to encapsulate
1035 /// expressions which have compatible types, but need to be dealt
1036 /// at higher levels with.
1038 /// For example, a "byte" expression could be encapsulated in one
1039 /// of these as an "unsigned int". The type for the expression
1040 /// would be "unsigned int".
1043 public abstract class TypeCast : Expression
1045 protected readonly Expression child;
1047 protected TypeCast (Expression child, TypeSpec return_type)
1049 eclass = child.eclass;
1050 loc = child.Location;
1055 public Expression Child {
1061 public override bool ContainsEmitWithAwait ()
1063 return child.ContainsEmitWithAwait ();
1066 public override Expression CreateExpressionTree (ResolveContext ec)
1068 Arguments args = new Arguments (2);
1069 args.Add (new Argument (child.CreateExpressionTree (ec)));
1070 args.Add (new Argument (new TypeOf (type, loc)));
1072 if (type.IsPointer || child.Type.IsPointer)
1073 Error_PointerInsideExpressionTree (ec);
1075 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1078 protected override Expression DoResolve (ResolveContext ec)
1080 // This should never be invoked, we are born in fully
1081 // initialized state.
1086 public override void Emit (EmitContext ec)
1091 public override SLE.Expression MakeExpression (BuilderContext ctx)
1094 return base.MakeExpression (ctx);
1096 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1097 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1098 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1102 protected override void CloneTo (CloneContext clonectx, Expression t)
1107 public override bool IsNull {
1108 get { return child.IsNull; }
1112 public class EmptyCast : TypeCast {
1113 EmptyCast (Expression child, TypeSpec target_type)
1114 : base (child, target_type)
1118 public static Expression Create (Expression child, TypeSpec type)
1120 Constant c = child as Constant;
1122 return new EmptyConstantCast (c, type);
1124 EmptyCast e = child as EmptyCast;
1126 return new EmptyCast (e.child, type);
1128 return new EmptyCast (child, type);
1131 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1133 child.EmitBranchable (ec, label, on_true);
1136 public override void EmitSideEffect (EmitContext ec)
1138 child.EmitSideEffect (ec);
1143 // Used for predefined type user operator (no obsolete check, etc.)
1145 public class OperatorCast : TypeCast
1147 readonly MethodSpec conversion_operator;
1149 public OperatorCast (Expression expr, TypeSpec target_type)
1150 : this (expr, target_type, target_type, false)
1154 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1155 : this (expr, target_type, target_type, find_explicit)
1159 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1160 : base (expr, returnType)
1162 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1163 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1166 foreach (MethodSpec oper in mi) {
1167 if (oper.ReturnType != returnType)
1170 if (oper.Parameters.Types[0] == expr.Type) {
1171 conversion_operator = oper;
1177 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1178 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1181 public override void Emit (EmitContext ec)
1184 ec.Emit (OpCodes.Call, conversion_operator);
1189 // Constant specialization of EmptyCast.
1190 // We need to special case this since an empty cast of
1191 // a constant is still a constant.
1193 public class EmptyConstantCast : Constant
1195 public readonly Constant child;
1197 public EmptyConstantCast (Constant child, TypeSpec type)
1198 : base (child.Location)
1201 throw new ArgumentNullException ("child");
1204 this.eclass = child.eclass;
1208 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1210 if (child.Type == target_type)
1213 // FIXME: check that 'type' can be converted to 'target_type' first
1214 return child.ConvertExplicitly (in_checked_context, target_type);
1217 public override Expression CreateExpressionTree (ResolveContext ec)
1219 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1220 child.CreateExpressionTree (ec),
1221 new TypeOf (type, loc));
1224 Error_PointerInsideExpressionTree (ec);
1226 return CreateExpressionFactoryCall (ec, "Convert", args);
1229 public override bool IsDefaultValue {
1230 get { return child.IsDefaultValue; }
1233 public override bool IsNegative {
1234 get { return child.IsNegative; }
1237 public override bool IsNull {
1238 get { return child.IsNull; }
1241 public override bool IsOneInteger {
1242 get { return child.IsOneInteger; }
1245 public override bool IsSideEffectFree {
1247 return child.IsSideEffectFree;
1251 public override bool IsZeroInteger {
1252 get { return child.IsZeroInteger; }
1255 public override void Emit (EmitContext ec)
1260 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1262 child.EmitBranchable (ec, label, on_true);
1264 // Only to make verifier happy
1265 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1266 ec.Emit (OpCodes.Unbox_Any, type);
1269 public override void EmitSideEffect (EmitContext ec)
1271 child.EmitSideEffect (ec);
1274 public override object GetValue ()
1276 return child.GetValue ();
1279 public override string GetValueAsLiteral ()
1281 return child.GetValueAsLiteral ();
1284 public override long GetValueAsLong ()
1286 return child.GetValueAsLong ();
1289 public override Constant ConvertImplicitly (TypeSpec target_type)
1291 if (type == target_type)
1294 // FIXME: Do we need to check user conversions?
1295 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1298 return child.ConvertImplicitly (target_type);
1303 /// This class is used to wrap literals which belong inside Enums
1305 public class EnumConstant : Constant
1307 public Constant Child;
1309 public EnumConstant (Constant child, TypeSpec enum_type)
1310 : base (child.Location)
1314 this.eclass = ExprClass.Value;
1315 this.type = enum_type;
1318 protected EnumConstant (Location loc)
1323 public override void Emit (EmitContext ec)
1328 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1330 Child.EncodeAttributeValue (rc, enc, Child.Type);
1333 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1335 Child.EmitBranchable (ec, label, on_true);
1338 public override void EmitSideEffect (EmitContext ec)
1340 Child.EmitSideEffect (ec);
1343 public override string GetSignatureForError()
1345 return TypeManager.CSharpName (Type);
1348 public override object GetValue ()
1350 return Child.GetValue ();
1354 public override object GetTypedValue ()
1357 // The method can be used in dynamic context only (on closed types)
1359 // System.Enum.ToObject cannot be called on dynamic types
1360 // EnumBuilder has to be used, but we cannot use EnumBuilder
1361 // because it does not properly support generics
1363 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1367 public override string GetValueAsLiteral ()
1369 return Child.GetValueAsLiteral ();
1372 public override long GetValueAsLong ()
1374 return Child.GetValueAsLong ();
1377 public EnumConstant Increment()
1379 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1382 public override bool IsDefaultValue {
1384 return Child.IsDefaultValue;
1388 public override bool IsSideEffectFree {
1390 return Child.IsSideEffectFree;
1394 public override bool IsZeroInteger {
1395 get { return Child.IsZeroInteger; }
1398 public override bool IsNegative {
1400 return Child.IsNegative;
1404 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1406 if (Child.Type == target_type)
1409 return Child.ConvertExplicitly (in_checked_context, target_type);
1412 public override Constant ConvertImplicitly (TypeSpec type)
1414 if (this.type == type) {
1418 if (!Convert.ImplicitStandardConversionExists (this, type)){
1422 return Child.ConvertImplicitly (type);
1427 /// This kind of cast is used to encapsulate Value Types in objects.
1429 /// The effect of it is to box the value type emitted by the previous
1432 public class BoxedCast : TypeCast {
1434 public BoxedCast (Expression expr, TypeSpec target_type)
1435 : base (expr, target_type)
1437 eclass = ExprClass.Value;
1440 protected override Expression DoResolve (ResolveContext ec)
1442 // This should never be invoked, we are born in fully
1443 // initialized state.
1448 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1450 // Only boxing to object type is supported
1451 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1452 base.EncodeAttributeValue (rc, enc, targetType);
1456 enc.Encode (child.Type);
1457 child.EncodeAttributeValue (rc, enc, child.Type);
1460 public override void Emit (EmitContext ec)
1464 ec.Emit (OpCodes.Box, child.Type);
1467 public override void EmitSideEffect (EmitContext ec)
1469 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1470 // so, we need to emit the box+pop instructions in most cases
1471 if (child.Type.IsStruct &&
1472 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1473 child.EmitSideEffect (ec);
1475 base.EmitSideEffect (ec);
1479 public class UnboxCast : TypeCast {
1480 public UnboxCast (Expression expr, TypeSpec return_type)
1481 : base (expr, return_type)
1485 protected override Expression DoResolve (ResolveContext ec)
1487 // This should never be invoked, we are born in fully
1488 // initialized state.
1493 public override void Emit (EmitContext ec)
1497 ec.Emit (OpCodes.Unbox_Any, type);
1502 /// This is used to perform explicit numeric conversions.
1504 /// Explicit numeric conversions might trigger exceptions in a checked
1505 /// context, so they should generate the conv.ovf opcodes instead of
1508 public class ConvCast : TypeCast {
1509 public enum Mode : byte {
1510 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1512 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1513 U2_I1, U2_U1, U2_I2, U2_CH,
1514 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1515 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1516 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1517 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1518 CH_I1, CH_U1, CH_I2,
1519 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1520 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1526 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1527 : base (child, return_type)
1532 protected override Expression DoResolve (ResolveContext ec)
1534 // This should never be invoked, we are born in fully
1535 // initialized state.
1540 public override string ToString ()
1542 return String.Format ("ConvCast ({0}, {1})", mode, child);
1545 public override void Emit (EmitContext ec)
1549 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1551 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1552 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1553 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1554 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1555 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1557 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1558 case Mode.U1_CH: /* nothing */ break;
1560 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1561 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1562 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1563 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1564 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1565 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1567 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1568 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1569 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1570 case Mode.U2_CH: /* nothing */ break;
1572 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1573 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1574 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1575 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1576 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1577 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1578 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1580 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1581 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1582 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1583 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1584 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1585 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1587 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1588 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1589 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1590 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1592 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1593 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1594 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1595 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1597 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1598 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1599 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1600 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1601 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1602 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1603 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1604 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1605 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1607 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1608 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1609 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1611 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1612 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1613 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1614 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1615 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1616 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1617 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1618 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1619 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1622 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1623 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1624 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1626 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1627 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1628 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1629 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1632 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1636 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1637 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1638 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1639 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1640 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1642 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1643 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1645 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1646 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1647 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1649 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1650 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1652 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1653 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1654 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1655 case Mode.U2_CH: /* nothing */ break;
1657 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1659 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1660 case Mode.I4_U4: /* nothing */ break;
1661 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1662 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1663 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1665 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1666 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1667 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1668 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.U4_I4: /* nothing */ break;
1670 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1673 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1674 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1675 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1677 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1678 case Mode.I8_U8: /* nothing */ break;
1679 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1682 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1683 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1684 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1685 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1687 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1688 case Mode.U8_I8: /* nothing */ break;
1689 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1692 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1693 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1694 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1697 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1698 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1699 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1700 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1701 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1702 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1703 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1704 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1707 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1708 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1709 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1710 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1711 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1712 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1713 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1714 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1717 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1723 class OpcodeCast : TypeCast
1727 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1728 : base (child, return_type)
1733 protected override Expression DoResolve (ResolveContext ec)
1735 // This should never be invoked, we are born in fully
1736 // initialized state.
1741 public override void Emit (EmitContext ec)
1747 public TypeSpec UnderlyingType {
1748 get { return child.Type; }
1753 // Opcode casts expression with 2 opcodes but only
1754 // single expression tree node
1756 class OpcodeCastDuplex : OpcodeCast
1758 readonly OpCode second;
1760 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1761 : base (child, returnType, first)
1763 this.second = second;
1766 public override void Emit (EmitContext ec)
1774 /// This kind of cast is used to encapsulate a child and cast it
1775 /// to the class requested
1777 public sealed class ClassCast : TypeCast {
1778 readonly bool forced;
1780 public ClassCast (Expression child, TypeSpec return_type)
1781 : base (child, return_type)
1785 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1786 : base (child, return_type)
1788 this.forced = forced;
1791 public override void Emit (EmitContext ec)
1795 bool gen = TypeManager.IsGenericParameter (child.Type);
1797 ec.Emit (OpCodes.Box, child.Type);
1799 if (type.IsGenericParameter) {
1800 ec.Emit (OpCodes.Unbox_Any, type);
1807 ec.Emit (OpCodes.Castclass, type);
1812 // Created during resolving pahse when an expression is wrapped or constantified
1813 // and original expression can be used later (e.g. for expression trees)
1815 public class ReducedExpression : Expression
1817 sealed class ReducedConstantExpression : EmptyConstantCast
1819 readonly Expression orig_expr;
1821 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1822 : base (expr, expr.Type)
1824 this.orig_expr = orig_expr;
1827 public override Constant ConvertImplicitly (TypeSpec target_type)
1829 Constant c = base.ConvertImplicitly (target_type);
1831 c = new ReducedConstantExpression (c, orig_expr);
1836 public override Expression CreateExpressionTree (ResolveContext ec)
1838 return orig_expr.CreateExpressionTree (ec);
1841 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1843 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1845 c = new ReducedConstantExpression (c, orig_expr);
1850 sealed class ReducedExpressionStatement : ExpressionStatement
1852 readonly Expression orig_expr;
1853 readonly ExpressionStatement stm;
1855 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1857 this.orig_expr = orig;
1859 this.eclass = stm.eclass;
1860 this.type = stm.Type;
1862 this.loc = orig.Location;
1865 public override Expression CreateExpressionTree (ResolveContext ec)
1867 return orig_expr.CreateExpressionTree (ec);
1870 protected override Expression DoResolve (ResolveContext ec)
1875 public override void Emit (EmitContext ec)
1880 public override void EmitStatement (EmitContext ec)
1882 stm.EmitStatement (ec);
1886 readonly Expression expr, orig_expr;
1888 private ReducedExpression (Expression expr, Expression orig_expr)
1891 this.eclass = expr.eclass;
1892 this.type = expr.Type;
1893 this.orig_expr = orig_expr;
1894 this.loc = orig_expr.Location;
1899 public Expression OriginalExpression {
1908 // Creates fully resolved expression switcher
1910 public static Constant Create (Constant expr, Expression original_expr)
1912 if (expr.eclass == ExprClass.Unresolved)
1913 throw new ArgumentException ("Unresolved expression");
1915 return new ReducedConstantExpression (expr, original_expr);
1918 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1920 return new ReducedExpressionStatement (s, orig);
1923 public static Expression Create (Expression expr, Expression original_expr)
1925 return Create (expr, original_expr, true);
1929 // Creates unresolved reduce expression. The original expression has to be
1930 // already resolved. Created expression is constant based based on `expr'
1931 // value unless canBeConstant is used
1933 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1935 if (canBeConstant) {
1936 Constant c = expr as Constant;
1938 return Create (c, original_expr);
1941 ExpressionStatement s = expr as ExpressionStatement;
1943 return Create (s, original_expr);
1945 if (expr.eclass == ExprClass.Unresolved)
1946 throw new ArgumentException ("Unresolved expression");
1948 return new ReducedExpression (expr, original_expr);
1951 public override Expression CreateExpressionTree (ResolveContext ec)
1953 return orig_expr.CreateExpressionTree (ec);
1956 protected override Expression DoResolve (ResolveContext ec)
1961 public override void Emit (EmitContext ec)
1966 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1968 expr.EmitBranchable (ec, target, on_true);
1971 public override SLE.Expression MakeExpression (BuilderContext ctx)
1973 return orig_expr.MakeExpression (ctx);
1978 // Standard composite pattern
1980 public abstract class CompositeExpression : Expression
1982 protected Expression expr;
1984 protected CompositeExpression (Expression expr)
1987 this.loc = expr.Location;
1990 public override Expression CreateExpressionTree (ResolveContext rc)
1992 return expr.CreateExpressionTree (rc);
1995 public Expression Child {
1996 get { return expr; }
1999 protected override Expression DoResolve (ResolveContext rc)
2001 expr = expr.Resolve (rc);
2004 eclass = expr.eclass;
2010 public override void Emit (EmitContext ec)
2015 public override bool IsNull {
2016 get { return expr.IsNull; }
2021 // Base of expressions used only to narrow resolve flow
2023 public abstract class ShimExpression : Expression
2025 protected Expression expr;
2027 protected ShimExpression (Expression expr)
2032 public Expression Expr {
2038 protected override void CloneTo (CloneContext clonectx, Expression t)
2043 ShimExpression target = (ShimExpression) t;
2044 target.expr = expr.Clone (clonectx);
2047 public override bool ContainsEmitWithAwait ()
2049 return expr.ContainsEmitWithAwait ();
2052 public override Expression CreateExpressionTree (ResolveContext ec)
2054 throw new NotSupportedException ("ET");
2057 public override void Emit (EmitContext ec)
2059 throw new InternalErrorException ("Missing Resolve call");
2065 // Unresolved type name expressions
2067 public abstract class ATypeNameExpression : FullNamedExpression
2070 protected TypeArguments targs;
2072 protected ATypeNameExpression (string name, Location l)
2078 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2085 protected ATypeNameExpression (string name, int arity, Location l)
2086 : this (name, new UnboundTypeArguments (arity), l)
2092 protected int Arity {
2094 return targs == null ? 0 : targs.Count;
2098 public bool HasTypeArguments {
2100 return targs != null && !targs.IsEmpty;
2104 public string Name {
2113 public TypeArguments TypeArguments {
2121 public override bool Equals (object obj)
2123 ATypeNameExpression atne = obj as ATypeNameExpression;
2124 return atne != null && atne.Name == Name &&
2125 (targs == null || targs.Equals (atne.targs));
2128 public override int GetHashCode ()
2130 return Name.GetHashCode ();
2133 // TODO: Move it to MemberCore
2134 public static string GetMemberType (MemberCore mc)
2140 if (mc is FieldBase)
2142 if (mc is MethodCore)
2144 if (mc is EnumMember)
2152 public override string GetSignatureForError ()
2154 if (targs != null) {
2155 return Name + "<" + targs.GetSignatureForError () + ">";
2161 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2165 /// SimpleName expressions are formed of a single word and only happen at the beginning
2166 /// of a dotted-name.
2168 public class SimpleName : ATypeNameExpression
2170 public SimpleName (string name, Location l)
2175 public SimpleName (string name, TypeArguments args, Location l)
2176 : base (name, args, l)
2180 public SimpleName (string name, int arity, Location l)
2181 : base (name, arity, l)
2185 public SimpleName GetMethodGroup ()
2187 return new SimpleName (Name, targs, loc);
2190 protected override Expression DoResolve (ResolveContext ec)
2192 return SimpleNameResolve (ec, null, false);
2195 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2197 return SimpleNameResolve (ec, right_side, false);
2200 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2202 if (ctx.CurrentType != null) {
2203 if (ctx.CurrentMemberDefinition != null) {
2204 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2206 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2212 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2213 if (retval != null) {
2214 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2215 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2219 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2220 if (retval != null) {
2221 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2225 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2228 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2230 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2233 if (fne.Type != null && Arity > 0) {
2234 if (HasTypeArguments) {
2235 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2236 if (ct.ResolveAsType (ec) == null)
2242 return new GenericOpenTypeExpr (fne.Type, loc);
2246 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2248 if (!(fne is Namespace))
2252 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2253 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2254 ec.Module.Compiler.Report.Error (1980, Location,
2255 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2256 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2259 fne = new DynamicTypeExpr (loc);
2260 fne.ResolveAsType (ec);
2266 Error_TypeOrNamespaceNotFound (ec);
2270 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2272 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2275 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2277 int lookup_arity = Arity;
2278 bool errorMode = false;
2280 Block current_block = rc.CurrentBlock;
2281 INamedBlockVariable variable = null;
2282 bool variable_found = false;
2286 // Stage 1: binding to local variables or parameters
2288 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2290 if (current_block != null && lookup_arity == 0) {
2291 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2292 if (!variable.IsDeclared) {
2293 // We found local name in accessible block but it's not
2294 // initialized yet, maybe the user wanted to bind to something else
2296 variable_found = true;
2298 e = variable.CreateReferenceExpression (rc, loc);
2301 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2310 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2312 TypeSpec member_type = rc.CurrentType;
2313 for (; member_type != null; member_type = member_type.DeclaringType) {
2314 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2318 var me = e as MemberExpr;
2320 // The name matches a type, defer to ResolveAsTypeStep
2328 if (variable != null) {
2329 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2330 rc.Report.Error (844, loc,
2331 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2332 Name, me.GetSignatureForError ());
2336 } else if (me is MethodGroupExpr) {
2337 // Leave it to overload resolution to report correct error
2339 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2340 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2343 // LAMESPEC: again, ignores InvocableOnly
2344 if (variable != null) {
2345 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2346 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2350 // MemberLookup does not check accessors availability, this is actually needed for properties only
2352 var pe = me as PropertyExpr;
2355 // Break as there is no other overload available anyway
2356 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2357 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2360 pe.Getter = pe.PropertyInfo.Get;
2362 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2365 pe.Setter = pe.PropertyInfo.Set;
2370 // TODO: It's used by EventExpr -> FieldExpr transformation only
2371 // TODO: Should go to MemberAccess
2372 me = me.ResolveMemberAccess (rc, null, null);
2376 me.SetTypeArguments (rc, targs);
2383 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2385 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2386 if (IsPossibleTypeOrNamespace (rc)) {
2387 if (variable != null) {
2388 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2389 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2392 return ResolveAsTypeOrNamespace (rc);
2397 if (variable_found) {
2398 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2401 TypeParameter[] tparams = rc.CurrentTypeParameters;
2402 if (tparams != null) {
2403 foreach (var ctp in tparams) {
2404 if (ctp.Name == Name) {
2405 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2411 var ct = rc.CurrentType;
2413 if (ct.MemberDefinition.TypeParametersCount > 0) {
2414 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2415 if (ctp.Name == Name) {
2416 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2422 ct = ct.DeclaringType;
2423 } while (ct != null);
2426 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2427 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2429 rc.Report.SymbolRelatedToPreviousError (e.Type);
2430 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2435 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2437 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2438 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2443 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2446 return ErrorExpression.Instance;
2449 if (rc.Module.Evaluator != null) {
2450 var fi = rc.Module.Evaluator.LookupField (Name);
2452 return new FieldExpr (fi.Item1, loc);
2460 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2462 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2467 if (right_side != null) {
2468 if (e is TypeExpr) {
2469 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2473 e = e.ResolveLValue (ec, right_side);
2478 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2484 /// Represents a namespace or a type. The name of the class was inspired by
2485 /// section 10.8.1 (Fully Qualified Names).
2487 public abstract class FullNamedExpression : Expression
2489 protected override void CloneTo (CloneContext clonectx, Expression target)
2491 // Do nothing, most unresolved type expressions cannot be
2492 // resolved to different type
2495 public override bool ContainsEmitWithAwait ()
2500 public override Expression CreateExpressionTree (ResolveContext ec)
2502 throw new NotSupportedException ("ET");
2505 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2508 // This is used to resolve the expression as a type, a null
2509 // value will be returned if the expression is not a type
2512 public override TypeSpec ResolveAsType (IMemberContext mc)
2514 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2519 TypeExpr te = fne as TypeExpr;
2521 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2529 var dep = type.GetMissingDependencies ();
2531 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2535 // Obsolete checks cannot be done when resolving base context as they
2536 // require type dependencies to be set but we are in process of resolving them
2538 if (!(mc is TypeContainer.BaseContext)) {
2539 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2540 if (obsolete_attr != null && !mc.IsObsolete) {
2541 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2549 public override void Emit (EmitContext ec)
2551 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2552 GetSignatureForError ());
2557 /// Expression that evaluates to a type
2559 public abstract class TypeExpr : FullNamedExpression
2561 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2567 protected sealed override Expression DoResolve (ResolveContext ec)
2573 public override bool Equals (object obj)
2575 TypeExpr tobj = obj as TypeExpr;
2579 return Type == tobj.Type;
2582 public override int GetHashCode ()
2584 return Type.GetHashCode ();
2589 /// Fully resolved Expression that already evaluated to a type
2591 public class TypeExpression : TypeExpr
2593 public TypeExpression (TypeSpec t, Location l)
2596 eclass = ExprClass.Type;
2600 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2607 /// This class denotes an expression which evaluates to a member
2608 /// of a struct or a class.
2610 public abstract class MemberExpr : Expression
2613 // An instance expression associated with this member, if it's a
2614 // non-static member
2616 public Expression InstanceExpression;
2619 /// The name of this member.
2621 public abstract string Name {
2626 // When base.member is used
2628 public bool IsBase {
2629 get { return InstanceExpression is BaseThis; }
2633 /// Whether this is an instance member.
2635 public abstract bool IsInstance {
2640 /// Whether this is a static member.
2642 public abstract bool IsStatic {
2646 protected abstract TypeSpec DeclaringType {
2651 // Converts best base candidate for virtual method starting from QueriedBaseType
2653 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2656 // Only when base.member is used and method is virtual
2662 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2663 // means for base.member access we have to find the closest match after we found best candidate
2665 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2667 // The method could already be what we are looking for
2669 TypeSpec[] targs = null;
2670 if (method.DeclaringType != InstanceExpression.Type) {
2671 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2672 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2673 if (base_override.IsGeneric)
2674 targs = method.TypeArguments;
2676 method = base_override;
2680 // TODO: For now we do it for any hoisted call even if it's needed for
2681 // hoisted stories only but that requires a new expression wrapper
2682 if (rc.CurrentAnonymousMethod != null) {
2683 if (targs == null && method.IsGeneric) {
2684 targs = method.TypeArguments;
2685 method = method.GetGenericMethodDefinition ();
2688 if (method.Parameters.HasArglist)
2689 throw new NotImplementedException ("__arglist base call proxy");
2691 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2693 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2694 // get/set member expressions second call would fail to proxy because left expression
2695 // would be of 'this' and not 'base'
2696 if (rc.CurrentType.IsStruct)
2697 InstanceExpression = new This (loc).Resolve (rc);
2701 method = method.MakeGenericMethod (rc, targs);
2705 // Only base will allow this invocation to happen.
2707 if (method.IsAbstract) {
2708 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2714 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2716 if (InstanceExpression == null)
2719 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2720 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2724 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2726 var ct = rc.CurrentType;
2727 if (ct == qualifier)
2730 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2733 qualifier = qualifier.GetDefinition ();
2734 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2735 rc.Report.SymbolRelatedToPreviousError (member);
2736 rc.Report.Error (1540, loc,
2737 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2738 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2742 public override bool ContainsEmitWithAwait ()
2744 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2747 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2750 type = type.GetDefinition ();
2752 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2755 type = type.DeclaringType;
2756 } while (type != null);
2761 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2763 if (InstanceExpression != null) {
2764 InstanceExpression = InstanceExpression.Resolve (rc);
2765 CheckProtectedMemberAccess (rc, member);
2768 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2769 UnsafeError (rc, loc);
2772 var dep = member.GetMissingDependencies ();
2774 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2777 if (!rc.IsObsolete) {
2778 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2780 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2783 if (!(member is FieldSpec))
2784 member.MemberDefinition.SetIsUsed ();
2787 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2789 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2793 // Implements identicial simple name and type-name
2795 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2798 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2801 // 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
2802 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2804 if (left is MemberExpr || left is VariableReference) {
2805 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2806 if (identical_type != null && identical_type.Type == left.Type)
2807 return identical_type;
2813 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2816 if (InstanceExpression != null) {
2817 if (InstanceExpression is TypeExpr) {
2818 var t = InstanceExpression.Type;
2820 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2821 if (oa != null && !rc.IsObsolete) {
2822 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2825 t = t.DeclaringType;
2826 } while (t != null);
2828 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2829 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2830 rc.Report.Error (176, loc,
2831 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2832 GetSignatureForError ());
2836 InstanceExpression = null;
2842 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2843 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2844 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2845 rc.Report.Error (236, loc,
2846 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2847 GetSignatureForError ());
2849 rc.Report.Error (120, loc,
2850 "An object reference is required to access non-static member `{0}'",
2851 GetSignatureForError ());
2856 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2857 rc.Report.Error (38, loc,
2858 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2859 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2862 InstanceExpression = new This (loc);
2863 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2864 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2865 InstanceExpression = InstanceExpression.Resolve (rc);
2868 InstanceExpression = InstanceExpression.Resolve (rc);
2874 var me = InstanceExpression as MemberExpr;
2876 me.ResolveInstanceExpression (rc, rhs);
2878 var fe = me as FieldExpr;
2879 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2880 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2881 rc.Report.Warning (1690, 1, loc,
2882 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2883 me.GetSignatureForError ());
2890 // Run member-access postponed check once we know that
2891 // the expression is not field expression which is the only
2892 // expression which can use uninitialized this
2894 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2895 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2899 // Additional checks for l-value member access
2903 // TODO: It should be recursive but that would break csc compatibility
2905 if (InstanceExpression is UnboxCast) {
2906 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2913 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2915 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2916 ec.Report.Warning (1720, 1, left.Location,
2917 "Expression will always cause a `{0}'", "System.NullReferenceException");
2920 InstanceExpression = left;
2924 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2926 TypeSpec instance_type = InstanceExpression.Type;
2927 if (TypeSpec.IsValueType (instance_type)) {
2928 if (InstanceExpression is IMemoryLocation) {
2929 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2931 LocalTemporary t = new LocalTemporary (instance_type);
2932 InstanceExpression.Emit (ec);
2934 t.AddressOf (ec, AddressOp.Store);
2937 InstanceExpression.Emit (ec);
2939 // Only to make verifier happy
2940 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2941 ec.Emit (OpCodes.Box, instance_type);
2944 if (prepare_for_load)
2945 ec.Emit (OpCodes.Dup);
2948 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2952 // Represents a group of extension method candidates for whole namespace
2954 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2956 NamespaceContainer namespace_entry;
2957 public readonly Expression ExtensionExpression;
2959 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
2960 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2962 this.namespace_entry = n;
2963 this.ExtensionExpression = extensionExpr;
2966 public override bool IsStatic {
2967 get { return true; }
2970 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2972 if (namespace_entry == null)
2976 // For extension methodgroup we are not looking for base members but parent
2977 // namespace extension methods
2979 int arity = type_arguments == null ? 0 : type_arguments.Count;
2980 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2984 return found.Cast<MemberSpec> ().ToList ();
2987 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2989 // We are already here
2993 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2995 if (arguments == null)
2996 arguments = new Arguments (1);
2998 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2999 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3001 // Store resolved argument and restore original arguments
3003 // Clean-up modified arguments for error reporting
3004 arguments.RemoveAt (0);
3008 var me = ExtensionExpression as MemberExpr;
3010 me.ResolveInstanceExpression (ec, null);
3012 InstanceExpression = null;
3016 #region IErrorHandler Members
3018 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3023 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3025 rc.Report.SymbolRelatedToPreviousError (best);
3026 rc.Report.Error (1928, loc,
3027 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3028 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3031 rc.Report.Error (1929, loc,
3032 "Extension method instance type `{0}' cannot be converted to `{1}'",
3033 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3039 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3044 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3053 /// MethodGroupExpr represents a group of method candidates which
3054 /// can be resolved to the best method overload
3056 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3058 protected IList<MemberSpec> Methods;
3059 MethodSpec best_candidate;
3060 TypeSpec best_candidate_return;
3061 protected TypeArguments type_arguments;
3063 SimpleName simple_name;
3064 protected TypeSpec queried_type;
3066 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3070 this.type = InternalType.MethodGroup;
3072 eclass = ExprClass.MethodGroup;
3073 queried_type = type;
3076 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3077 : this (new MemberSpec[] { m }, type, loc)
3083 public MethodSpec BestCandidate {
3085 return best_candidate;
3089 public TypeSpec BestCandidateReturnType {
3091 return best_candidate_return;
3095 public IList<MemberSpec> Candidates {
3101 protected override TypeSpec DeclaringType {
3103 return queried_type;
3107 public override bool IsInstance {
3109 if (best_candidate != null)
3110 return !best_candidate.IsStatic;
3116 public override bool IsStatic {
3118 if (best_candidate != null)
3119 return best_candidate.IsStatic;
3125 public override string Name {
3127 if (best_candidate != null)
3128 return best_candidate.Name;
3131 return Methods.First ().Name;
3138 // When best candidate is already know this factory can be used
3139 // to avoid expensive overload resolution to be called
3141 // NOTE: InstanceExpression has to be set manually
3143 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3145 return new MethodGroupExpr (best, queriedType, loc) {
3146 best_candidate = best,
3147 best_candidate_return = best.ReturnType
3151 public override string GetSignatureForError ()
3153 if (best_candidate != null)
3154 return best_candidate.GetSignatureForError ();
3156 return Methods.First ().GetSignatureForError ();
3159 public override Expression CreateExpressionTree (ResolveContext ec)
3161 if (best_candidate == null) {
3162 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3166 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3167 ec.Report.Error (765, loc,
3168 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3170 return new TypeOfMethod (best_candidate, loc);
3173 protected override Expression DoResolve (ResolveContext ec)
3175 this.eclass = ExprClass.MethodGroup;
3177 if (InstanceExpression != null) {
3178 InstanceExpression = InstanceExpression.Resolve (ec);
3179 if (InstanceExpression == null)
3186 public override void Emit (EmitContext ec)
3188 throw new NotSupportedException ();
3191 public void EmitCall (EmitContext ec, Arguments arguments)
3193 var call = new CallEmitter ();
3194 call.InstanceExpression = InstanceExpression;
3195 call.Emit (ec, best_candidate, arguments, loc);
3198 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3200 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3201 Name, TypeManager.CSharpName (target));
3204 public static bool IsExtensionMethodArgument (Expression expr)
3207 // LAMESPEC: No details about which expressions are not allowed
3209 return !(expr is TypeExpr) && !(expr is BaseThis);
3213 /// Find the Applicable Function Members (7.4.2.1)
3215 /// me: Method Group expression with the members to select.
3216 /// it might contain constructors or methods (or anything
3217 /// that maps to a method).
3219 /// Arguments: ArrayList containing resolved Argument objects.
3221 /// loc: The location if we want an error to be reported, or a Null
3222 /// location for "probing" purposes.
3224 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3225 /// that is the best match of me on Arguments.
3228 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3230 // TODO: causes issues with probing mode, remove explicit Kind check
3231 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3234 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3235 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3236 r.BaseMembersProvider = this;
3239 if (cerrors != null)
3240 r.CustomErrors = cerrors;
3242 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3243 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3244 if (best_candidate == null)
3245 return r.BestCandidateIsDynamic ? this : null;
3247 // Overload resolver had to create a new method group, all checks bellow have already been executed
3248 if (r.BestCandidateNewMethodGroup != null)
3249 return r.BestCandidateNewMethodGroup;
3251 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3252 if (InstanceExpression != null) {
3253 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3254 InstanceExpression = null;
3256 if (best_candidate.IsStatic && simple_name != null) {
3257 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3260 InstanceExpression.Resolve (ec);
3264 ResolveInstanceExpression (ec, null);
3265 if (InstanceExpression != null)
3266 CheckProtectedMemberAccess (ec, best_candidate);
3269 var base_override = CandidateToBaseOverride (ec, best_candidate);
3270 if (base_override == best_candidate) {
3271 best_candidate_return = r.BestCandidateReturnType;
3273 best_candidate = base_override;
3274 best_candidate_return = best_candidate.ReturnType;
3280 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3282 simple_name = original;
3283 return base.ResolveMemberAccess (ec, left, original);
3286 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3288 type_arguments = ta;
3291 #region IBaseMembersProvider Members
3293 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3295 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3298 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3300 if (queried_type == member.DeclaringType)
3303 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3304 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3308 // Extension methods lookup after ordinary methods candidates failed to apply
3310 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3312 if (InstanceExpression == null)
3315 InstanceExpression = InstanceExpression.Resolve (rc);
3316 if (!IsExtensionMethodArgument (InstanceExpression))
3319 int arity = type_arguments == null ? 0 : type_arguments.Count;
3320 NamespaceContainer methods_scope = null;
3321 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3322 if (methods == null)
3325 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3326 emg.SetTypeArguments (rc, type_arguments);
3333 public struct OverloadResolver
3336 public enum Restrictions
3340 ProbingOnly = 1 << 1,
3341 CovariantDelegate = 1 << 2,
3342 NoBaseMembers = 1 << 3,
3343 BaseMembersIncluded = 1 << 4
3346 public interface IBaseMembersProvider
3348 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3349 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3350 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3353 public interface IErrorHandler
3355 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3356 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3357 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3358 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3361 sealed class NoBaseMembers : IBaseMembersProvider
3363 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3365 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3370 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3375 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3381 struct AmbiguousCandidate
3383 public readonly MemberSpec Member;
3384 public readonly bool Expanded;
3385 public readonly AParametersCollection Parameters;
3387 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3390 Parameters = parameters;
3391 Expanded = expanded;
3396 IList<MemberSpec> members;
3397 TypeArguments type_arguments;
3398 IBaseMembersProvider base_provider;
3399 IErrorHandler custom_errors;
3400 Restrictions restrictions;
3401 MethodGroupExpr best_candidate_extension_group;
3402 TypeSpec best_candidate_return_type;
3404 SessionReportPrinter lambda_conv_msgs;
3405 ReportPrinter prev_recorder;
3407 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3408 : this (members, null, restrictions, loc)
3412 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3415 if (members == null || members.Count == 0)
3416 throw new ArgumentException ("empty members set");
3418 this.members = members;
3420 type_arguments = targs;
3421 this.restrictions = restrictions;
3422 if (IsDelegateInvoke)
3423 this.restrictions |= Restrictions.NoBaseMembers;
3425 base_provider = NoBaseMembers.Instance;
3430 public IBaseMembersProvider BaseMembersProvider {
3432 return base_provider;
3435 base_provider = value;
3439 public bool BestCandidateIsDynamic { get; set; }
3442 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3444 public MethodGroupExpr BestCandidateNewMethodGroup {
3446 return best_candidate_extension_group;
3451 // Return type can be different between best candidate and closest override
3453 public TypeSpec BestCandidateReturnType {
3455 return best_candidate_return_type;
3459 public IErrorHandler CustomErrors {
3461 return custom_errors;
3464 custom_errors = value;
3468 TypeSpec DelegateType {
3470 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3471 throw new InternalErrorException ("Not running in delegate mode", loc);
3473 return members [0].DeclaringType;
3477 bool IsProbingOnly {
3479 return (restrictions & Restrictions.ProbingOnly) != 0;
3483 bool IsDelegateInvoke {
3485 return (restrictions & Restrictions.DelegateInvoke) != 0;
3492 // 7.4.3.3 Better conversion from expression
3493 // Returns : 1 if a->p is better,
3494 // 2 if a->q is better,
3495 // 0 if neither is better
3497 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3499 TypeSpec argument_type = a.Type;
3502 // If argument is an anonymous function
3504 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3506 // p and q are delegate types or expression tree types
3508 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3509 if (q.MemberDefinition != p.MemberDefinition) {
3514 // Uwrap delegate from Expression<T>
3516 q = TypeManager.GetTypeArguments (q)[0];
3517 p = TypeManager.GetTypeArguments (p)[0];
3520 var p_m = Delegate.GetInvokeMethod (p);
3521 var q_m = Delegate.GetInvokeMethod (q);
3524 // With identical parameter lists
3526 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3533 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3535 if (p.Kind == MemberKind.Void) {
3536 return q.Kind != MemberKind.Void ? 2 : 0;
3540 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3542 if (q.Kind == MemberKind.Void) {
3543 return p.Kind != MemberKind.Void ? 1: 0;
3547 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3548 // better conversion is performed between underlying types Y1 and Y2
3550 if (p.IsGenericTask || q.IsGenericTask) {
3551 if (p.IsGenericTask != q.IsGenericTask) {
3555 var async_am = a.Expr as AnonymousMethodExpression;
3556 if (async_am == null || !async_am.IsAsync)
3559 q = q.TypeArguments[0];
3560 p = p.TypeArguments[0];
3564 // The parameters are identicial and return type is not void, use better type conversion
3565 // on return type to determine better one
3568 if (argument_type == p)
3571 if (argument_type == q)
3575 return BetterTypeConversion (ec, p, q);
3579 // 7.4.3.4 Better conversion from type
3581 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3583 if (p == null || q == null)
3584 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3586 switch (p.BuiltinType) {
3587 case BuiltinTypeSpec.Type.Int:
3588 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3591 case BuiltinTypeSpec.Type.Long:
3592 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3595 case BuiltinTypeSpec.Type.SByte:
3596 switch (q.BuiltinType) {
3597 case BuiltinTypeSpec.Type.Byte:
3598 case BuiltinTypeSpec.Type.UShort:
3599 case BuiltinTypeSpec.Type.UInt:
3600 case BuiltinTypeSpec.Type.ULong:
3604 case BuiltinTypeSpec.Type.Short:
3605 switch (q.BuiltinType) {
3606 case BuiltinTypeSpec.Type.UShort:
3607 case BuiltinTypeSpec.Type.UInt:
3608 case BuiltinTypeSpec.Type.ULong:
3612 case BuiltinTypeSpec.Type.Dynamic:
3613 // Dynamic is never better
3617 switch (q.BuiltinType) {
3618 case BuiltinTypeSpec.Type.Int:
3619 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3622 case BuiltinTypeSpec.Type.Long:
3623 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3626 case BuiltinTypeSpec.Type.SByte:
3627 switch (p.BuiltinType) {
3628 case BuiltinTypeSpec.Type.Byte:
3629 case BuiltinTypeSpec.Type.UShort:
3630 case BuiltinTypeSpec.Type.UInt:
3631 case BuiltinTypeSpec.Type.ULong:
3635 case BuiltinTypeSpec.Type.Short:
3636 switch (p.BuiltinType) {
3637 case BuiltinTypeSpec.Type.UShort:
3638 case BuiltinTypeSpec.Type.UInt:
3639 case BuiltinTypeSpec.Type.ULong:
3643 case BuiltinTypeSpec.Type.Dynamic:
3644 // Dynamic is never better
3648 // FIXME: handle lifted operators
3650 // TODO: this is expensive
3651 Expression p_tmp = new EmptyExpression (p);
3652 Expression q_tmp = new EmptyExpression (q);
3654 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3655 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3657 if (p_to_q && !q_to_p)
3660 if (q_to_p && !p_to_q)
3667 /// Determines "Better function" between candidate
3668 /// and the current best match
3671 /// Returns a boolean indicating :
3672 /// false if candidate ain't better
3673 /// true if candidate is better than the current best match
3675 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3676 MemberSpec best, AParametersCollection bparam, bool best_params)
3678 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3679 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3681 bool better_at_least_one = false;
3683 int args_count = args == null ? 0 : args.Count;
3687 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3690 // Default arguments are ignored for better decision
3691 if (a.IsDefaultArgument)
3695 // When comparing named argument the parameter type index has to be looked up
3696 // in original parameter set (override version for virtual members)
3698 NamedArgument na = a as NamedArgument;
3700 int idx = cparam.GetParameterIndexByName (na.Name);
3701 ct = candidate_pd.Types[idx];
3702 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3703 ct = TypeManager.GetElementType (ct);
3705 idx = bparam.GetParameterIndexByName (na.Name);
3706 bt = best_pd.Types[idx];
3707 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3708 bt = TypeManager.GetElementType (bt);
3710 ct = candidate_pd.Types[c_idx];
3711 bt = best_pd.Types[b_idx];
3713 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3714 ct = TypeManager.GetElementType (ct);
3718 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3719 bt = TypeManager.GetElementType (bt);
3724 if (TypeSpecComparer.IsEqual (ct, bt))
3728 int result = BetterExpressionConversion (ec, a, ct, bt);
3730 // for each argument, the conversion to 'ct' should be no worse than
3731 // the conversion to 'bt'.
3735 // for at least one argument, the conversion to 'ct' should be better than
3736 // the conversion to 'bt'.
3738 better_at_least_one = true;
3741 if (better_at_least_one)
3745 // This handles the case
3747 // Add (float f1, float f2, float f3);
3748 // Add (params decimal [] foo);
3750 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3751 // first candidate would've chosen as better.
3753 if (!same && !a.IsDefaultArgument)
3757 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3761 // This handles the following cases:
3763 // Foo (int i) is better than Foo (int i, long l = 0)
3764 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3766 // Prefer non-optional version
3768 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3770 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3771 if (candidate_pd.Count >= best_pd.Count)
3774 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3781 // One is a non-generic method and second is a generic method, then non-generic is better
3783 if (best.IsGeneric != candidate.IsGeneric)
3784 return best.IsGeneric;
3787 // This handles the following cases:
3789 // Trim () is better than Trim (params char[] chars)
3790 // Concat (string s1, string s2, string s3) is better than
3791 // Concat (string s1, params string [] srest)
3792 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3794 // Prefer non-expanded version
3796 if (candidate_params != best_params)
3799 int candidate_param_count = candidate_pd.Count;
3800 int best_param_count = best_pd.Count;
3802 if (candidate_param_count != best_param_count)
3803 // can only happen if (candidate_params && best_params)
3804 return candidate_param_count > best_param_count && best_pd.HasParams;
3807 // Both methods have the same number of parameters, and the parameters have equal types
3808 // Pick the "more specific" signature using rules over original (non-inflated) types
3810 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3811 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3813 bool specific_at_least_once = false;
3814 for (j = 0; j < args_count; ++j) {
3815 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3817 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3818 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3820 ct = candidate_def_pd.Types[j];
3821 bt = best_def_pd.Types[j];
3826 TypeSpec specific = MoreSpecific (ct, bt);
3830 specific_at_least_once = true;
3833 if (specific_at_least_once)
3839 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3841 rc.Report.Error (1729, loc,
3842 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3843 type.GetSignatureForError (), argCount.ToString ());
3847 // Determines if the candidate method is applicable to the given set of arguments
3848 // There could be two different set of parameters for same candidate where one
3849 // is the closest override for default values and named arguments checks and second
3850 // one being the virtual base for the parameter types and modifiers.
3852 // A return value rates candidate method compatibility,
3853 // 0 = the best, int.MaxValue = the worst
3855 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)
3857 // Parameters of most-derived type used mainly for named and optional parameters
3858 var pd = pm.Parameters;
3860 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3861 // params modifier instead of most-derived type
3862 var cpd = ((IParametersMember) candidate).Parameters;
3863 int param_count = pd.Count;
3864 int optional_count = 0;
3866 Arguments orig_args = arguments;
3868 if (arg_count != param_count) {
3869 for (int i = 0; i < pd.Count; ++i) {
3870 if (pd.FixedParameters[i].HasDefaultValue) {
3871 optional_count = pd.Count - i;
3876 if (optional_count != 0) {
3877 // Readjust expected number when params used
3878 if (cpd.HasParams) {
3880 if (arg_count < param_count)
3882 } else if (arg_count > param_count) {
3883 int args_gap = System.Math.Abs (arg_count - param_count);
3884 return int.MaxValue - 10000 + args_gap;
3886 } else if (arg_count != param_count) {
3887 int args_gap = System.Math.Abs (arg_count - param_count);
3889 return int.MaxValue - 10000 + args_gap;
3890 if (arg_count < param_count - 1)
3891 return int.MaxValue - 10000 + args_gap;
3894 // Resize to fit optional arguments
3895 if (optional_count != 0) {
3896 if (arguments == null) {
3897 arguments = new Arguments (optional_count);
3899 // Have to create a new container, so the next run can do same
3900 var resized = new Arguments (param_count);
3901 resized.AddRange (arguments);
3902 arguments = resized;
3905 for (int i = arg_count; i < param_count; ++i)
3906 arguments.Add (null);
3910 if (arg_count > 0) {
3912 // Shuffle named arguments to the right positions if there are any
3914 if (arguments[arg_count - 1] is NamedArgument) {
3915 arg_count = arguments.Count;
3917 for (int i = 0; i < arg_count; ++i) {
3918 bool arg_moved = false;
3920 NamedArgument na = arguments[i] as NamedArgument;
3924 int index = pd.GetParameterIndexByName (na.Name);
3926 // Named parameter not found
3930 // already reordered
3935 if (index >= param_count) {
3936 // When using parameters which should not be available to the user
3937 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3940 arguments.Add (null);
3944 temp = arguments[index];
3946 // The slot has been taken by positional argument
3947 if (temp != null && !(temp is NamedArgument))
3952 arguments = arguments.MarkOrderedArgument (na);
3956 arguments[index] = arguments[i];
3957 arguments[i] = temp;
3964 arg_count = arguments.Count;
3966 } else if (arguments != null) {
3967 arg_count = arguments.Count;
3971 // 1. Handle generic method using type arguments when specified or type inference
3974 var ms = candidate as MethodSpec;
3975 if (ms != null && ms.IsGeneric) {
3976 // Setup constraint checker for probing only
3977 ConstraintChecker cc = new ConstraintChecker (null);
3979 if (type_arguments != null) {
3980 var g_args_count = ms.Arity;
3981 if (g_args_count != type_arguments.Count)
3982 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3984 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3986 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3987 // for now it simplifies things. I should probably add a callback to ResolveContext
3988 if (lambda_conv_msgs == null) {
3989 lambda_conv_msgs = new SessionReportPrinter ();
3990 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3993 var ti = new TypeInference (arguments);
3994 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3995 lambda_conv_msgs.EndSession ();
3998 return ti.InferenceScore - 20000;
4000 if (i_args.Length != 0) {
4001 ms = ms.MakeGenericMethod (ec, i_args);
4004 cc.IgnoreInferredDynamic = true;
4008 // Type arguments constraints have to match for the method to be applicable
4010 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4012 return int.MaxValue - 25000;
4016 // We have a generic return type and at same time the method is override which
4017 // means we have to also inflate override return type in case the candidate is
4018 // best candidate and override return type is different to base return type.
4020 // virtual Foo<T, object> with override Foo<T, dynamic>
4022 if (candidate != pm) {
4023 MethodSpec override_ms = (MethodSpec) pm;
4024 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4025 returnType = inflator.Inflate (returnType);
4027 returnType = ms.ReturnType;
4031 ptypes = ms.Parameters.Types;
4033 if (type_arguments != null)
4034 return int.MaxValue - 15000;
4040 // 2. Each argument has to be implicitly convertible to method parameter
4042 Parameter.Modifier p_mod = 0;
4045 for (int i = 0; i < arg_count; i++) {
4046 Argument a = arguments[i];
4048 if (!pd.FixedParameters[i].HasDefaultValue) {
4049 arguments = orig_args;
4050 return arg_count * 2 + 2;
4054 // Get the default value expression, we can use the same expression
4055 // if the type matches
4057 Expression e = pd.FixedParameters[i].DefaultValue;
4058 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4060 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4062 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4063 e = new MemberAccess (new MemberAccess (new MemberAccess (
4064 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4066 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4072 arguments[i] = new Argument (e, Argument.AType.Default);
4076 if (p_mod != Parameter.Modifier.PARAMS) {
4077 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4079 } else if (!params_expanded_form) {
4080 params_expanded_form = true;
4081 pt = ((ElementTypeSpec) pt).Element;
4087 if (!params_expanded_form) {
4088 if (a.ArgType == Argument.AType.ExtensionType) {
4090 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4093 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4094 Convert.ImplicitReferenceConversionExists (at, pt) ||
4095 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4100 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4103 dynamicArgument = true;
4108 // It can be applicable in expanded form (when not doing exact match like for delegates)
4110 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4111 if (!params_expanded_form)
4112 pt = ((ElementTypeSpec) pt).Element;
4115 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4118 params_expanded_form = true;
4119 } else if (score < 0) {
4120 params_expanded_form = true;
4121 dynamicArgument = true;
4126 if (params_expanded_form)
4128 return (arg_count - i) * 2 + score;
4133 // When params parameter has no argument it will be provided later if the method is the best candidate
4135 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4136 params_expanded_form = true;
4139 // Restore original arguments for dynamic binder to keep the intention of original source code
4141 if (dynamicArgument)
4142 arguments = orig_args;
4148 // Tests argument compatibility with the parameter
4149 // The possible return values are
4151 // 1 - modifier mismatch
4152 // 2 - type mismatch
4153 // -1 - dynamic binding required
4155 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4158 // Types have to be identical when ref or out modifer
4159 // is used and argument is not of dynamic type
4161 if ((argument.Modifier | param_mod) != 0) {
4162 if (argument.Type != parameter) {
4164 // Do full equality check after quick path
4166 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4168 // Using dynamic for ref/out parameter can still succeed at runtime
4170 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4177 if (argument.Modifier != param_mod) {
4179 // Using dynamic for ref/out parameter can still succeed at runtime
4181 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4188 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4192 // Deploy custom error reporting for lambda methods. When probing lambda methods
4193 // keep all errors reported in separate set and once we are done and no best
4194 // candidate was found, this set is used to report more details about what was wrong
4197 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4198 if (lambda_conv_msgs == null) {
4199 lambda_conv_msgs = new SessionReportPrinter ();
4200 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4205 // Use implicit conversion in all modes to return same candidates when the expression
4206 // is used as argument or delegate conversion
4208 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4209 if (lambda_conv_msgs != null) {
4210 lambda_conv_msgs.EndSession ();
4220 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4222 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4224 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4227 var ac_p = p as ArrayContainer;
4229 var ac_q = ((ArrayContainer) q);
4230 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4231 if (specific == ac_p.Element)
4233 if (specific == ac_q.Element)
4235 } else if (TypeManager.IsGenericType (p)) {
4236 var pargs = TypeManager.GetTypeArguments (p);
4237 var qargs = TypeManager.GetTypeArguments (q);
4239 bool p_specific_at_least_once = false;
4240 bool q_specific_at_least_once = false;
4242 for (int i = 0; i < pargs.Length; i++) {
4243 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4244 if (specific == pargs[i])
4245 p_specific_at_least_once = true;
4246 if (specific == qargs[i])
4247 q_specific_at_least_once = true;
4250 if (p_specific_at_least_once && !q_specific_at_least_once)
4252 if (!p_specific_at_least_once && q_specific_at_least_once)
4260 // Find the best method from candidate list
4262 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4264 List<AmbiguousCandidate> ambiguous_candidates = null;
4266 MemberSpec best_candidate;
4267 Arguments best_candidate_args = null;
4268 bool best_candidate_params = false;
4269 bool best_candidate_dynamic = false;
4270 int best_candidate_rate;
4271 IParametersMember best_parameter_member = null;
4273 int args_count = args != null ? args.Count : 0;
4275 Arguments candidate_args = args;
4276 bool error_mode = false;
4277 MemberSpec invocable_member = null;
4279 // Be careful, cannot return until error reporter is restored
4281 best_candidate = null;
4282 best_candidate_rate = int.MaxValue;
4284 var type_members = members;
4288 for (int i = 0; i < type_members.Count; ++i) {
4289 var member = type_members[i];
4292 // Methods in a base class are not candidates if any method in a derived
4293 // class is applicable
4295 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4299 if (!member.IsAccessible (rc))
4302 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4306 IParametersMember pm = member as IParametersMember;
4309 // Will use it later to report ambiguity between best method and invocable member
4311 if (Invocation.IsMemberInvocable (member))
4312 invocable_member = member;
4318 // Overload resolution is looking for base member but using parameter names
4319 // and default values from the closest member. That means to do expensive lookup
4320 // for the closest override for virtual or abstract members
4322 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4323 var override_params = base_provider.GetOverrideMemberParameters (member);
4324 if (override_params != null)
4325 pm = override_params;
4329 // Check if the member candidate is applicable
4331 bool params_expanded_form = false;
4332 bool dynamic_argument = false;
4333 TypeSpec rt = pm.MemberType;
4334 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4337 // How does it score compare to others
4339 if (candidate_rate < best_candidate_rate) {
4340 best_candidate_rate = candidate_rate;
4341 best_candidate = member;
4342 best_candidate_args = candidate_args;
4343 best_candidate_params = params_expanded_form;
4344 best_candidate_dynamic = dynamic_argument;
4345 best_parameter_member = pm;
4346 best_candidate_return_type = rt;
4347 } else if (candidate_rate == 0) {
4349 // The member look is done per type for most operations but sometimes
4350 // it's not possible like for binary operators overload because they
4351 // are unioned between 2 sides
4353 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4354 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4359 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4361 // We pack all interface members into top level type which makes the overload resolution
4362 // more complicated for interfaces. We compensate it by removing methods with same
4363 // signature when building the cache hence this path should not really be hit often
4366 // interface IA { void Foo (int arg); }
4367 // interface IB : IA { void Foo (params int[] args); }
4369 // IB::Foo is the best overload when calling IB.Foo (1)
4372 if (ambiguous_candidates != null) {
4373 foreach (var amb_cand in ambiguous_candidates) {
4374 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4383 ambiguous_candidates = null;
4386 // Is the new candidate better
4387 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4391 best_candidate = member;
4392 best_candidate_args = candidate_args;
4393 best_candidate_params = params_expanded_form;
4394 best_candidate_dynamic = dynamic_argument;
4395 best_parameter_member = pm;
4396 best_candidate_return_type = rt;
4398 // It's not better but any other found later could be but we are not sure yet
4399 if (ambiguous_candidates == null)
4400 ambiguous_candidates = new List<AmbiguousCandidate> ();
4402 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4406 // Restore expanded arguments
4407 if (candidate_args != args)
4408 candidate_args = args;
4410 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4412 if (prev_recorder != null)
4413 rc.Report.SetPrinter (prev_recorder);
4417 // We've found exact match
4419 if (best_candidate_rate == 0)
4423 // Try extension methods lookup when no ordinary method match was found and provider enables it
4426 var emg = base_provider.LookupExtensionMethod (rc);
4428 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4430 best_candidate_extension_group = emg;
4431 return (T) (MemberSpec) emg.BestCandidate;
4436 // Don't run expensive error reporting mode for probing
4443 lambda_conv_msgs = null;
4448 // No best member match found, report an error
4450 if (best_candidate_rate != 0 || error_mode) {
4451 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4455 if (best_candidate_dynamic) {
4456 if (args[0].ArgType == Argument.AType.ExtensionType) {
4457 rc.Report.Error (1973, loc,
4458 "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",
4459 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4462 BestCandidateIsDynamic = true;
4467 // These flags indicates we are running delegate probing conversion. No need to
4468 // do more expensive checks
4470 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4471 return (T) best_candidate;
4473 if (ambiguous_candidates != null) {
4475 // Now check that there are no ambiguities i.e the selected method
4476 // should be better than all the others
4478 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4479 var candidate = ambiguous_candidates [ix];
4481 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4482 var ambiguous = candidate.Member;
4483 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4484 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4485 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4486 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4487 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4490 return (T) best_candidate;
4495 if (invocable_member != null) {
4496 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4497 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4498 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4499 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4503 // And now check if the arguments are all
4504 // compatible, perform conversions if
4505 // necessary etc. and return if everything is
4508 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4511 if (best_candidate == null)
4515 // Check ObsoleteAttribute on the best method
4517 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4518 if (oa != null && !rc.IsObsolete)
4519 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4521 var dep = best_candidate.GetMissingDependencies ();
4523 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4526 best_candidate.MemberDefinition.SetIsUsed ();
4528 args = best_candidate_args;
4529 return (T) best_candidate;
4532 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4534 return ResolveMember<MethodSpec> (rc, ref args);
4537 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4538 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4540 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4543 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4544 ec.Report.SymbolRelatedToPreviousError (method);
4545 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4546 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4547 TypeManager.CSharpSignature (method));
4550 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4551 TypeManager.CSharpSignature (method));
4552 } else if (IsDelegateInvoke) {
4553 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4554 DelegateType.GetSignatureForError ());
4556 ec.Report.SymbolRelatedToPreviousError (method);
4557 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4558 method.GetSignatureForError ());
4561 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4563 string index = (idx + 1).ToString ();
4564 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4565 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4566 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4567 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4568 index, Parameter.GetModifierSignature (a.Modifier));
4570 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4571 index, Parameter.GetModifierSignature (mod));
4572 } else if (a.Expr != ErrorExpression.Instance) {
4573 string p1 = a.GetSignatureForError ();
4574 string p2 = TypeManager.CSharpName (paramType);
4577 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4578 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4581 ec.Report.Error (1503, loc,
4582 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4587 // We have failed to find exact match so we return error info about the closest match
4589 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4591 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4592 int arg_count = args == null ? 0 : args.Count;
4594 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4595 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4596 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4600 if (lambda_conv_msgs != null) {
4601 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4606 // For candidates which match on parameters count report more details about incorrect arguments
4609 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4610 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4611 // Reject any inaccessible member
4612 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4613 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4614 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4618 var ms = best_candidate as MethodSpec;
4619 if (ms != null && ms.IsGeneric) {
4620 bool constr_ok = true;
4621 if (ms.TypeArguments != null)
4622 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4624 if (ta_count == 0) {
4625 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4629 rc.Report.Error (411, loc,
4630 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4631 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4638 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4644 // We failed to find any method with correct argument count, report best candidate
4646 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4649 if (best_candidate.Kind == MemberKind.Constructor) {
4650 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4651 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4652 } else if (IsDelegateInvoke) {
4653 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4654 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4655 DelegateType.GetSignatureForError (), arg_count.ToString ());
4657 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4658 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4659 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4660 name, arg_count.ToString ());
4664 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4666 var pd = pm.Parameters;
4667 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4669 Parameter.Modifier p_mod = 0;
4671 int a_idx = 0, a_pos = 0;
4673 ArrayInitializer params_initializers = null;
4674 bool has_unsafe_arg = pm.MemberType.IsPointer;
4675 int arg_count = args == null ? 0 : args.Count;
4677 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4679 if (p_mod != Parameter.Modifier.PARAMS) {
4680 p_mod = pd.FixedParameters[a_idx].ModFlags;
4682 has_unsafe_arg |= pt.IsPointer;
4684 if (p_mod == Parameter.Modifier.PARAMS) {
4685 if (chose_params_expanded) {
4686 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4687 pt = TypeManager.GetElementType (pt);
4693 // Types have to be identical when ref or out modifer is used
4695 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4696 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4699 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4705 NamedArgument na = a as NamedArgument;
4707 int name_index = pd.GetParameterIndexByName (na.Name);
4708 if (name_index < 0 || name_index >= pd.Count) {
4709 if (IsDelegateInvoke) {
4710 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4711 ec.Report.Error (1746, na.Location,
4712 "The delegate `{0}' does not contain a parameter named `{1}'",
4713 DelegateType.GetSignatureForError (), na.Name);
4715 ec.Report.SymbolRelatedToPreviousError (member);
4716 ec.Report.Error (1739, na.Location,
4717 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4718 TypeManager.CSharpSignature (member), na.Name);
4720 } else if (args[name_index] != a) {
4721 if (IsDelegateInvoke)
4722 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4724 ec.Report.SymbolRelatedToPreviousError (member);
4726 ec.Report.Error (1744, na.Location,
4727 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4732 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4735 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4736 custom_errors.NoArgumentMatch (ec, member);
4740 Expression conv = null;
4741 if (a.ArgType == Argument.AType.ExtensionType) {
4742 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4745 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4747 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4750 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4757 // Convert params arguments to an array initializer
4759 if (params_initializers != null) {
4760 // we choose to use 'a.Expr' rather than 'conv' so that
4761 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4762 params_initializers.Add (a.Expr);
4763 args.RemoveAt (a_idx--);
4768 // Update the argument with the implicit conversion
4772 if (a_idx != arg_count) {
4773 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4778 // Fill not provided arguments required by params modifier
4780 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4782 args = new Arguments (1);
4784 pt = ptypes[pd.Count - 1];
4785 pt = TypeManager.GetElementType (pt);
4786 has_unsafe_arg |= pt.IsPointer;
4787 params_initializers = new ArrayInitializer (0, loc);
4791 // Append an array argument with all params arguments
4793 if (params_initializers != null) {
4794 args.Add (new Argument (
4795 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4799 if (has_unsafe_arg && !ec.IsUnsafe) {
4800 Expression.UnsafeError (ec, loc);
4804 // We could infer inaccesible type arguments
4806 if (type_arguments == null && member.IsGeneric) {
4807 var ms = (MethodSpec) member;
4808 foreach (var ta in ms.TypeArguments) {
4809 if (!ta.IsAccessible (ec)) {
4810 ec.Report.SymbolRelatedToPreviousError (ta);
4811 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4821 public class ConstantExpr : MemberExpr
4823 readonly ConstSpec constant;
4825 public ConstantExpr (ConstSpec constant, Location loc)
4827 this.constant = constant;
4831 public override string Name {
4832 get { throw new NotImplementedException (); }
4835 public override bool IsInstance {
4836 get { return !IsStatic; }
4839 public override bool IsStatic {
4840 get { return true; }
4843 protected override TypeSpec DeclaringType {
4844 get { return constant.DeclaringType; }
4847 public override Expression CreateExpressionTree (ResolveContext ec)
4849 throw new NotSupportedException ("ET");
4852 protected override Expression DoResolve (ResolveContext rc)
4854 ResolveInstanceExpression (rc, null);
4855 DoBestMemberChecks (rc, constant);
4857 var c = constant.GetConstant (rc);
4859 // Creates reference expression to the constant value
4860 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4863 public override void Emit (EmitContext ec)
4865 throw new NotSupportedException ();
4868 public override string GetSignatureForError ()
4870 return constant.GetSignatureForError ();
4873 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4875 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4880 // Fully resolved expression that references a Field
4882 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
4884 protected FieldSpec spec;
4885 VariableInfo variable_info;
4887 LocalTemporary temp;
4890 protected FieldExpr (Location l)
4895 public FieldExpr (FieldSpec spec, Location loc)
4900 type = spec.MemberType;
4903 public FieldExpr (FieldBase fi, Location l)
4910 public override string Name {
4916 public bool IsHoisted {
4918 IVariableReference hv = InstanceExpression as IVariableReference;
4919 return hv != null && hv.IsHoisted;
4923 public override bool IsInstance {
4925 return !spec.IsStatic;
4929 public override bool IsStatic {
4931 return spec.IsStatic;
4935 public FieldSpec Spec {
4941 protected override TypeSpec DeclaringType {
4943 return spec.DeclaringType;
4947 public VariableInfo VariableInfo {
4949 return variable_info;
4955 public override string GetSignatureForError ()
4957 return TypeManager.GetFullNameSignature (spec);
4960 public bool IsMarshalByRefAccess (ResolveContext rc)
4962 // Checks possible ldflda of field access expression
4963 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
4964 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
4965 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
4968 public void SetHasAddressTaken ()
4970 IVariableReference vr = InstanceExpression as IVariableReference;
4972 vr.SetHasAddressTaken ();
4975 public override Expression CreateExpressionTree (ResolveContext ec)
4977 Expression instance;
4978 if (InstanceExpression == null) {
4979 instance = new NullLiteral (loc);
4981 instance = InstanceExpression.CreateExpressionTree (ec);
4984 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4986 CreateTypeOfExpression ());
4988 return CreateExpressionFactoryCall (ec, "Field", args);
4991 public Expression CreateTypeOfExpression ()
4993 return new TypeOfField (spec, loc);
4996 protected override Expression DoResolve (ResolveContext ec)
4998 return DoResolve (ec, null);
5001 Expression DoResolve (ResolveContext ec, Expression rhs)
5003 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5006 if (ResolveInstanceExpression (ec, rhs)) {
5007 // Resolve the field's instance expression while flow analysis is turned
5008 // off: when accessing a field "a.b", we must check whether the field
5009 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5011 if (lvalue_instance) {
5012 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5013 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5015 Expression right_side =
5016 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5018 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5021 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5022 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5026 if (InstanceExpression == null)
5030 DoBestMemberChecks (ec, spec);
5033 var fb = spec as FixedFieldSpec;
5034 IVariableReference var = InstanceExpression as IVariableReference;
5036 if (lvalue_instance && var != null && var.VariableInfo != null) {
5037 var.VariableInfo.SetFieldAssigned (ec, Name);
5041 IFixedExpression fe = InstanceExpression as IFixedExpression;
5042 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5043 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5046 if (InstanceExpression.eclass != ExprClass.Variable) {
5047 ec.Report.SymbolRelatedToPreviousError (spec);
5048 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5049 TypeManager.GetFullNameSignature (spec));
5050 } else if (var != null && var.IsHoisted) {
5051 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5054 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5057 eclass = ExprClass.Variable;
5059 // If the instance expression is a local variable or parameter.
5060 if (var == null || var.VariableInfo == null)
5063 VariableInfo vi = var.VariableInfo;
5064 if (!vi.IsFieldAssigned (ec, Name, loc))
5067 variable_info = vi.GetSubStruct (Name);
5071 static readonly int [] codes = {
5072 191, // instance, write access
5073 192, // instance, out access
5074 198, // static, write access
5075 199, // static, out access
5076 1648, // member of value instance, write access
5077 1649, // member of value instance, out access
5078 1650, // member of value static, write access
5079 1651 // member of value static, out access
5082 static readonly string [] msgs = {
5083 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5084 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5085 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5086 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5087 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5088 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5089 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5090 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5093 // The return value is always null. Returning a value simplifies calling code.
5094 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5097 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5101 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5103 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5108 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5110 Expression e = DoResolve (ec, right_side);
5115 spec.MemberDefinition.SetIsAssigned ();
5117 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5118 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5119 ec.Report.Warning (420, 1, loc,
5120 "`{0}': A volatile field references will not be treated as volatile",
5121 spec.GetSignatureForError ());
5124 if (spec.IsReadOnly) {
5125 // InitOnly fields can only be assigned in constructors or initializers
5126 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5127 return Report_AssignToReadonly (ec, right_side);
5129 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5131 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5132 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5133 return Report_AssignToReadonly (ec, right_side);
5134 // static InitOnly fields cannot be assigned-to in an instance constructor
5135 if (IsStatic && !ec.IsStatic)
5136 return Report_AssignToReadonly (ec, right_side);
5137 // instance constructors can't modify InitOnly fields of other instances of the same type
5138 if (!IsStatic && !(InstanceExpression is This))
5139 return Report_AssignToReadonly (ec, right_side);
5143 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5144 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5145 ec.Report.Warning (197, 1, loc,
5146 "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",
5147 GetSignatureForError ());
5150 eclass = ExprClass.Variable;
5154 public override int GetHashCode ()
5156 return spec.GetHashCode ();
5159 public bool IsFixed {
5162 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5164 IVariableReference variable = InstanceExpression as IVariableReference;
5165 if (variable != null)
5166 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5168 IFixedExpression fe = InstanceExpression as IFixedExpression;
5169 return fe != null && fe.IsFixed;
5173 public override bool Equals (object obj)
5175 FieldExpr fe = obj as FieldExpr;
5179 if (spec != fe.spec)
5182 if (InstanceExpression == null || fe.InstanceExpression == null)
5185 return InstanceExpression.Equals (fe.InstanceExpression);
5188 public void Emit (EmitContext ec, bool leave_copy)
5190 bool is_volatile = false;
5192 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5195 spec.MemberDefinition.SetIsUsed ();
5199 ec.Emit (OpCodes.Volatile);
5201 ec.Emit (OpCodes.Ldsfld, spec);
5204 EmitInstance (ec, false);
5206 // Optimization for build-in types
5207 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5208 ec.EmitLoadFromPtr (type);
5210 var ff = spec as FixedFieldSpec;
5212 ec.Emit (OpCodes.Ldflda, spec);
5213 ec.Emit (OpCodes.Ldflda, ff.Element);
5216 ec.Emit (OpCodes.Volatile);
5218 ec.Emit (OpCodes.Ldfld, spec);
5224 ec.Emit (OpCodes.Dup);
5226 temp = new LocalTemporary (this.Type);
5232 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5234 if (ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ()) {
5235 source = source.EmitToField (ec);
5238 prepared = isCompound && !(source is DynamicExpressionStatement);
5240 EmitInstance (ec, prepared);
5245 ec.Emit (OpCodes.Dup);
5247 temp = new LocalTemporary (this.Type);
5252 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5253 ec.Emit (OpCodes.Volatile);
5255 spec.MemberDefinition.SetIsAssigned ();
5258 ec.Emit (OpCodes.Stsfld, spec);
5260 ec.Emit (OpCodes.Stfld, spec);
5270 // Emits store to field with prepared values on stack
5272 public void EmitAssignFromStack (EmitContext ec)
5275 ec.Emit (OpCodes.Stsfld, spec);
5277 ec.Emit (OpCodes.Stfld, spec);
5281 public override void Emit (EmitContext ec)
5286 public override void EmitSideEffect (EmitContext ec)
5288 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5290 if (is_volatile) // || is_marshal_by_ref ())
5291 base.EmitSideEffect (ec);
5294 public void AddressOf (EmitContext ec, AddressOp mode)
5296 if ((mode & AddressOp.Store) != 0)
5297 spec.MemberDefinition.SetIsAssigned ();
5298 if ((mode & AddressOp.Load) != 0)
5299 spec.MemberDefinition.SetIsUsed ();
5302 // Handle initonly fields specially: make a copy and then
5303 // get the address of the copy.
5306 if (spec.IsReadOnly){
5308 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5320 var temp = ec.GetTemporaryLocal (type);
5321 ec.Emit (OpCodes.Stloc, temp, type);
5322 ec.Emit (OpCodes.Ldloca, temp, type);
5323 ec.FreeTemporaryLocal (temp, type);
5329 ec.Emit (OpCodes.Ldsflda, spec);
5332 EmitInstance (ec, false);
5333 ec.Emit (OpCodes.Ldflda, spec);
5337 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5339 return MakeExpression (ctx);
5342 public override SLE.Expression MakeExpression (BuilderContext ctx)
5345 return base.MakeExpression (ctx);
5347 return SLE.Expression.Field (
5348 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5349 spec.GetMetaInfo ());
5353 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5355 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5361 // Expression that evaluates to a Property.
5363 // This is not an LValue because we need to re-write the expression. We
5364 // can not take data from the stack and store it.
5366 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5368 public PropertyExpr (PropertySpec spec, Location l)
5371 best_candidate = spec;
5372 type = spec.MemberType;
5377 protected override Arguments Arguments {
5385 protected override TypeSpec DeclaringType {
5387 return best_candidate.DeclaringType;
5391 public override string Name {
5393 return best_candidate.Name;
5397 public override bool IsInstance {
5403 public override bool IsStatic {
5405 return best_candidate.IsStatic;
5409 public PropertySpec PropertyInfo {
5411 return best_candidate;
5417 public override Expression CreateExpressionTree (ResolveContext ec)
5420 if (IsSingleDimensionalArrayLength ()) {
5421 args = new Arguments (1);
5422 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5423 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5426 args = new Arguments (2);
5427 if (InstanceExpression == null)
5428 args.Add (new Argument (new NullLiteral (loc)));
5430 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5431 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5432 return CreateExpressionFactoryCall (ec, "Property", args);
5435 public Expression CreateSetterTypeOfExpression ()
5437 return new TypeOfMethod (Setter, loc);
5440 public override string GetSignatureForError ()
5442 return best_candidate.GetSignatureForError ();
5445 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5448 return base.MakeExpression (ctx);
5450 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5454 public override SLE.Expression MakeExpression (BuilderContext ctx)
5457 return base.MakeExpression (ctx);
5459 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5463 void Error_PropertyNotValid (ResolveContext ec)
5465 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5466 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5467 GetSignatureForError ());
5470 bool IsSingleDimensionalArrayLength ()
5472 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5475 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5476 return ac != null && ac.Rank == 1;
5479 public override void Emit (EmitContext ec, bool leave_copy)
5482 // Special case: length of single dimension array property is turned into ldlen
5484 if (IsSingleDimensionalArrayLength ()) {
5485 EmitInstance (ec, false);
5486 ec.Emit (OpCodes.Ldlen);
5487 ec.Emit (OpCodes.Conv_I4);
5491 base.Emit (ec, leave_copy);
5494 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5497 LocalTemporary await_source_arg = null;
5499 if (isCompound && !(source is DynamicExpressionStatement)) {
5500 emitting_compound_assignment = true;
5503 if (has_await_arguments) {
5504 await_source_arg = new LocalTemporary (Type);
5505 await_source_arg.Store (ec);
5507 args = new Arguments (1);
5508 args.Add (new Argument (await_source_arg));
5511 temp = await_source_arg;
5514 has_await_arguments = false;
5519 ec.Emit (OpCodes.Dup);
5520 temp = new LocalTemporary (this.Type);
5525 args = new Arguments (1);
5529 temp = new LocalTemporary (this.Type);
5531 args.Add (new Argument (temp));
5533 args.Add (new Argument (source));
5537 emitting_compound_assignment = false;
5539 var call = new CallEmitter ();
5540 call.InstanceExpression = InstanceExpression;
5542 call.InstanceExpressionOnStack = true;
5544 call.Emit (ec, Setter, args, loc);
5551 if (await_source_arg != null) {
5552 await_source_arg.Release (ec);
5556 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5558 eclass = ExprClass.PropertyAccess;
5560 if (best_candidate.IsNotCSharpCompatible) {
5561 Error_PropertyNotValid (rc);
5564 ResolveInstanceExpression (rc, right_side);
5566 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5567 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5568 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5570 type = p.MemberType;
5574 DoBestMemberChecks (rc, best_candidate);
5578 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5580 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5584 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5586 // getter and setter can be different for base calls
5587 MethodSpec getter, setter;
5588 protected T best_candidate;
5590 protected LocalTemporary temp;
5591 protected bool emitting_compound_assignment;
5592 protected bool has_await_arguments;
5594 protected PropertyOrIndexerExpr (Location l)
5601 protected abstract Arguments Arguments { get; set; }
5603 public MethodSpec Getter {
5612 public MethodSpec Setter {
5623 protected override Expression DoResolve (ResolveContext ec)
5625 if (eclass == ExprClass.Unresolved) {
5626 var expr = OverloadResolve (ec, null);
5631 return expr.Resolve (ec);
5634 if (!ResolveGetter (ec))
5640 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5642 if (right_side == EmptyExpression.OutAccess) {
5643 // TODO: best_candidate can be null at this point
5644 INamedBlockVariable variable = null;
5645 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5646 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5647 best_candidate.Name);
5649 right_side.DoResolveLValue (ec, this);
5654 // if the property/indexer returns a value type, and we try to set a field in it
5655 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5656 Error_CannotModifyIntermediateExpressionValue (ec);
5659 if (eclass == ExprClass.Unresolved) {
5660 var expr = OverloadResolve (ec, right_side);
5665 return expr.ResolveLValue (ec, right_side);
5668 if (!ResolveSetter (ec))
5675 // Implements the IAssignMethod interface for assignments
5677 public virtual void Emit (EmitContext ec, bool leave_copy)
5679 var call = new CallEmitter ();
5680 call.InstanceExpression = InstanceExpression;
5681 if (has_await_arguments)
5682 call.HasAwaitArguments = true;
5684 call.DuplicateArguments = emitting_compound_assignment;
5686 call.Emit (ec, Getter, Arguments, loc);
5688 if (call.HasAwaitArguments) {
5689 InstanceExpression = call.InstanceExpression;
5690 Arguments = call.EmittedArguments;
5691 has_await_arguments = true;
5695 ec.Emit (OpCodes.Dup);
5696 temp = new LocalTemporary (Type);
5701 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5703 public override void Emit (EmitContext ec)
5708 protected override void EmitToFieldSource (EmitContext ec)
5710 has_await_arguments = true;
5714 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5716 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5718 bool ResolveGetter (ResolveContext rc)
5720 if (!best_candidate.HasGet) {
5721 if (InstanceExpression != EmptyExpression.Null) {
5722 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5723 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5724 best_candidate.GetSignatureForError ());
5727 } else if (!best_candidate.Get.IsAccessible (rc)) {
5728 if (best_candidate.HasDifferentAccessibility) {
5729 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5730 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5731 TypeManager.CSharpSignature (best_candidate));
5733 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5734 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5738 if (best_candidate.HasDifferentAccessibility) {
5739 CheckProtectedMemberAccess (rc, best_candidate.Get);
5742 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5746 bool ResolveSetter (ResolveContext rc)
5748 if (!best_candidate.HasSet) {
5749 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5750 GetSignatureForError ());
5754 if (!best_candidate.Set.IsAccessible (rc)) {
5755 if (best_candidate.HasDifferentAccessibility) {
5756 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5757 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5758 GetSignatureForError ());
5760 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5761 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5765 if (best_candidate.HasDifferentAccessibility)
5766 CheckProtectedMemberAccess (rc, best_candidate.Set);
5768 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5774 /// Fully resolved expression that evaluates to an Event
5776 public class EventExpr : MemberExpr, IAssignMethod
5778 readonly EventSpec spec;
5781 public EventExpr (EventSpec spec, Location loc)
5789 protected override TypeSpec DeclaringType {
5791 return spec.DeclaringType;
5795 public override string Name {
5801 public override bool IsInstance {
5803 return !spec.IsStatic;
5807 public override bool IsStatic {
5809 return spec.IsStatic;
5813 public MethodSpec Operator {
5821 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5824 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5826 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5827 if (spec.BackingField != null &&
5828 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5830 spec.MemberDefinition.SetIsUsed ();
5832 if (!ec.IsObsolete) {
5833 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5835 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5838 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5839 Error_AssignmentEventOnly (ec);
5841 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5843 InstanceExpression = null;
5845 return ml.ResolveMemberAccess (ec, left, original);
5849 return base.ResolveMemberAccess (ec, left, original);
5852 public override Expression CreateExpressionTree (ResolveContext ec)
5854 throw new NotSupportedException ("ET");
5857 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5859 if (right_side == EmptyExpression.EventAddition) {
5860 op = spec.AccessorAdd;
5861 } else if (right_side == EmptyExpression.EventSubtraction) {
5862 op = spec.AccessorRemove;
5866 Error_AssignmentEventOnly (ec);
5870 op = CandidateToBaseOverride (ec, op);
5874 protected override Expression DoResolve (ResolveContext ec)
5876 eclass = ExprClass.EventAccess;
5877 type = spec.MemberType;
5879 ResolveInstanceExpression (ec, null);
5881 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5882 Error_AssignmentEventOnly (ec);
5885 DoBestMemberChecks (ec, spec);
5889 public override void Emit (EmitContext ec)
5891 throw new NotSupportedException ();
5892 //Error_CannotAssign ();
5895 #region IAssignMethod Members
5897 public void Emit (EmitContext ec, bool leave_copy)
5899 throw new NotImplementedException ();
5902 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5904 if (leave_copy || !isCompound)
5905 throw new NotImplementedException ("EventExpr::EmitAssign");
5907 Arguments args = new Arguments (1);
5908 args.Add (new Argument (source));
5910 var call = new CallEmitter ();
5911 call.InstanceExpression = InstanceExpression;
5912 call.Emit (ec, op, args, loc);
5917 void Error_AssignmentEventOnly (ResolveContext ec)
5919 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5920 ec.Report.Error (79, loc,
5921 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5922 GetSignatureForError ());
5924 ec.Report.Error (70, loc,
5925 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5926 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5930 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5932 name = name.Substring (0, name.LastIndexOf ('.'));
5933 base.Error_CannotCallAbstractBase (rc, name);
5936 public override string GetSignatureForError ()
5938 return TypeManager.CSharpSignature (spec);
5941 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5943 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
5947 public class TemporaryVariableReference : VariableReference
5949 public class Declarator : Statement
5951 TemporaryVariableReference variable;
5953 public Declarator (TemporaryVariableReference variable)
5955 this.variable = variable;
5959 protected override void DoEmit (EmitContext ec)
5961 variable.li.CreateBuilder (ec);
5964 protected override void CloneTo (CloneContext clonectx, Statement target)
5972 public TemporaryVariableReference (LocalVariable li, Location loc)
5975 this.type = li.Type;
5979 public override bool IsLockedByStatement {
5987 public LocalVariable LocalInfo {
5993 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5995 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5996 return new TemporaryVariableReference (li, loc);
5999 public override Expression CreateExpressionTree (ResolveContext ec)
6001 throw new NotSupportedException ("ET");
6004 protected override Expression DoResolve (ResolveContext ec)
6006 eclass = ExprClass.Variable;
6009 // Don't capture temporary variables except when using
6010 // iterator redirection
6012 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6013 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6014 storey.CaptureLocalVariable (ec, li);
6020 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6022 return Resolve (ec);
6025 public override void Emit (EmitContext ec)
6027 li.CreateBuilder (ec);
6032 public void EmitAssign (EmitContext ec, Expression source)
6034 li.CreateBuilder (ec);
6036 EmitAssign (ec, source, false, false);
6039 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6041 return li.HoistedVariant;
6044 public override bool IsFixed {
6045 get { return true; }
6048 public override bool IsRef {
6049 get { return false; }
6052 public override string Name {
6053 get { throw new NotImplementedException (); }
6056 public override void SetHasAddressTaken ()
6058 throw new NotImplementedException ();
6061 protected override ILocalVariable Variable {
6065 public override VariableInfo VariableInfo {
6066 get { throw new NotImplementedException (); }
6071 /// Handles `var' contextual keyword; var becomes a keyword only
6072 /// if no type called var exists in a variable scope
6074 class VarExpr : SimpleName
6076 public VarExpr (Location loc)
6081 public bool InferType (ResolveContext ec, Expression right_side)
6084 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6086 type = right_side.Type;
6087 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6088 ec.Report.Error (815, loc,
6089 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6090 type.GetSignatureForError ());
6094 eclass = ExprClass.Variable;
6098 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6100 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6101 base.Error_TypeOrNamespaceNotFound (ec);
6103 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");