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 bool contains_await = false;
553 for (int i = 1; i < expressions.Count; ++i) {
554 if (expressions[i].ContainsEmitWithAwait ()) {
555 contains_await = true;
560 if (contains_await) {
561 for (int i = 0; i < expressions.Count; ++i) {
562 expressions [i] = expressions[i].EmitToField (ec);
566 for (int i = 0; i < expressions.Count; ++i) {
567 expressions[i].Emit (ec);
572 /// Protected constructor. Only derivate types should
573 /// be able to be created
576 protected Expression ()
581 /// Returns a fully formed expression after a MemberLookup
584 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
586 if (spec is EventSpec)
587 return new EventExpr ((EventSpec) spec, loc);
588 if (spec is ConstSpec)
589 return new ConstantExpr ((ConstSpec) spec, loc);
590 if (spec is FieldSpec)
591 return new FieldExpr ((FieldSpec) spec, loc);
592 if (spec is PropertySpec)
593 return new PropertyExpr ((PropertySpec) spec, loc);
594 if (spec is TypeSpec)
595 return new TypeExpression (((TypeSpec) spec), loc);
600 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
602 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
604 rc.Report.SymbolRelatedToPreviousError (type);
606 // Report meaningful error for struct as they always have default ctor in C# context
607 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
609 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
610 type.GetSignatureForError ());
616 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
617 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
621 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
622 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
629 public enum MemberLookupRestrictions
638 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
639 // `qualifier_type' or null to lookup members in the current class.
641 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
643 var members = MemberCache.FindMembers (queried_type, name, false);
647 MemberSpec non_method = null;
648 MemberSpec ambig_non_method = null;
650 for (int i = 0; i < members.Count; ++i) {
651 var member = members[i];
653 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
654 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
657 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
661 if (!member.IsAccessible (rc))
665 // With runtime binder we can have a situation where queried type is inaccessible
666 // because it came via dynamic object, the check about inconsisted accessibility
667 // had no effect as the type was unknown during compilation
670 // private class N { }
672 // public dynamic Foo ()
678 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
682 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
683 if (member is MethodSpec)
684 return new MethodGroupExpr (members, queried_type, loc);
686 if (!Invocation.IsMemberInvocable (member))
690 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
692 } else if (!errorMode && !member.IsNotCSharpCompatible) {
693 ambig_non_method = member;
697 if (non_method != null) {
698 if (ambig_non_method != null && rc != null) {
699 var report = rc.Module.Compiler.Report;
700 report.SymbolRelatedToPreviousError (non_method);
701 report.SymbolRelatedToPreviousError (ambig_non_method);
702 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
703 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
706 if (non_method is MethodSpec)
707 return new MethodGroupExpr (members, queried_type, loc);
709 return ExprClassFromMemberInfo (non_method, loc);
712 if (members[0].DeclaringType.BaseType == null)
715 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
717 } while (members != null);
722 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
724 throw new NotImplementedException ();
727 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
729 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
733 /// Returns an expression that can be used to invoke operator true
734 /// on the expression if it exists.
736 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
738 return GetOperatorTrueOrFalse (ec, e, true, loc);
742 /// Returns an expression that can be used to invoke operator false
743 /// on the expression if it exists.
745 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
747 return GetOperatorTrueOrFalse (ec, e, false, loc);
750 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
752 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
753 var methods = MemberCache.GetUserOperator (e.type, op, false);
757 Arguments arguments = new Arguments (1);
758 arguments.Add (new Argument (e));
760 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
761 var oper = res.ResolveOperator (ec, ref arguments);
766 return new UserOperatorCall (oper, arguments, null, loc);
769 public virtual string ExprClassName
773 case ExprClass.Unresolved:
775 case ExprClass.Value:
777 case ExprClass.Variable:
779 case ExprClass.Namespace:
783 case ExprClass.MethodGroup:
784 return "method group";
785 case ExprClass.PropertyAccess:
786 return "property access";
787 case ExprClass.EventAccess:
788 return "event access";
789 case ExprClass.IndexerAccess:
790 return "indexer access";
791 case ExprClass.Nothing:
793 case ExprClass.TypeParameter:
794 return "type parameter";
796 throw new Exception ("Should not happen");
801 /// Reports that we were expecting `expr' to be of class `expected'
803 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
805 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
808 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
812 name = mc.GetSignatureForError ();
814 name = GetSignatureForError ();
816 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
817 name, was, expected);
820 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
822 string [] valid = new string [4];
825 if ((flags & ResolveFlags.VariableOrValue) != 0) {
826 valid [count++] = "variable";
827 valid [count++] = "value";
830 if ((flags & ResolveFlags.Type) != 0)
831 valid [count++] = "type";
833 if ((flags & ResolveFlags.MethodGroup) != 0)
834 valid [count++] = "method group";
837 valid [count++] = "unknown";
839 StringBuilder sb = new StringBuilder (valid [0]);
840 for (int i = 1; i < count - 1; i++) {
842 sb.Append (valid [i]);
845 sb.Append ("' or `");
846 sb.Append (valid [count - 1]);
849 ec.Report.Error (119, loc,
850 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
853 public static void UnsafeError (ResolveContext ec, Location loc)
855 UnsafeError (ec.Report, loc);
858 public static void UnsafeError (Report Report, Location loc)
860 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
863 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
865 ec.Report.SymbolRelatedToPreviousError (type);
866 if (ec.CurrentInitializerVariable != null) {
867 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
868 TypeManager.CSharpName (type), GetSignatureForError ());
870 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
871 GetSignatureForError ());
876 // Converts `source' to an int, uint, long or ulong.
878 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
880 var btypes = ec.BuiltinTypes;
882 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
883 Arguments args = new Arguments (1);
884 args.Add (new Argument (source));
885 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
888 Expression converted;
890 using (ec.Set (ResolveContext.Options.CheckedScope)) {
891 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
892 if (converted == null)
893 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
894 if (converted == null)
895 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
896 if (converted == null)
897 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
899 if (converted == null) {
900 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
906 // Only positive constants are allowed at compile time
908 Constant c = converted as Constant;
909 if (c != null && c.IsNegative)
910 Error_NegativeArrayIndex (ec, source.loc);
912 // No conversion needed to array index
913 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
916 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
920 // Derived classes implement this method by cloning the fields that
921 // could become altered during the Resolve stage
923 // Only expressions that are created for the parser need to implement
926 protected virtual void CloneTo (CloneContext clonectx, Expression target)
928 throw new NotImplementedException (
930 "CloneTo not implemented for expression {0}", this.GetType ()));
934 // Clones an expression created by the parser.
936 // We only support expressions created by the parser so far, not
937 // expressions that have been resolved (many more classes would need
938 // to implement CloneTo).
940 // This infrastructure is here merely for Lambda expressions which
941 // compile the same code using different type values for the same
942 // arguments to find the correct overload
944 public virtual Expression Clone (CloneContext clonectx)
946 Expression cloned = (Expression) MemberwiseClone ();
947 CloneTo (clonectx, cloned);
953 // Implementation of expression to expression tree conversion
955 public abstract Expression CreateExpressionTree (ResolveContext ec);
957 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
959 return CreateExpressionFactoryCall (ec, name, null, args, loc);
962 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
964 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
967 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
969 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
972 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
974 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
978 return new TypeExpression (t, loc);
982 // Implemented by all expressions which support conversion from
983 // compiler expression to invokable runtime expression. Used by
984 // dynamic C# binder.
986 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
988 throw new NotImplementedException ("MakeExpression for " + GetType ());
993 /// This is just a base class for expressions that can
994 /// appear on statements (invocations, object creation,
995 /// assignments, post/pre increment and decrement). The idea
996 /// being that they would support an extra Emition interface that
997 /// does not leave a result on the stack.
999 public abstract class ExpressionStatement : Expression {
1001 public ExpressionStatement ResolveStatement (BlockContext ec)
1003 Expression e = Resolve (ec);
1007 ExpressionStatement es = e as ExpressionStatement;
1009 Error_InvalidExpressionStatement (ec);
1015 /// Requests the expression to be emitted in a `statement'
1016 /// context. This means that no new value is left on the
1017 /// stack after invoking this method (constrasted with
1018 /// Emit that will always leave a value on the stack).
1020 public abstract void EmitStatement (EmitContext ec);
1022 public override void EmitSideEffect (EmitContext ec)
1029 /// This kind of cast is used to encapsulate the child
1030 /// whose type is child.Type into an expression that is
1031 /// reported to return "return_type". This is used to encapsulate
1032 /// expressions which have compatible types, but need to be dealt
1033 /// at higher levels with.
1035 /// For example, a "byte" expression could be encapsulated in one
1036 /// of these as an "unsigned int". The type for the expression
1037 /// would be "unsigned int".
1040 public abstract class TypeCast : Expression
1042 protected readonly Expression child;
1044 protected TypeCast (Expression child, TypeSpec return_type)
1046 eclass = child.eclass;
1047 loc = child.Location;
1052 public Expression Child {
1058 public override bool ContainsEmitWithAwait ()
1060 return child.ContainsEmitWithAwait ();
1063 public override Expression CreateExpressionTree (ResolveContext ec)
1065 Arguments args = new Arguments (2);
1066 args.Add (new Argument (child.CreateExpressionTree (ec)));
1067 args.Add (new Argument (new TypeOf (type, loc)));
1069 if (type.IsPointer || child.Type.IsPointer)
1070 Error_PointerInsideExpressionTree (ec);
1072 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1075 protected override Expression DoResolve (ResolveContext ec)
1077 // This should never be invoked, we are born in fully
1078 // initialized state.
1083 public override void Emit (EmitContext ec)
1088 public override SLE.Expression MakeExpression (BuilderContext ctx)
1091 return base.MakeExpression (ctx);
1093 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1094 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1095 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1099 protected override void CloneTo (CloneContext clonectx, Expression t)
1104 public override bool IsNull {
1105 get { return child.IsNull; }
1109 public class EmptyCast : TypeCast {
1110 EmptyCast (Expression child, TypeSpec target_type)
1111 : base (child, target_type)
1115 public static Expression Create (Expression child, TypeSpec type)
1117 Constant c = child as Constant;
1119 return new EmptyConstantCast (c, type);
1121 EmptyCast e = child as EmptyCast;
1123 return new EmptyCast (e.child, type);
1125 return new EmptyCast (child, type);
1128 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1130 child.EmitBranchable (ec, label, on_true);
1133 public override void EmitSideEffect (EmitContext ec)
1135 child.EmitSideEffect (ec);
1140 // Used for predefined type user operator (no obsolete check, etc.)
1142 public class OperatorCast : TypeCast
1144 readonly MethodSpec conversion_operator;
1146 public OperatorCast (Expression expr, TypeSpec target_type)
1147 : this (expr, target_type, target_type, false)
1151 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1152 : this (expr, target_type, target_type, find_explicit)
1156 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1157 : base (expr, returnType)
1159 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1160 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1163 foreach (MethodSpec oper in mi) {
1164 if (oper.ReturnType != returnType)
1167 if (oper.Parameters.Types[0] == expr.Type) {
1168 conversion_operator = oper;
1174 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1175 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1178 public override void Emit (EmitContext ec)
1181 ec.Emit (OpCodes.Call, conversion_operator);
1186 // Constant specialization of EmptyCast.
1187 // We need to special case this since an empty cast of
1188 // a constant is still a constant.
1190 public class EmptyConstantCast : Constant
1192 public readonly Constant child;
1194 public EmptyConstantCast (Constant child, TypeSpec type)
1195 : base (child.Location)
1198 throw new ArgumentNullException ("child");
1201 this.eclass = child.eclass;
1205 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1207 if (child.Type == target_type)
1210 // FIXME: check that 'type' can be converted to 'target_type' first
1211 return child.ConvertExplicitly (in_checked_context, target_type);
1214 public override Expression CreateExpressionTree (ResolveContext ec)
1216 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1217 child.CreateExpressionTree (ec),
1218 new TypeOf (type, loc));
1221 Error_PointerInsideExpressionTree (ec);
1223 return CreateExpressionFactoryCall (ec, "Convert", args);
1226 public override bool IsDefaultValue {
1227 get { return child.IsDefaultValue; }
1230 public override bool IsNegative {
1231 get { return child.IsNegative; }
1234 public override bool IsNull {
1235 get { return child.IsNull; }
1238 public override bool IsOneInteger {
1239 get { return child.IsOneInteger; }
1242 public override bool IsSideEffectFree {
1244 return child.IsSideEffectFree;
1248 public override bool IsZeroInteger {
1249 get { return child.IsZeroInteger; }
1252 public override void Emit (EmitContext ec)
1257 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1259 child.EmitBranchable (ec, label, on_true);
1261 // Only to make verifier happy
1262 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1263 ec.Emit (OpCodes.Unbox_Any, type);
1266 public override void EmitSideEffect (EmitContext ec)
1268 child.EmitSideEffect (ec);
1271 public override object GetValue ()
1273 return child.GetValue ();
1276 public override string GetValueAsLiteral ()
1278 return child.GetValueAsLiteral ();
1281 public override long GetValueAsLong ()
1283 return child.GetValueAsLong ();
1286 public override Constant ConvertImplicitly (TypeSpec target_type)
1288 if (type == target_type)
1291 // FIXME: Do we need to check user conversions?
1292 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1295 return child.ConvertImplicitly (target_type);
1300 /// This class is used to wrap literals which belong inside Enums
1302 public class EnumConstant : Constant
1304 public Constant Child;
1306 public EnumConstant (Constant child, TypeSpec enum_type)
1307 : base (child.Location)
1311 this.eclass = ExprClass.Value;
1312 this.type = enum_type;
1315 protected EnumConstant (Location loc)
1320 public override void Emit (EmitContext ec)
1325 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1327 Child.EncodeAttributeValue (rc, enc, Child.Type);
1330 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1332 Child.EmitBranchable (ec, label, on_true);
1335 public override void EmitSideEffect (EmitContext ec)
1337 Child.EmitSideEffect (ec);
1340 public override string GetSignatureForError()
1342 return TypeManager.CSharpName (Type);
1345 public override object GetValue ()
1347 return Child.GetValue ();
1351 public override object GetTypedValue ()
1354 // The method can be used in dynamic context only (on closed types)
1356 // System.Enum.ToObject cannot be called on dynamic types
1357 // EnumBuilder has to be used, but we cannot use EnumBuilder
1358 // because it does not properly support generics
1360 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1364 public override string GetValueAsLiteral ()
1366 return Child.GetValueAsLiteral ();
1369 public override long GetValueAsLong ()
1371 return Child.GetValueAsLong ();
1374 public EnumConstant Increment()
1376 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1379 public override bool IsDefaultValue {
1381 return Child.IsDefaultValue;
1385 public override bool IsSideEffectFree {
1387 return Child.IsSideEffectFree;
1391 public override bool IsZeroInteger {
1392 get { return Child.IsZeroInteger; }
1395 public override bool IsNegative {
1397 return Child.IsNegative;
1401 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1403 if (Child.Type == target_type)
1406 return Child.ConvertExplicitly (in_checked_context, target_type);
1409 public override Constant ConvertImplicitly (TypeSpec type)
1411 if (this.type == type) {
1415 if (!Convert.ImplicitStandardConversionExists (this, type)){
1419 return Child.ConvertImplicitly (type);
1424 /// This kind of cast is used to encapsulate Value Types in objects.
1426 /// The effect of it is to box the value type emitted by the previous
1429 public class BoxedCast : TypeCast {
1431 public BoxedCast (Expression expr, TypeSpec target_type)
1432 : base (expr, target_type)
1434 eclass = ExprClass.Value;
1437 protected override Expression DoResolve (ResolveContext ec)
1439 // This should never be invoked, we are born in fully
1440 // initialized state.
1445 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1447 // Only boxing to object type is supported
1448 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1449 base.EncodeAttributeValue (rc, enc, targetType);
1453 enc.Encode (child.Type);
1454 child.EncodeAttributeValue (rc, enc, child.Type);
1457 public override void Emit (EmitContext ec)
1461 ec.Emit (OpCodes.Box, child.Type);
1464 public override void EmitSideEffect (EmitContext ec)
1466 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1467 // so, we need to emit the box+pop instructions in most cases
1468 if (child.Type.IsStruct &&
1469 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1470 child.EmitSideEffect (ec);
1472 base.EmitSideEffect (ec);
1476 public class UnboxCast : TypeCast {
1477 public UnboxCast (Expression expr, TypeSpec return_type)
1478 : base (expr, return_type)
1482 protected override Expression DoResolve (ResolveContext ec)
1484 // This should never be invoked, we are born in fully
1485 // initialized state.
1490 public override void Emit (EmitContext ec)
1494 ec.Emit (OpCodes.Unbox_Any, type);
1499 /// This is used to perform explicit numeric conversions.
1501 /// Explicit numeric conversions might trigger exceptions in a checked
1502 /// context, so they should generate the conv.ovf opcodes instead of
1505 public class ConvCast : TypeCast {
1506 public enum Mode : byte {
1507 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1509 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1510 U2_I1, U2_U1, U2_I2, U2_CH,
1511 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1512 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1513 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1514 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1515 CH_I1, CH_U1, CH_I2,
1516 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1517 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1523 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1524 : base (child, return_type)
1529 protected override Expression DoResolve (ResolveContext ec)
1531 // This should never be invoked, we are born in fully
1532 // initialized state.
1537 public override string ToString ()
1539 return String.Format ("ConvCast ({0}, {1})", mode, child);
1542 public override void Emit (EmitContext ec)
1546 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1548 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1549 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1550 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1551 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1552 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1554 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1555 case Mode.U1_CH: /* nothing */ break;
1557 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1558 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1559 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1560 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1561 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1562 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1564 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1565 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1566 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1567 case Mode.U2_CH: /* nothing */ break;
1569 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1570 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1571 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1572 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1573 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1574 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1575 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1577 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1578 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1579 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1580 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1581 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1582 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1584 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1585 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1586 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1587 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1588 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1589 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1590 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1591 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1592 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1594 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1595 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1596 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1597 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1598 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1599 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1600 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1601 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1602 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1604 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1605 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1606 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1608 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1609 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1610 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1611 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1612 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1613 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1614 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1615 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1616 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1618 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1619 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1620 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1621 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1622 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1623 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1624 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1625 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1626 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1627 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1629 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1633 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1634 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1635 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1636 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1637 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1639 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1640 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1642 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1643 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1644 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1645 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1646 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1647 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1649 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1650 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1651 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1652 case Mode.U2_CH: /* nothing */ break;
1654 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1655 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1656 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1657 case Mode.I4_U4: /* nothing */ break;
1658 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1659 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1660 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1662 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1663 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1664 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1665 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1666 case Mode.U4_I4: /* nothing */ break;
1667 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1670 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1671 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1672 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1673 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1674 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1675 case Mode.I8_U8: /* nothing */ break;
1676 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1677 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1679 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1680 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1681 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1682 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1683 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1684 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1685 case Mode.U8_I8: /* nothing */ break;
1686 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1687 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1689 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1690 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1691 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1693 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1694 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1695 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1697 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1698 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1699 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1700 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1701 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1703 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1704 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1705 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1706 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1707 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1708 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1709 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1710 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1711 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1714 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1720 class OpcodeCast : TypeCast
1724 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1725 : base (child, return_type)
1730 protected override Expression DoResolve (ResolveContext ec)
1732 // This should never be invoked, we are born in fully
1733 // initialized state.
1738 public override void Emit (EmitContext ec)
1744 public TypeSpec UnderlyingType {
1745 get { return child.Type; }
1750 // Opcode casts expression with 2 opcodes but only
1751 // single expression tree node
1753 class OpcodeCastDuplex : OpcodeCast
1755 readonly OpCode second;
1757 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1758 : base (child, returnType, first)
1760 this.second = second;
1763 public override void Emit (EmitContext ec)
1771 /// This kind of cast is used to encapsulate a child and cast it
1772 /// to the class requested
1774 public sealed class ClassCast : TypeCast {
1775 readonly bool forced;
1777 public ClassCast (Expression child, TypeSpec return_type)
1778 : base (child, return_type)
1782 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1783 : base (child, return_type)
1785 this.forced = forced;
1788 public override void Emit (EmitContext ec)
1792 bool gen = TypeManager.IsGenericParameter (child.Type);
1794 ec.Emit (OpCodes.Box, child.Type);
1796 if (type.IsGenericParameter) {
1797 ec.Emit (OpCodes.Unbox_Any, type);
1804 ec.Emit (OpCodes.Castclass, type);
1809 // Created during resolving pahse when an expression is wrapped or constantified
1810 // and original expression can be used later (e.g. for expression trees)
1812 public class ReducedExpression : Expression
1814 sealed class ReducedConstantExpression : EmptyConstantCast
1816 readonly Expression orig_expr;
1818 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1819 : base (expr, expr.Type)
1821 this.orig_expr = orig_expr;
1824 public override Constant ConvertImplicitly (TypeSpec target_type)
1826 Constant c = base.ConvertImplicitly (target_type);
1828 c = new ReducedConstantExpression (c, orig_expr);
1833 public override Expression CreateExpressionTree (ResolveContext ec)
1835 return orig_expr.CreateExpressionTree (ec);
1838 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1840 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1842 c = new ReducedConstantExpression (c, orig_expr);
1847 sealed class ReducedExpressionStatement : ExpressionStatement
1849 readonly Expression orig_expr;
1850 readonly ExpressionStatement stm;
1852 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1854 this.orig_expr = orig;
1856 this.eclass = stm.eclass;
1857 this.type = stm.Type;
1859 this.loc = orig.Location;
1862 public override Expression CreateExpressionTree (ResolveContext ec)
1864 return orig_expr.CreateExpressionTree (ec);
1867 protected override Expression DoResolve (ResolveContext ec)
1872 public override void Emit (EmitContext ec)
1877 public override void EmitStatement (EmitContext ec)
1879 stm.EmitStatement (ec);
1883 readonly Expression expr, orig_expr;
1885 private ReducedExpression (Expression expr, Expression orig_expr)
1888 this.eclass = expr.eclass;
1889 this.type = expr.Type;
1890 this.orig_expr = orig_expr;
1891 this.loc = orig_expr.Location;
1896 public Expression OriginalExpression {
1905 // Creates fully resolved expression switcher
1907 public static Constant Create (Constant expr, Expression original_expr)
1909 if (expr.eclass == ExprClass.Unresolved)
1910 throw new ArgumentException ("Unresolved expression");
1912 return new ReducedConstantExpression (expr, original_expr);
1915 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1917 return new ReducedExpressionStatement (s, orig);
1920 public static Expression Create (Expression expr, Expression original_expr)
1922 return Create (expr, original_expr, true);
1926 // Creates unresolved reduce expression. The original expression has to be
1927 // already resolved. Created expression is constant based based on `expr'
1928 // value unless canBeConstant is used
1930 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1932 if (canBeConstant) {
1933 Constant c = expr as Constant;
1935 return Create (c, original_expr);
1938 ExpressionStatement s = expr as ExpressionStatement;
1940 return Create (s, original_expr);
1942 if (expr.eclass == ExprClass.Unresolved)
1943 throw new ArgumentException ("Unresolved expression");
1945 return new ReducedExpression (expr, original_expr);
1948 public override Expression CreateExpressionTree (ResolveContext ec)
1950 return orig_expr.CreateExpressionTree (ec);
1953 protected override Expression DoResolve (ResolveContext ec)
1958 public override void Emit (EmitContext ec)
1963 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1965 expr.EmitBranchable (ec, target, on_true);
1968 public override SLE.Expression MakeExpression (BuilderContext ctx)
1970 return orig_expr.MakeExpression (ctx);
1975 // Standard composite pattern
1977 public abstract class CompositeExpression : Expression
1979 protected Expression expr;
1981 protected CompositeExpression (Expression expr)
1984 this.loc = expr.Location;
1987 public override Expression CreateExpressionTree (ResolveContext rc)
1989 return expr.CreateExpressionTree (rc);
1992 public Expression Child {
1993 get { return expr; }
1996 protected override Expression DoResolve (ResolveContext rc)
1998 expr = expr.Resolve (rc);
2001 eclass = expr.eclass;
2007 public override void Emit (EmitContext ec)
2012 public override bool IsNull {
2013 get { return expr.IsNull; }
2018 // Base of expressions used only to narrow resolve flow
2020 public abstract class ShimExpression : Expression
2022 protected Expression expr;
2024 protected ShimExpression (Expression expr)
2029 public Expression Expr {
2035 protected override void CloneTo (CloneContext clonectx, Expression t)
2040 ShimExpression target = (ShimExpression) t;
2041 target.expr = expr.Clone (clonectx);
2044 public override Expression CreateExpressionTree (ResolveContext ec)
2046 throw new NotSupportedException ("ET");
2049 public override void Emit (EmitContext ec)
2051 throw new InternalErrorException ("Missing Resolve call");
2057 // Unresolved type name expressions
2059 public abstract class ATypeNameExpression : FullNamedExpression
2062 protected TypeArguments targs;
2064 protected ATypeNameExpression (string name, Location l)
2070 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2077 protected ATypeNameExpression (string name, int arity, Location l)
2078 : this (name, new UnboundTypeArguments (arity), l)
2084 protected int Arity {
2086 return targs == null ? 0 : targs.Count;
2090 public bool HasTypeArguments {
2092 return targs != null && !targs.IsEmpty;
2096 public string Name {
2105 public TypeArguments TypeArguments {
2113 public override bool Equals (object obj)
2115 ATypeNameExpression atne = obj as ATypeNameExpression;
2116 return atne != null && atne.Name == Name &&
2117 (targs == null || targs.Equals (atne.targs));
2120 public override int GetHashCode ()
2122 return Name.GetHashCode ();
2125 // TODO: Move it to MemberCore
2126 public static string GetMemberType (MemberCore mc)
2132 if (mc is FieldBase)
2134 if (mc is MethodCore)
2136 if (mc is EnumMember)
2144 public override string GetSignatureForError ()
2146 if (targs != null) {
2147 return Name + "<" + targs.GetSignatureForError () + ">";
2153 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2157 /// SimpleName expressions are formed of a single word and only happen at the beginning
2158 /// of a dotted-name.
2160 public class SimpleName : ATypeNameExpression
2162 public SimpleName (string name, Location l)
2167 public SimpleName (string name, TypeArguments args, Location l)
2168 : base (name, args, l)
2172 public SimpleName (string name, int arity, Location l)
2173 : base (name, arity, l)
2177 public SimpleName GetMethodGroup ()
2179 return new SimpleName (Name, targs, loc);
2182 protected override Expression DoResolve (ResolveContext ec)
2184 return SimpleNameResolve (ec, null, false);
2187 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2189 return SimpleNameResolve (ec, right_side, false);
2192 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2194 if (ctx.CurrentType != null) {
2195 if (ctx.CurrentMemberDefinition != null) {
2196 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2198 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2204 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2205 if (retval != null) {
2206 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2207 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2211 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2212 if (retval != null) {
2213 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2217 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2220 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2222 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2225 if (fne.Type != null && Arity > 0) {
2226 if (HasTypeArguments) {
2227 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2228 if (ct.ResolveAsType (ec) == null)
2234 return new GenericOpenTypeExpr (fne.Type, loc);
2238 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2240 if (!(fne is Namespace))
2244 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2245 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2246 ec.Module.Compiler.Report.Error (1980, Location,
2247 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2248 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2251 fne = new DynamicTypeExpr (loc);
2252 fne.ResolveAsType (ec);
2258 Error_TypeOrNamespaceNotFound (ec);
2262 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2264 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2267 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2269 int lookup_arity = Arity;
2270 bool errorMode = false;
2272 Block current_block = rc.CurrentBlock;
2273 INamedBlockVariable variable = null;
2274 bool variable_found = false;
2278 // Stage 1: binding to local variables or parameters
2280 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2282 if (current_block != null && lookup_arity == 0) {
2283 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2284 if (!variable.IsDeclared) {
2285 // We found local name in accessible block but it's not
2286 // initialized yet, maybe the user wanted to bind to something else
2288 variable_found = true;
2290 e = variable.CreateReferenceExpression (rc, loc);
2293 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2302 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2304 TypeSpec member_type = rc.CurrentType;
2305 for (; member_type != null; member_type = member_type.DeclaringType) {
2306 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2310 var me = e as MemberExpr;
2312 // The name matches a type, defer to ResolveAsTypeStep
2320 if (variable != null) {
2321 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2322 rc.Report.Error (844, loc,
2323 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2324 Name, me.GetSignatureForError ());
2328 } else if (me is MethodGroupExpr) {
2329 // Leave it to overload resolution to report correct error
2331 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2332 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2335 // LAMESPEC: again, ignores InvocableOnly
2336 if (variable != null) {
2337 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2338 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2342 // MemberLookup does not check accessors availability, this is actually needed for properties only
2344 var pe = me as PropertyExpr;
2347 // Break as there is no other overload available anyway
2348 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2349 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2352 pe.Getter = pe.PropertyInfo.Get;
2354 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2357 pe.Setter = pe.PropertyInfo.Set;
2362 // TODO: It's used by EventExpr -> FieldExpr transformation only
2363 // TODO: Should go to MemberAccess
2364 me = me.ResolveMemberAccess (rc, null, null);
2368 me.SetTypeArguments (rc, targs);
2375 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2377 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2378 if (IsPossibleTypeOrNamespace (rc)) {
2379 if (variable != null) {
2380 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2381 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2384 return ResolveAsTypeOrNamespace (rc);
2389 if (variable_found) {
2390 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2393 TypeParameter[] tparams = rc.CurrentTypeParameters;
2394 if (tparams != null) {
2395 foreach (var ctp in tparams) {
2396 if (ctp.Name == Name) {
2397 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2403 var ct = rc.CurrentType;
2405 if (ct.MemberDefinition.TypeParametersCount > 0) {
2406 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2407 if (ctp.Name == Name) {
2408 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2414 ct = ct.DeclaringType;
2415 } while (ct != null);
2418 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2419 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2421 rc.Report.SymbolRelatedToPreviousError (e.Type);
2422 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2427 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2429 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2430 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2435 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2438 return ErrorExpression.Instance;
2441 if (rc.Module.Evaluator != null) {
2442 var fi = rc.Module.Evaluator.LookupField (Name);
2444 return new FieldExpr (fi.Item1, loc);
2452 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2454 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2459 if (right_side != null) {
2460 if (e is TypeExpr) {
2461 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2465 e = e.ResolveLValue (ec, right_side);
2470 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2476 /// Represents a namespace or a type. The name of the class was inspired by
2477 /// section 10.8.1 (Fully Qualified Names).
2479 public abstract class FullNamedExpression : Expression
2481 protected override void CloneTo (CloneContext clonectx, Expression target)
2483 // Do nothing, most unresolved type expressions cannot be
2484 // resolved to different type
2487 public override Expression CreateExpressionTree (ResolveContext ec)
2489 throw new NotSupportedException ("ET");
2492 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2495 // This is used to resolve the expression as a type, a null
2496 // value will be returned if the expression is not a type
2499 public override TypeSpec ResolveAsType (IMemberContext mc)
2501 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2506 TypeExpr te = fne as TypeExpr;
2508 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2516 var dep = type.GetMissingDependencies ();
2518 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2522 // Obsolete checks cannot be done when resolving base context as they
2523 // require type dependencies to be set but we are in process of resolving them
2525 if (!(mc is TypeContainer.BaseContext)) {
2526 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2527 if (obsolete_attr != null && !mc.IsObsolete) {
2528 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2536 public override void Emit (EmitContext ec)
2538 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2539 GetSignatureForError ());
2544 /// Expression that evaluates to a type
2546 public abstract class TypeExpr : FullNamedExpression
2548 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2554 protected sealed override Expression DoResolve (ResolveContext ec)
2560 public override bool Equals (object obj)
2562 TypeExpr tobj = obj as TypeExpr;
2566 return Type == tobj.Type;
2569 public override int GetHashCode ()
2571 return Type.GetHashCode ();
2576 /// Fully resolved Expression that already evaluated to a type
2578 public class TypeExpression : TypeExpr
2580 public TypeExpression (TypeSpec t, Location l)
2583 eclass = ExprClass.Type;
2587 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2594 /// This class denotes an expression which evaluates to a member
2595 /// of a struct or a class.
2597 public abstract class MemberExpr : Expression
2600 // An instance expression associated with this member, if it's a
2601 // non-static member
2603 public Expression InstanceExpression;
2606 /// The name of this member.
2608 public abstract string Name {
2613 // When base.member is used
2615 public bool IsBase {
2616 get { return InstanceExpression is BaseThis; }
2620 /// Whether this is an instance member.
2622 public abstract bool IsInstance {
2627 /// Whether this is a static member.
2629 public abstract bool IsStatic {
2633 protected abstract TypeSpec DeclaringType {
2638 // Converts best base candidate for virtual method starting from QueriedBaseType
2640 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2643 // Only when base.member is used and method is virtual
2649 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2650 // means for base.member access we have to find the closest match after we found best candidate
2652 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2654 // The method could already be what we are looking for
2656 TypeSpec[] targs = null;
2657 if (method.DeclaringType != InstanceExpression.Type) {
2658 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2659 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2660 if (base_override.IsGeneric)
2661 targs = method.TypeArguments;
2663 method = base_override;
2667 // TODO: For now we do it for any hoisted call even if it's needed for
2668 // hoisted stories only but that requires a new expression wrapper
2669 if (rc.CurrentAnonymousMethod != null) {
2670 if (targs == null && method.IsGeneric) {
2671 targs = method.TypeArguments;
2672 method = method.GetGenericMethodDefinition ();
2675 if (method.Parameters.HasArglist)
2676 throw new NotImplementedException ("__arglist base call proxy");
2678 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2680 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2681 // get/set member expressions second call would fail to proxy because left expression
2682 // would be of 'this' and not 'base'
2683 if (rc.CurrentType.IsStruct)
2684 InstanceExpression = new This (loc).Resolve (rc);
2688 method = method.MakeGenericMethod (rc, targs);
2692 // Only base will allow this invocation to happen.
2694 if (method.IsAbstract) {
2695 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2701 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2703 if (InstanceExpression == null)
2706 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2707 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2711 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2713 var ct = rc.CurrentType;
2714 if (ct == qualifier)
2717 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2720 qualifier = qualifier.GetDefinition ();
2721 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2722 rc.Report.SymbolRelatedToPreviousError (member);
2723 rc.Report.Error (1540, loc,
2724 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2725 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2729 public override bool ContainsEmitWithAwait ()
2731 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2734 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2737 type = type.GetDefinition ();
2739 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2742 type = type.DeclaringType;
2743 } while (type != null);
2748 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2750 if (InstanceExpression != null) {
2751 InstanceExpression = InstanceExpression.Resolve (rc);
2752 CheckProtectedMemberAccess (rc, member);
2755 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2756 UnsafeError (rc, loc);
2759 var dep = member.GetMissingDependencies ();
2761 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2764 if (!rc.IsObsolete) {
2765 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2767 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2770 if (!(member is FieldSpec))
2771 member.MemberDefinition.SetIsUsed ();
2774 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2776 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2780 // Implements identicial simple name and type-name
2782 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2785 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2788 // 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
2789 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2791 if (left is MemberExpr || left is VariableReference) {
2792 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2793 if (identical_type != null && identical_type.Type == left.Type)
2794 return identical_type;
2800 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2803 if (InstanceExpression != null) {
2804 if (InstanceExpression is TypeExpr) {
2805 var t = InstanceExpression.Type;
2807 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2808 if (oa != null && !rc.IsObsolete) {
2809 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2812 t = t.DeclaringType;
2813 } while (t != null);
2815 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2816 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2817 rc.Report.Error (176, loc,
2818 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2819 GetSignatureForError ());
2823 InstanceExpression = null;
2829 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2830 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2831 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2832 rc.Report.Error (236, loc,
2833 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2834 GetSignatureForError ());
2836 rc.Report.Error (120, loc,
2837 "An object reference is required to access non-static member `{0}'",
2838 GetSignatureForError ());
2843 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2844 rc.Report.Error (38, loc,
2845 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2846 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2849 InstanceExpression = new This (loc);
2850 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2851 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2852 InstanceExpression = InstanceExpression.Resolve (rc);
2855 InstanceExpression = InstanceExpression.Resolve (rc);
2861 var me = InstanceExpression as MemberExpr;
2863 me.ResolveInstanceExpression (rc, rhs);
2865 var fe = me as FieldExpr;
2866 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2867 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2868 rc.Report.Warning (1690, 1, loc,
2869 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2870 me.GetSignatureForError ());
2877 // Run member-access postponed check once we know that
2878 // the expression is not field expression which is the only
2879 // expression which can use uninitialized this
2881 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2882 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2886 // Additional checks for l-value member access
2890 // TODO: It should be recursive but that would break csc compatibility
2892 if (InstanceExpression is UnboxCast) {
2893 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2900 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2902 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2903 ec.Report.Warning (1720, 1, left.Location,
2904 "Expression will always cause a `{0}'", "System.NullReferenceException");
2907 InstanceExpression = left;
2911 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2913 TypeSpec instance_type = InstanceExpression.Type;
2914 if (TypeSpec.IsValueType (instance_type)) {
2915 if (InstanceExpression is IMemoryLocation) {
2916 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2918 LocalTemporary t = new LocalTemporary (instance_type);
2919 InstanceExpression.Emit (ec);
2921 t.AddressOf (ec, AddressOp.Store);
2924 InstanceExpression.Emit (ec);
2926 // Only to make verifier happy
2927 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2928 ec.Emit (OpCodes.Box, instance_type);
2931 if (prepare_for_load)
2932 ec.Emit (OpCodes.Dup);
2935 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2939 // Represents a group of extension method candidates for whole namespace
2941 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2943 NamespaceContainer namespace_entry;
2944 public readonly Expression ExtensionExpression;
2946 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
2947 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2949 this.namespace_entry = n;
2950 this.ExtensionExpression = extensionExpr;
2953 public override bool IsStatic {
2954 get { return true; }
2957 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2959 if (namespace_entry == null)
2963 // For extension methodgroup we are not looking for base members but parent
2964 // namespace extension methods
2966 int arity = type_arguments == null ? 0 : type_arguments.Count;
2967 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2971 return found.Cast<MemberSpec> ().ToList ();
2974 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2976 // We are already here
2980 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2982 if (arguments == null)
2983 arguments = new Arguments (1);
2985 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2986 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2988 // Store resolved argument and restore original arguments
2990 // Clean-up modified arguments for error reporting
2991 arguments.RemoveAt (0);
2995 var me = ExtensionExpression as MemberExpr;
2997 me.ResolveInstanceExpression (ec, null);
2999 InstanceExpression = null;
3003 #region IErrorHandler Members
3005 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3010 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3012 rc.Report.SymbolRelatedToPreviousError (best);
3013 rc.Report.Error (1928, loc,
3014 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3015 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3018 rc.Report.Error (1929, loc,
3019 "Extension method instance type `{0}' cannot be converted to `{1}'",
3020 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3026 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3031 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3040 /// MethodGroupExpr represents a group of method candidates which
3041 /// can be resolved to the best method overload
3043 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3045 protected IList<MemberSpec> Methods;
3046 MethodSpec best_candidate;
3047 TypeSpec best_candidate_return;
3048 protected TypeArguments type_arguments;
3050 SimpleName simple_name;
3051 protected TypeSpec queried_type;
3053 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3057 this.type = InternalType.MethodGroup;
3059 eclass = ExprClass.MethodGroup;
3060 queried_type = type;
3063 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3064 : this (new MemberSpec[] { m }, type, loc)
3070 public MethodSpec BestCandidate {
3072 return best_candidate;
3076 public TypeSpec BestCandidateReturnType {
3078 return best_candidate_return;
3082 public IList<MemberSpec> Candidates {
3088 protected override TypeSpec DeclaringType {
3090 return queried_type;
3094 public override bool IsInstance {
3096 if (best_candidate != null)
3097 return !best_candidate.IsStatic;
3103 public override bool IsStatic {
3105 if (best_candidate != null)
3106 return best_candidate.IsStatic;
3112 public override string Name {
3114 if (best_candidate != null)
3115 return best_candidate.Name;
3118 return Methods.First ().Name;
3125 // When best candidate is already know this factory can be used
3126 // to avoid expensive overload resolution to be called
3128 // NOTE: InstanceExpression has to be set manually
3130 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3132 return new MethodGroupExpr (best, queriedType, loc) {
3133 best_candidate = best,
3134 best_candidate_return = best.ReturnType
3138 public override string GetSignatureForError ()
3140 if (best_candidate != null)
3141 return best_candidate.GetSignatureForError ();
3143 return Methods.First ().GetSignatureForError ();
3146 public override Expression CreateExpressionTree (ResolveContext ec)
3148 if (best_candidate == null) {
3149 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3153 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3154 ec.Report.Error (765, loc,
3155 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3157 return new TypeOfMethod (best_candidate, loc);
3160 protected override Expression DoResolve (ResolveContext ec)
3162 this.eclass = ExprClass.MethodGroup;
3164 if (InstanceExpression != null) {
3165 InstanceExpression = InstanceExpression.Resolve (ec);
3166 if (InstanceExpression == null)
3173 public override void Emit (EmitContext ec)
3175 throw new NotSupportedException ();
3178 public void EmitCall (EmitContext ec, Arguments arguments)
3180 var call = new CallEmitter ();
3181 call.InstanceExpression = InstanceExpression;
3182 call.Emit (ec, best_candidate, arguments, loc);
3185 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3187 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3188 Name, TypeManager.CSharpName (target));
3191 public static bool IsExtensionMethodArgument (Expression expr)
3194 // LAMESPEC: No details about which expressions are not allowed
3196 return !(expr is TypeExpr) && !(expr is BaseThis);
3200 /// Find the Applicable Function Members (7.4.2.1)
3202 /// me: Method Group expression with the members to select.
3203 /// it might contain constructors or methods (or anything
3204 /// that maps to a method).
3206 /// Arguments: ArrayList containing resolved Argument objects.
3208 /// loc: The location if we want an error to be reported, or a Null
3209 /// location for "probing" purposes.
3211 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3212 /// that is the best match of me on Arguments.
3215 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3217 // TODO: causes issues with probing mode, remove explicit Kind check
3218 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3221 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3222 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3223 r.BaseMembersProvider = this;
3226 if (cerrors != null)
3227 r.CustomErrors = cerrors;
3229 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3230 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3231 if (best_candidate == null)
3232 return r.BestCandidateIsDynamic ? this : null;
3234 // Overload resolver had to create a new method group, all checks bellow have already been executed
3235 if (r.BestCandidateNewMethodGroup != null)
3236 return r.BestCandidateNewMethodGroup;
3238 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3239 if (InstanceExpression != null) {
3240 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3241 InstanceExpression = null;
3243 if (best_candidate.IsStatic && simple_name != null) {
3244 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3247 InstanceExpression.Resolve (ec);
3251 ResolveInstanceExpression (ec, null);
3252 if (InstanceExpression != null)
3253 CheckProtectedMemberAccess (ec, best_candidate);
3256 var base_override = CandidateToBaseOverride (ec, best_candidate);
3257 if (base_override == best_candidate) {
3258 best_candidate_return = r.BestCandidateReturnType;
3260 best_candidate = base_override;
3261 best_candidate_return = best_candidate.ReturnType;
3267 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3269 simple_name = original;
3270 return base.ResolveMemberAccess (ec, left, original);
3273 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3275 type_arguments = ta;
3278 #region IBaseMembersProvider Members
3280 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3282 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3285 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3287 if (queried_type == member.DeclaringType)
3290 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3291 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3295 // Extension methods lookup after ordinary methods candidates failed to apply
3297 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3299 if (InstanceExpression == null)
3302 InstanceExpression = InstanceExpression.Resolve (rc);
3303 if (!IsExtensionMethodArgument (InstanceExpression))
3306 int arity = type_arguments == null ? 0 : type_arguments.Count;
3307 NamespaceContainer methods_scope = null;
3308 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3309 if (methods == null)
3312 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3313 emg.SetTypeArguments (rc, type_arguments);
3320 public struct OverloadResolver
3323 public enum Restrictions
3327 ProbingOnly = 1 << 1,
3328 CovariantDelegate = 1 << 2,
3329 NoBaseMembers = 1 << 3,
3330 BaseMembersIncluded = 1 << 4
3333 public interface IBaseMembersProvider
3335 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3336 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3337 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3340 public interface IErrorHandler
3342 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3343 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3344 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3345 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3348 sealed class NoBaseMembers : IBaseMembersProvider
3350 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3352 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3357 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3362 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3368 struct AmbiguousCandidate
3370 public readonly MemberSpec Member;
3371 public readonly bool Expanded;
3372 public readonly AParametersCollection Parameters;
3374 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3377 Parameters = parameters;
3378 Expanded = expanded;
3383 IList<MemberSpec> members;
3384 TypeArguments type_arguments;
3385 IBaseMembersProvider base_provider;
3386 IErrorHandler custom_errors;
3387 Restrictions restrictions;
3388 MethodGroupExpr best_candidate_extension_group;
3389 TypeSpec best_candidate_return_type;
3391 SessionReportPrinter lambda_conv_msgs;
3392 ReportPrinter prev_recorder;
3394 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3395 : this (members, null, restrictions, loc)
3399 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3402 if (members == null || members.Count == 0)
3403 throw new ArgumentException ("empty members set");
3405 this.members = members;
3407 type_arguments = targs;
3408 this.restrictions = restrictions;
3409 if (IsDelegateInvoke)
3410 this.restrictions |= Restrictions.NoBaseMembers;
3412 base_provider = NoBaseMembers.Instance;
3417 public IBaseMembersProvider BaseMembersProvider {
3419 return base_provider;
3422 base_provider = value;
3426 public bool BestCandidateIsDynamic { get; set; }
3429 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3431 public MethodGroupExpr BestCandidateNewMethodGroup {
3433 return best_candidate_extension_group;
3438 // Return type can be different between best candidate and closest override
3440 public TypeSpec BestCandidateReturnType {
3442 return best_candidate_return_type;
3446 public IErrorHandler CustomErrors {
3448 return custom_errors;
3451 custom_errors = value;
3455 TypeSpec DelegateType {
3457 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3458 throw new InternalErrorException ("Not running in delegate mode", loc);
3460 return members [0].DeclaringType;
3464 bool IsProbingOnly {
3466 return (restrictions & Restrictions.ProbingOnly) != 0;
3470 bool IsDelegateInvoke {
3472 return (restrictions & Restrictions.DelegateInvoke) != 0;
3479 // 7.4.3.3 Better conversion from expression
3480 // Returns : 1 if a->p is better,
3481 // 2 if a->q is better,
3482 // 0 if neither is better
3484 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3486 TypeSpec argument_type = a.Type;
3489 // If argument is an anonymous function
3491 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3493 // p and q are delegate types or expression tree types
3495 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3496 if (q.MemberDefinition != p.MemberDefinition) {
3501 // Uwrap delegate from Expression<T>
3503 q = TypeManager.GetTypeArguments (q)[0];
3504 p = TypeManager.GetTypeArguments (p)[0];
3507 var p_m = Delegate.GetInvokeMethod (p);
3508 var q_m = Delegate.GetInvokeMethod (q);
3511 // With identical parameter lists
3513 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3520 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3522 if (p.Kind == MemberKind.Void) {
3523 return q.Kind != MemberKind.Void ? 2 : 0;
3527 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3529 if (q.Kind == MemberKind.Void) {
3530 return p.Kind != MemberKind.Void ? 1: 0;
3534 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3535 // better conversion is performed between underlying types Y1 and Y2
3537 if (p.IsGenericTask || q.IsGenericTask) {
3538 if (p.IsGenericTask != q.IsGenericTask) {
3542 var async_am = a.Expr as AnonymousMethodExpression;
3543 if (async_am == null || !async_am.IsAsync)
3546 q = q.TypeArguments[0];
3547 p = p.TypeArguments[0];
3551 // The parameters are identicial and return type is not void, use better type conversion
3552 // on return type to determine better one
3555 if (argument_type == p)
3558 if (argument_type == q)
3562 return BetterTypeConversion (ec, p, q);
3566 // 7.4.3.4 Better conversion from type
3568 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3570 if (p == null || q == null)
3571 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3573 switch (p.BuiltinType) {
3574 case BuiltinTypeSpec.Type.Int:
3575 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3578 case BuiltinTypeSpec.Type.Long:
3579 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3582 case BuiltinTypeSpec.Type.SByte:
3583 switch (q.BuiltinType) {
3584 case BuiltinTypeSpec.Type.Byte:
3585 case BuiltinTypeSpec.Type.UShort:
3586 case BuiltinTypeSpec.Type.UInt:
3587 case BuiltinTypeSpec.Type.ULong:
3591 case BuiltinTypeSpec.Type.Short:
3592 switch (q.BuiltinType) {
3593 case BuiltinTypeSpec.Type.UShort:
3594 case BuiltinTypeSpec.Type.UInt:
3595 case BuiltinTypeSpec.Type.ULong:
3599 case BuiltinTypeSpec.Type.Dynamic:
3600 // Dynamic is never better
3604 switch (q.BuiltinType) {
3605 case BuiltinTypeSpec.Type.Int:
3606 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3609 case BuiltinTypeSpec.Type.Long:
3610 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3613 case BuiltinTypeSpec.Type.SByte:
3614 switch (p.BuiltinType) {
3615 case BuiltinTypeSpec.Type.Byte:
3616 case BuiltinTypeSpec.Type.UShort:
3617 case BuiltinTypeSpec.Type.UInt:
3618 case BuiltinTypeSpec.Type.ULong:
3622 case BuiltinTypeSpec.Type.Short:
3623 switch (p.BuiltinType) {
3624 case BuiltinTypeSpec.Type.UShort:
3625 case BuiltinTypeSpec.Type.UInt:
3626 case BuiltinTypeSpec.Type.ULong:
3630 case BuiltinTypeSpec.Type.Dynamic:
3631 // Dynamic is never better
3635 // FIXME: handle lifted operators
3637 // TODO: this is expensive
3638 Expression p_tmp = new EmptyExpression (p);
3639 Expression q_tmp = new EmptyExpression (q);
3641 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3642 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3644 if (p_to_q && !q_to_p)
3647 if (q_to_p && !p_to_q)
3654 /// Determines "Better function" between candidate
3655 /// and the current best match
3658 /// Returns a boolean indicating :
3659 /// false if candidate ain't better
3660 /// true if candidate is better than the current best match
3662 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3663 MemberSpec best, AParametersCollection bparam, bool best_params)
3665 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3666 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3668 bool better_at_least_one = false;
3670 int args_count = args == null ? 0 : args.Count;
3674 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3677 // Default arguments are ignored for better decision
3678 if (a.IsDefaultArgument)
3682 // When comparing named argument the parameter type index has to be looked up
3683 // in original parameter set (override version for virtual members)
3685 NamedArgument na = a as NamedArgument;
3687 int idx = cparam.GetParameterIndexByName (na.Name);
3688 ct = candidate_pd.Types[idx];
3689 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3690 ct = TypeManager.GetElementType (ct);
3692 idx = bparam.GetParameterIndexByName (na.Name);
3693 bt = best_pd.Types[idx];
3694 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3695 bt = TypeManager.GetElementType (bt);
3697 ct = candidate_pd.Types[c_idx];
3698 bt = best_pd.Types[b_idx];
3700 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3701 ct = TypeManager.GetElementType (ct);
3705 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3706 bt = TypeManager.GetElementType (bt);
3711 if (TypeSpecComparer.IsEqual (ct, bt))
3715 int result = BetterExpressionConversion (ec, a, ct, bt);
3717 // for each argument, the conversion to 'ct' should be no worse than
3718 // the conversion to 'bt'.
3722 // for at least one argument, the conversion to 'ct' should be better than
3723 // the conversion to 'bt'.
3725 better_at_least_one = true;
3728 if (better_at_least_one)
3732 // This handles the case
3734 // Add (float f1, float f2, float f3);
3735 // Add (params decimal [] foo);
3737 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3738 // first candidate would've chosen as better.
3740 if (!same && !a.IsDefaultArgument)
3744 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3748 // This handles the following cases:
3750 // Foo (int i) is better than Foo (int i, long l = 0)
3751 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3753 // Prefer non-optional version
3755 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3757 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3758 if (candidate_pd.Count >= best_pd.Count)
3761 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3768 // One is a non-generic method and second is a generic method, then non-generic is better
3770 if (best.IsGeneric != candidate.IsGeneric)
3771 return best.IsGeneric;
3774 // This handles the following cases:
3776 // Trim () is better than Trim (params char[] chars)
3777 // Concat (string s1, string s2, string s3) is better than
3778 // Concat (string s1, params string [] srest)
3779 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3781 // Prefer non-expanded version
3783 if (candidate_params != best_params)
3786 int candidate_param_count = candidate_pd.Count;
3787 int best_param_count = best_pd.Count;
3789 if (candidate_param_count != best_param_count)
3790 // can only happen if (candidate_params && best_params)
3791 return candidate_param_count > best_param_count && best_pd.HasParams;
3794 // Both methods have the same number of parameters, and the parameters have equal types
3795 // Pick the "more specific" signature using rules over original (non-inflated) types
3797 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3798 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3800 bool specific_at_least_once = false;
3801 for (j = 0; j < args_count; ++j) {
3802 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3804 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3805 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3807 ct = candidate_def_pd.Types[j];
3808 bt = best_def_pd.Types[j];
3813 TypeSpec specific = MoreSpecific (ct, bt);
3817 specific_at_least_once = true;
3820 if (specific_at_least_once)
3826 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3828 rc.Report.Error (1729, loc,
3829 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3830 type.GetSignatureForError (), argCount.ToString ());
3834 // Determines if the candidate method is applicable to the given set of arguments
3835 // There could be two different set of parameters for same candidate where one
3836 // is the closest override for default values and named arguments checks and second
3837 // one being the virtual base for the parameter types and modifiers.
3839 // A return value rates candidate method compatibility,
3840 // 0 = the best, int.MaxValue = the worst
3842 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)
3844 // Parameters of most-derived type used mainly for named and optional parameters
3845 var pd = pm.Parameters;
3847 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3848 // params modifier instead of most-derived type
3849 var cpd = ((IParametersMember) candidate).Parameters;
3850 int param_count = pd.Count;
3851 int optional_count = 0;
3853 Arguments orig_args = arguments;
3855 if (arg_count != param_count) {
3856 for (int i = 0; i < pd.Count; ++i) {
3857 if (pd.FixedParameters[i].HasDefaultValue) {
3858 optional_count = pd.Count - i;
3863 if (optional_count != 0) {
3864 // Readjust expected number when params used
3865 if (cpd.HasParams) {
3867 if (arg_count < param_count)
3869 } else if (arg_count > param_count) {
3870 int args_gap = System.Math.Abs (arg_count - param_count);
3871 return int.MaxValue - 10000 + args_gap;
3873 } else if (arg_count != param_count) {
3874 int args_gap = System.Math.Abs (arg_count - param_count);
3876 return int.MaxValue - 10000 + args_gap;
3877 if (arg_count < param_count - 1)
3878 return int.MaxValue - 10000 + args_gap;
3881 // Resize to fit optional arguments
3882 if (optional_count != 0) {
3883 if (arguments == null) {
3884 arguments = new Arguments (optional_count);
3886 // Have to create a new container, so the next run can do same
3887 var resized = new Arguments (param_count);
3888 resized.AddRange (arguments);
3889 arguments = resized;
3892 for (int i = arg_count; i < param_count; ++i)
3893 arguments.Add (null);
3897 if (arg_count > 0) {
3899 // Shuffle named arguments to the right positions if there are any
3901 if (arguments[arg_count - 1] is NamedArgument) {
3902 arg_count = arguments.Count;
3904 for (int i = 0; i < arg_count; ++i) {
3905 bool arg_moved = false;
3907 NamedArgument na = arguments[i] as NamedArgument;
3911 int index = pd.GetParameterIndexByName (na.Name);
3913 // Named parameter not found
3917 // already reordered
3922 if (index >= param_count) {
3923 // When using parameters which should not be available to the user
3924 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3927 arguments.Add (null);
3931 temp = arguments[index];
3933 // The slot has been taken by positional argument
3934 if (temp != null && !(temp is NamedArgument))
3939 arguments = arguments.MarkOrderedArgument (na);
3943 arguments[index] = arguments[i];
3944 arguments[i] = temp;
3951 arg_count = arguments.Count;
3953 } else if (arguments != null) {
3954 arg_count = arguments.Count;
3958 // 1. Handle generic method using type arguments when specified or type inference
3961 var ms = candidate as MethodSpec;
3962 if (ms != null && ms.IsGeneric) {
3963 // Setup constraint checker for probing only
3964 ConstraintChecker cc = new ConstraintChecker (null);
3966 if (type_arguments != null) {
3967 var g_args_count = ms.Arity;
3968 if (g_args_count != type_arguments.Count)
3969 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3971 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3973 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3974 // for now it simplifies things. I should probably add a callback to ResolveContext
3975 if (lambda_conv_msgs == null) {
3976 lambda_conv_msgs = new SessionReportPrinter ();
3977 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3980 var ti = new TypeInference (arguments);
3981 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3982 lambda_conv_msgs.EndSession ();
3985 return ti.InferenceScore - 20000;
3987 if (i_args.Length != 0) {
3988 ms = ms.MakeGenericMethod (ec, i_args);
3991 cc.IgnoreInferredDynamic = true;
3995 // Type arguments constraints have to match for the method to be applicable
3997 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3999 return int.MaxValue - 25000;
4003 // We have a generic return type and at same time the method is override which
4004 // means we have to also inflate override return type in case the candidate is
4005 // best candidate and override return type is different to base return type.
4007 // virtual Foo<T, object> with override Foo<T, dynamic>
4009 if (candidate != pm) {
4010 MethodSpec override_ms = (MethodSpec) pm;
4011 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4012 returnType = inflator.Inflate (returnType);
4014 returnType = ms.ReturnType;
4018 ptypes = ms.Parameters.Types;
4020 if (type_arguments != null)
4021 return int.MaxValue - 15000;
4027 // 2. Each argument has to be implicitly convertible to method parameter
4029 Parameter.Modifier p_mod = 0;
4032 for (int i = 0; i < arg_count; i++) {
4033 Argument a = arguments[i];
4035 if (!pd.FixedParameters[i].HasDefaultValue) {
4036 arguments = orig_args;
4037 return arg_count * 2 + 2;
4041 // Get the default value expression, we can use the same expression
4042 // if the type matches
4044 Expression e = pd.FixedParameters[i].DefaultValue;
4045 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4047 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4049 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4050 e = new MemberAccess (new MemberAccess (new MemberAccess (
4051 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4053 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4059 arguments[i] = new Argument (e, Argument.AType.Default);
4063 if (p_mod != Parameter.Modifier.PARAMS) {
4064 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4066 } else if (!params_expanded_form) {
4067 params_expanded_form = true;
4068 pt = ((ElementTypeSpec) pt).Element;
4074 if (!params_expanded_form) {
4075 if (a.ArgType == Argument.AType.ExtensionType) {
4077 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4080 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4081 Convert.ImplicitReferenceConversionExists (at, pt) ||
4082 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4087 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4090 dynamicArgument = true;
4095 // It can be applicable in expanded form (when not doing exact match like for delegates)
4097 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4098 if (!params_expanded_form)
4099 pt = ((ElementTypeSpec) pt).Element;
4102 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4105 params_expanded_form = true;
4106 } else if (score < 0) {
4107 params_expanded_form = true;
4108 dynamicArgument = true;
4113 if (params_expanded_form)
4115 return (arg_count - i) * 2 + score;
4120 // When params parameter has no argument it will be provided later if the method is the best candidate
4122 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4123 params_expanded_form = true;
4126 // Restore original arguments for dynamic binder to keep the intention of original source code
4128 if (dynamicArgument)
4129 arguments = orig_args;
4135 // Tests argument compatibility with the parameter
4136 // The possible return values are
4138 // 1 - modifier mismatch
4139 // 2 - type mismatch
4140 // -1 - dynamic binding required
4142 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4145 // Types have to be identical when ref or out modifer
4146 // is used and argument is not of dynamic type
4148 if ((argument.Modifier | param_mod) != 0) {
4149 if (argument.Type != parameter) {
4151 // Do full equality check after quick path
4153 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4155 // Using dynamic for ref/out parameter can still succeed at runtime
4157 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4164 if (argument.Modifier != param_mod) {
4166 // Using dynamic for ref/out parameter can still succeed at runtime
4168 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4175 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4179 // Deploy custom error reporting for lambda methods. When probing lambda methods
4180 // keep all errors reported in separate set and once we are done and no best
4181 // candidate was found, this set is used to report more details about what was wrong
4184 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4185 if (lambda_conv_msgs == null) {
4186 lambda_conv_msgs = new SessionReportPrinter ();
4187 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4192 // Use implicit conversion in all modes to return same candidates when the expression
4193 // is used as argument or delegate conversion
4195 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4196 if (lambda_conv_msgs != null) {
4197 lambda_conv_msgs.EndSession ();
4207 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4209 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4211 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4214 var ac_p = p as ArrayContainer;
4216 var ac_q = ((ArrayContainer) q);
4217 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4218 if (specific == ac_p.Element)
4220 if (specific == ac_q.Element)
4222 } else if (TypeManager.IsGenericType (p)) {
4223 var pargs = TypeManager.GetTypeArguments (p);
4224 var qargs = TypeManager.GetTypeArguments (q);
4226 bool p_specific_at_least_once = false;
4227 bool q_specific_at_least_once = false;
4229 for (int i = 0; i < pargs.Length; i++) {
4230 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4231 if (specific == pargs[i])
4232 p_specific_at_least_once = true;
4233 if (specific == qargs[i])
4234 q_specific_at_least_once = true;
4237 if (p_specific_at_least_once && !q_specific_at_least_once)
4239 if (!p_specific_at_least_once && q_specific_at_least_once)
4247 // Find the best method from candidate list
4249 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4251 List<AmbiguousCandidate> ambiguous_candidates = null;
4253 MemberSpec best_candidate;
4254 Arguments best_candidate_args = null;
4255 bool best_candidate_params = false;
4256 bool best_candidate_dynamic = false;
4257 int best_candidate_rate;
4258 IParametersMember best_parameter_member = null;
4260 int args_count = args != null ? args.Count : 0;
4262 Arguments candidate_args = args;
4263 bool error_mode = false;
4264 MemberSpec invocable_member = null;
4266 // Be careful, cannot return until error reporter is restored
4268 best_candidate = null;
4269 best_candidate_rate = int.MaxValue;
4271 var type_members = members;
4275 for (int i = 0; i < type_members.Count; ++i) {
4276 var member = type_members[i];
4279 // Methods in a base class are not candidates if any method in a derived
4280 // class is applicable
4282 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4286 if (!member.IsAccessible (rc))
4289 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4293 IParametersMember pm = member as IParametersMember;
4296 // Will use it later to report ambiguity between best method and invocable member
4298 if (Invocation.IsMemberInvocable (member))
4299 invocable_member = member;
4305 // Overload resolution is looking for base member but using parameter names
4306 // and default values from the closest member. That means to do expensive lookup
4307 // for the closest override for virtual or abstract members
4309 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4310 var override_params = base_provider.GetOverrideMemberParameters (member);
4311 if (override_params != null)
4312 pm = override_params;
4316 // Check if the member candidate is applicable
4318 bool params_expanded_form = false;
4319 bool dynamic_argument = false;
4320 TypeSpec rt = pm.MemberType;
4321 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4324 // How does it score compare to others
4326 if (candidate_rate < best_candidate_rate) {
4327 best_candidate_rate = candidate_rate;
4328 best_candidate = member;
4329 best_candidate_args = candidate_args;
4330 best_candidate_params = params_expanded_form;
4331 best_candidate_dynamic = dynamic_argument;
4332 best_parameter_member = pm;
4333 best_candidate_return_type = rt;
4334 } else if (candidate_rate == 0) {
4336 // The member look is done per type for most operations but sometimes
4337 // it's not possible like for binary operators overload because they
4338 // are unioned between 2 sides
4340 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4341 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4346 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4348 // We pack all interface members into top level type which makes the overload resolution
4349 // more complicated for interfaces. We compensate it by removing methods with same
4350 // signature when building the cache hence this path should not really be hit often
4353 // interface IA { void Foo (int arg); }
4354 // interface IB : IA { void Foo (params int[] args); }
4356 // IB::Foo is the best overload when calling IB.Foo (1)
4359 if (ambiguous_candidates != null) {
4360 foreach (var amb_cand in ambiguous_candidates) {
4361 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4370 ambiguous_candidates = null;
4373 // Is the new candidate better
4374 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4378 best_candidate = member;
4379 best_candidate_args = candidate_args;
4380 best_candidate_params = params_expanded_form;
4381 best_candidate_dynamic = dynamic_argument;
4382 best_parameter_member = pm;
4383 best_candidate_return_type = rt;
4385 // It's not better but any other found later could be but we are not sure yet
4386 if (ambiguous_candidates == null)
4387 ambiguous_candidates = new List<AmbiguousCandidate> ();
4389 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4393 // Restore expanded arguments
4394 if (candidate_args != args)
4395 candidate_args = args;
4397 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4399 if (prev_recorder != null)
4400 rc.Report.SetPrinter (prev_recorder);
4404 // We've found exact match
4406 if (best_candidate_rate == 0)
4410 // Try extension methods lookup when no ordinary method match was found and provider enables it
4413 var emg = base_provider.LookupExtensionMethod (rc);
4415 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4417 best_candidate_extension_group = emg;
4418 return (T) (MemberSpec) emg.BestCandidate;
4423 // Don't run expensive error reporting mode for probing
4430 lambda_conv_msgs = null;
4435 // No best member match found, report an error
4437 if (best_candidate_rate != 0 || error_mode) {
4438 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4442 if (best_candidate_dynamic) {
4443 if (args[0].ArgType == Argument.AType.ExtensionType) {
4444 rc.Report.Error (1973, loc,
4445 "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",
4446 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4449 BestCandidateIsDynamic = true;
4454 // These flags indicates we are running delegate probing conversion. No need to
4455 // do more expensive checks
4457 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4458 return (T) best_candidate;
4460 if (ambiguous_candidates != null) {
4462 // Now check that there are no ambiguities i.e the selected method
4463 // should be better than all the others
4465 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4466 var candidate = ambiguous_candidates [ix];
4468 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4469 var ambiguous = candidate.Member;
4470 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4471 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4472 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4473 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4474 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4477 return (T) best_candidate;
4482 if (invocable_member != null) {
4483 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4484 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4485 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4486 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4490 // And now check if the arguments are all
4491 // compatible, perform conversions if
4492 // necessary etc. and return if everything is
4495 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4498 if (best_candidate == null)
4502 // Check ObsoleteAttribute on the best method
4504 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4505 if (oa != null && !rc.IsObsolete)
4506 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4508 var dep = best_candidate.GetMissingDependencies ();
4510 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4513 best_candidate.MemberDefinition.SetIsUsed ();
4515 args = best_candidate_args;
4516 return (T) best_candidate;
4519 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4521 return ResolveMember<MethodSpec> (rc, ref args);
4524 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4525 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4527 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4530 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4531 ec.Report.SymbolRelatedToPreviousError (method);
4532 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4533 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4534 TypeManager.CSharpSignature (method));
4537 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4538 TypeManager.CSharpSignature (method));
4539 } else if (IsDelegateInvoke) {
4540 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4541 DelegateType.GetSignatureForError ());
4543 ec.Report.SymbolRelatedToPreviousError (method);
4544 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4545 method.GetSignatureForError ());
4548 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4550 string index = (idx + 1).ToString ();
4551 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4552 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4553 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4554 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4555 index, Parameter.GetModifierSignature (a.Modifier));
4557 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4558 index, Parameter.GetModifierSignature (mod));
4559 } else if (a.Expr != ErrorExpression.Instance) {
4560 string p1 = a.GetSignatureForError ();
4561 string p2 = TypeManager.CSharpName (paramType);
4564 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4565 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4568 ec.Report.Error (1503, loc,
4569 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4574 // We have failed to find exact match so we return error info about the closest match
4576 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4578 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4579 int arg_count = args == null ? 0 : args.Count;
4581 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4582 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4583 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4587 if (lambda_conv_msgs != null) {
4588 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4593 // For candidates which match on parameters count report more details about incorrect arguments
4596 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4597 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4598 // Reject any inaccessible member
4599 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4600 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4601 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4605 var ms = best_candidate as MethodSpec;
4606 if (ms != null && ms.IsGeneric) {
4607 bool constr_ok = true;
4608 if (ms.TypeArguments != null)
4609 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4611 if (ta_count == 0) {
4612 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4616 rc.Report.Error (411, loc,
4617 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4618 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4625 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4631 // We failed to find any method with correct argument count, report best candidate
4633 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4636 if (best_candidate.Kind == MemberKind.Constructor) {
4637 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4638 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4639 } else if (IsDelegateInvoke) {
4640 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4641 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4642 DelegateType.GetSignatureForError (), arg_count.ToString ());
4644 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4645 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4646 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4647 name, arg_count.ToString ());
4651 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4653 var pd = pm.Parameters;
4654 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4656 Parameter.Modifier p_mod = 0;
4658 int a_idx = 0, a_pos = 0;
4660 ArrayInitializer params_initializers = null;
4661 bool has_unsafe_arg = pm.MemberType.IsPointer;
4662 int arg_count = args == null ? 0 : args.Count;
4664 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4666 if (p_mod != Parameter.Modifier.PARAMS) {
4667 p_mod = pd.FixedParameters[a_idx].ModFlags;
4669 has_unsafe_arg |= pt.IsPointer;
4671 if (p_mod == Parameter.Modifier.PARAMS) {
4672 if (chose_params_expanded) {
4673 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4674 pt = TypeManager.GetElementType (pt);
4680 // Types have to be identical when ref or out modifer is used
4682 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4683 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4686 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4692 NamedArgument na = a as NamedArgument;
4694 int name_index = pd.GetParameterIndexByName (na.Name);
4695 if (name_index < 0 || name_index >= pd.Count) {
4696 if (IsDelegateInvoke) {
4697 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4698 ec.Report.Error (1746, na.Location,
4699 "The delegate `{0}' does not contain a parameter named `{1}'",
4700 DelegateType.GetSignatureForError (), na.Name);
4702 ec.Report.SymbolRelatedToPreviousError (member);
4703 ec.Report.Error (1739, na.Location,
4704 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4705 TypeManager.CSharpSignature (member), na.Name);
4707 } else if (args[name_index] != a) {
4708 if (IsDelegateInvoke)
4709 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4711 ec.Report.SymbolRelatedToPreviousError (member);
4713 ec.Report.Error (1744, na.Location,
4714 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4719 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4722 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4723 custom_errors.NoArgumentMatch (ec, member);
4727 Expression conv = null;
4728 if (a.ArgType == Argument.AType.ExtensionType) {
4729 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4732 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4734 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4737 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4744 // Convert params arguments to an array initializer
4746 if (params_initializers != null) {
4747 // we choose to use 'a.Expr' rather than 'conv' so that
4748 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4749 params_initializers.Add (a.Expr);
4750 args.RemoveAt (a_idx--);
4755 // Update the argument with the implicit conversion
4759 if (a_idx != arg_count) {
4760 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4765 // Fill not provided arguments required by params modifier
4767 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4769 args = new Arguments (1);
4771 pt = ptypes[pd.Count - 1];
4772 pt = TypeManager.GetElementType (pt);
4773 has_unsafe_arg |= pt.IsPointer;
4774 params_initializers = new ArrayInitializer (0, loc);
4778 // Append an array argument with all params arguments
4780 if (params_initializers != null) {
4781 args.Add (new Argument (
4782 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4786 if (has_unsafe_arg && !ec.IsUnsafe) {
4787 Expression.UnsafeError (ec, loc);
4791 // We could infer inaccesible type arguments
4793 if (type_arguments == null && member.IsGeneric) {
4794 var ms = (MethodSpec) member;
4795 foreach (var ta in ms.TypeArguments) {
4796 if (!ta.IsAccessible (ec)) {
4797 ec.Report.SymbolRelatedToPreviousError (ta);
4798 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4808 public class ConstantExpr : MemberExpr
4810 readonly ConstSpec constant;
4812 public ConstantExpr (ConstSpec constant, Location loc)
4814 this.constant = constant;
4818 public override string Name {
4819 get { throw new NotImplementedException (); }
4822 public override bool IsInstance {
4823 get { return !IsStatic; }
4826 public override bool IsStatic {
4827 get { return true; }
4830 protected override TypeSpec DeclaringType {
4831 get { return constant.DeclaringType; }
4834 public override Expression CreateExpressionTree (ResolveContext ec)
4836 throw new NotSupportedException ("ET");
4839 protected override Expression DoResolve (ResolveContext rc)
4841 ResolveInstanceExpression (rc, null);
4842 DoBestMemberChecks (rc, constant);
4844 var c = constant.GetConstant (rc);
4846 // Creates reference expression to the constant value
4847 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4850 public override void Emit (EmitContext ec)
4852 throw new NotSupportedException ();
4855 public override string GetSignatureForError ()
4857 return constant.GetSignatureForError ();
4860 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4862 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4867 // Fully resolved expression that references a Field
4869 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
4871 protected FieldSpec spec;
4872 VariableInfo variable_info;
4874 LocalTemporary temp;
4877 protected FieldExpr (Location l)
4882 public FieldExpr (FieldSpec spec, Location loc)
4887 type = spec.MemberType;
4890 public FieldExpr (FieldBase fi, Location l)
4897 public override string Name {
4903 public bool IsHoisted {
4905 IVariableReference hv = InstanceExpression as IVariableReference;
4906 return hv != null && hv.IsHoisted;
4910 public override bool IsInstance {
4912 return !spec.IsStatic;
4916 public override bool IsStatic {
4918 return spec.IsStatic;
4922 public FieldSpec Spec {
4928 protected override TypeSpec DeclaringType {
4930 return spec.DeclaringType;
4934 public VariableInfo VariableInfo {
4936 return variable_info;
4942 public override string GetSignatureForError ()
4944 return TypeManager.GetFullNameSignature (spec);
4947 public bool IsMarshalByRefAccess (ResolveContext rc)
4949 // Checks possible ldflda of field access expression
4950 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
4951 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
4952 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
4955 public void SetHasAddressTaken ()
4957 IVariableReference vr = InstanceExpression as IVariableReference;
4959 vr.SetHasAddressTaken ();
4962 public override Expression CreateExpressionTree (ResolveContext ec)
4964 Expression instance;
4965 if (InstanceExpression == null) {
4966 instance = new NullLiteral (loc);
4968 instance = InstanceExpression.CreateExpressionTree (ec);
4971 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4973 CreateTypeOfExpression ());
4975 return CreateExpressionFactoryCall (ec, "Field", args);
4978 public Expression CreateTypeOfExpression ()
4980 return new TypeOfField (spec, loc);
4983 protected override Expression DoResolve (ResolveContext ec)
4985 return DoResolve (ec, null);
4988 Expression DoResolve (ResolveContext ec, Expression rhs)
4990 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4993 if (ResolveInstanceExpression (ec, rhs)) {
4994 // Resolve the field's instance expression while flow analysis is turned
4995 // off: when accessing a field "a.b", we must check whether the field
4996 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4998 if (lvalue_instance) {
4999 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5000 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5002 Expression right_side =
5003 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5005 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5008 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5009 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5013 if (InstanceExpression == null)
5017 DoBestMemberChecks (ec, spec);
5020 var fb = spec as FixedFieldSpec;
5021 IVariableReference var = InstanceExpression as IVariableReference;
5023 if (lvalue_instance && var != null && var.VariableInfo != null) {
5024 var.VariableInfo.SetFieldAssigned (ec, Name);
5028 IFixedExpression fe = InstanceExpression as IFixedExpression;
5029 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5030 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5033 if (InstanceExpression.eclass != ExprClass.Variable) {
5034 ec.Report.SymbolRelatedToPreviousError (spec);
5035 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5036 TypeManager.GetFullNameSignature (spec));
5037 } else if (var != null && var.IsHoisted) {
5038 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5041 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5044 eclass = ExprClass.Variable;
5046 // If the instance expression is a local variable or parameter.
5047 if (var == null || var.VariableInfo == null)
5050 VariableInfo vi = var.VariableInfo;
5051 if (!vi.IsFieldAssigned (ec, Name, loc))
5054 variable_info = vi.GetSubStruct (Name);
5058 static readonly int [] codes = {
5059 191, // instance, write access
5060 192, // instance, out access
5061 198, // static, write access
5062 199, // static, out access
5063 1648, // member of value instance, write access
5064 1649, // member of value instance, out access
5065 1650, // member of value static, write access
5066 1651 // member of value static, out access
5069 static readonly string [] msgs = {
5070 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5071 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5072 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5073 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5074 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5075 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5076 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5077 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5080 // The return value is always null. Returning a value simplifies calling code.
5081 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5084 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5088 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5090 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5095 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5097 Expression e = DoResolve (ec, right_side);
5102 spec.MemberDefinition.SetIsAssigned ();
5104 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5105 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5106 ec.Report.Warning (420, 1, loc,
5107 "`{0}': A volatile field references will not be treated as volatile",
5108 spec.GetSignatureForError ());
5111 if (spec.IsReadOnly) {
5112 // InitOnly fields can only be assigned in constructors or initializers
5113 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5114 return Report_AssignToReadonly (ec, right_side);
5116 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5118 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5119 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5120 return Report_AssignToReadonly (ec, right_side);
5121 // static InitOnly fields cannot be assigned-to in an instance constructor
5122 if (IsStatic && !ec.IsStatic)
5123 return Report_AssignToReadonly (ec, right_side);
5124 // instance constructors can't modify InitOnly fields of other instances of the same type
5125 if (!IsStatic && !(InstanceExpression is This))
5126 return Report_AssignToReadonly (ec, right_side);
5130 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5131 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5132 ec.Report.Warning (197, 1, loc,
5133 "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",
5134 GetSignatureForError ());
5137 eclass = ExprClass.Variable;
5141 public override int GetHashCode ()
5143 return spec.GetHashCode ();
5146 public bool IsFixed {
5149 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5151 IVariableReference variable = InstanceExpression as IVariableReference;
5152 if (variable != null)
5153 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5155 IFixedExpression fe = InstanceExpression as IFixedExpression;
5156 return fe != null && fe.IsFixed;
5160 public override bool Equals (object obj)
5162 FieldExpr fe = obj as FieldExpr;
5166 if (spec != fe.spec)
5169 if (InstanceExpression == null || fe.InstanceExpression == null)
5172 return InstanceExpression.Equals (fe.InstanceExpression);
5175 public void Emit (EmitContext ec, bool leave_copy)
5177 bool is_volatile = false;
5179 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5182 spec.MemberDefinition.SetIsUsed ();
5186 ec.Emit (OpCodes.Volatile);
5188 ec.Emit (OpCodes.Ldsfld, spec);
5191 EmitInstance (ec, false);
5193 // Optimization for build-in types
5194 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5195 ec.EmitLoadFromPtr (type);
5197 var ff = spec as FixedFieldSpec;
5199 ec.Emit (OpCodes.Ldflda, spec);
5200 ec.Emit (OpCodes.Ldflda, ff.Element);
5203 ec.Emit (OpCodes.Volatile);
5205 ec.Emit (OpCodes.Ldfld, spec);
5211 ec.Emit (OpCodes.Dup);
5213 temp = new LocalTemporary (this.Type);
5219 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5221 if (source.ContainsEmitWithAwait ()) {
5222 source = source.EmitToField (ec);
5225 prepared = isCompound && !(source is DynamicExpressionStatement);
5227 EmitInstance (ec, prepared);
5232 ec.Emit (OpCodes.Dup);
5234 temp = new LocalTemporary (this.Type);
5239 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5240 ec.Emit (OpCodes.Volatile);
5242 spec.MemberDefinition.SetIsAssigned ();
5245 ec.Emit (OpCodes.Stsfld, spec);
5247 ec.Emit (OpCodes.Stfld, spec);
5257 // Emits store to field with prepared values on stack
5259 public void EmitAssignFromStack (EmitContext ec)
5262 ec.Emit (OpCodes.Stsfld, spec);
5264 ec.Emit (OpCodes.Stfld, spec);
5268 public override void Emit (EmitContext ec)
5273 public override void EmitSideEffect (EmitContext ec)
5275 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5277 if (is_volatile) // || is_marshal_by_ref ())
5278 base.EmitSideEffect (ec);
5281 public void AddressOf (EmitContext ec, AddressOp mode)
5283 if ((mode & AddressOp.Store) != 0)
5284 spec.MemberDefinition.SetIsAssigned ();
5285 if ((mode & AddressOp.Load) != 0)
5286 spec.MemberDefinition.SetIsUsed ();
5289 // Handle initonly fields specially: make a copy and then
5290 // get the address of the copy.
5293 if (spec.IsReadOnly){
5295 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5307 var temp = ec.GetTemporaryLocal (type);
5308 ec.Emit (OpCodes.Stloc, temp, type);
5309 ec.Emit (OpCodes.Ldloca, temp, type);
5310 ec.FreeTemporaryLocal (temp, type);
5316 ec.Emit (OpCodes.Ldsflda, spec);
5319 EmitInstance (ec, false);
5320 ec.Emit (OpCodes.Ldflda, spec);
5324 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5326 return MakeExpression (ctx);
5329 public override SLE.Expression MakeExpression (BuilderContext ctx)
5332 return base.MakeExpression (ctx);
5334 return SLE.Expression.Field (
5335 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5336 spec.GetMetaInfo ());
5340 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5342 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5348 // Expression that evaluates to a Property.
5350 // This is not an LValue because we need to re-write the expression. We
5351 // can not take data from the stack and store it.
5353 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5355 public PropertyExpr (PropertySpec spec, Location l)
5358 best_candidate = spec;
5359 type = spec.MemberType;
5364 protected override Arguments Arguments {
5372 protected override TypeSpec DeclaringType {
5374 return best_candidate.DeclaringType;
5378 public override string Name {
5380 return best_candidate.Name;
5384 public override bool IsInstance {
5390 public override bool IsStatic {
5392 return best_candidate.IsStatic;
5396 public PropertySpec PropertyInfo {
5398 return best_candidate;
5404 public override Expression CreateExpressionTree (ResolveContext ec)
5407 if (IsSingleDimensionalArrayLength ()) {
5408 args = new Arguments (1);
5409 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5410 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5413 args = new Arguments (2);
5414 if (InstanceExpression == null)
5415 args.Add (new Argument (new NullLiteral (loc)));
5417 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5418 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5419 return CreateExpressionFactoryCall (ec, "Property", args);
5422 public Expression CreateSetterTypeOfExpression ()
5424 return new TypeOfMethod (Setter, loc);
5427 public override string GetSignatureForError ()
5429 return best_candidate.GetSignatureForError ();
5432 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5435 return base.MakeExpression (ctx);
5437 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5441 public override SLE.Expression MakeExpression (BuilderContext ctx)
5444 return base.MakeExpression (ctx);
5446 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5450 void Error_PropertyNotValid (ResolveContext ec)
5452 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5453 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5454 GetSignatureForError ());
5457 bool IsSingleDimensionalArrayLength ()
5459 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5462 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5463 return ac != null && ac.Rank == 1;
5466 public override void Emit (EmitContext ec, bool leave_copy)
5469 // Special case: length of single dimension array property is turned into ldlen
5471 if (IsSingleDimensionalArrayLength ()) {
5472 EmitInstance (ec, false);
5473 ec.Emit (OpCodes.Ldlen);
5474 ec.Emit (OpCodes.Conv_I4);
5478 base.Emit (ec, leave_copy);
5481 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5484 LocalTemporary await_source_arg = null;
5486 if (isCompound && !(source is DynamicExpressionStatement)) {
5487 emitting_compound_assignment = true;
5490 if (has_await_arguments) {
5491 await_source_arg = new LocalTemporary (Type);
5492 await_source_arg.Store (ec);
5494 has_await_arguments = false;
5496 args = new Arguments (1);
5497 args.Add (new Argument (await_source_arg));
5503 ec.Emit (OpCodes.Dup);
5505 temp = new LocalTemporary (this.Type);
5510 args = new Arguments (1);
5514 temp = new LocalTemporary (this.Type);
5516 args.Add (new Argument (temp));
5518 args.Add (new Argument (source));
5522 emitting_compound_assignment = false;
5524 var call = new CallEmitter ();
5525 call.InstanceExpression = InstanceExpression;
5527 call.InstanceExpressionOnStack = true;
5529 call.Emit (ec, Setter, args, loc);
5536 if (await_source_arg != null) {
5537 await_source_arg.Release (ec);
5541 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5543 eclass = ExprClass.PropertyAccess;
5545 if (best_candidate.IsNotCSharpCompatible) {
5546 Error_PropertyNotValid (rc);
5549 ResolveInstanceExpression (rc, right_side);
5551 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5552 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5553 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5555 type = p.MemberType;
5559 DoBestMemberChecks (rc, best_candidate);
5563 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5565 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5569 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5571 // getter and setter can be different for base calls
5572 MethodSpec getter, setter;
5573 protected T best_candidate;
5575 protected LocalTemporary temp;
5576 protected bool emitting_compound_assignment;
5577 protected bool has_await_arguments;
5579 protected PropertyOrIndexerExpr (Location l)
5586 protected abstract Arguments Arguments { get; set; }
5588 public MethodSpec Getter {
5597 public MethodSpec Setter {
5608 protected override Expression DoResolve (ResolveContext ec)
5610 if (eclass == ExprClass.Unresolved) {
5611 var expr = OverloadResolve (ec, null);
5616 return expr.Resolve (ec);
5619 if (!ResolveGetter (ec))
5625 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5627 if (right_side == EmptyExpression.OutAccess) {
5628 // TODO: best_candidate can be null at this point
5629 INamedBlockVariable variable = null;
5630 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5631 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5632 best_candidate.Name);
5634 right_side.DoResolveLValue (ec, this);
5639 // if the property/indexer returns a value type, and we try to set a field in it
5640 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5641 Error_CannotModifyIntermediateExpressionValue (ec);
5644 if (eclass == ExprClass.Unresolved) {
5645 var expr = OverloadResolve (ec, right_side);
5650 return expr.ResolveLValue (ec, right_side);
5653 if (!ResolveSetter (ec))
5660 // Implements the IAssignMethod interface for assignments
5662 public virtual void Emit (EmitContext ec, bool leave_copy)
5664 var call = new CallEmitter ();
5665 call.InstanceExpression = InstanceExpression;
5666 if (has_await_arguments)
5667 call.HasAwaitArguments = true;
5669 call.DuplicateArguments = emitting_compound_assignment;
5671 call.Emit (ec, Getter, Arguments, loc);
5673 if (call.HasAwaitArguments) {
5674 InstanceExpression = call.InstanceExpression;
5675 Arguments = call.EmittedArguments;
5676 has_await_arguments = true;
5680 ec.Emit (OpCodes.Dup);
5681 temp = new LocalTemporary (Type);
5686 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5688 public override void Emit (EmitContext ec)
5693 protected override void EmitToFieldSource (EmitContext ec)
5695 has_await_arguments = true;
5699 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5701 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5703 bool ResolveGetter (ResolveContext rc)
5705 if (!best_candidate.HasGet) {
5706 if (InstanceExpression != EmptyExpression.Null) {
5707 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5708 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5709 best_candidate.GetSignatureForError ());
5712 } else if (!best_candidate.Get.IsAccessible (rc)) {
5713 if (best_candidate.HasDifferentAccessibility) {
5714 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5715 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5716 TypeManager.CSharpSignature (best_candidate));
5718 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5719 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5723 if (best_candidate.HasDifferentAccessibility) {
5724 CheckProtectedMemberAccess (rc, best_candidate.Get);
5727 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5731 bool ResolveSetter (ResolveContext rc)
5733 if (!best_candidate.HasSet) {
5734 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5735 GetSignatureForError ());
5739 if (!best_candidate.Set.IsAccessible (rc)) {
5740 if (best_candidate.HasDifferentAccessibility) {
5741 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5742 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5743 GetSignatureForError ());
5745 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5746 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5750 if (best_candidate.HasDifferentAccessibility)
5751 CheckProtectedMemberAccess (rc, best_candidate.Set);
5753 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5759 /// Fully resolved expression that evaluates to an Event
5761 public class EventExpr : MemberExpr, IAssignMethod
5763 readonly EventSpec spec;
5766 public EventExpr (EventSpec spec, Location loc)
5774 protected override TypeSpec DeclaringType {
5776 return spec.DeclaringType;
5780 public override string Name {
5786 public override bool IsInstance {
5788 return !spec.IsStatic;
5792 public override bool IsStatic {
5794 return spec.IsStatic;
5798 public MethodSpec Operator {
5806 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5809 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5811 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5812 if (spec.BackingField != null &&
5813 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5815 spec.MemberDefinition.SetIsUsed ();
5817 if (!ec.IsObsolete) {
5818 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5820 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5823 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5824 Error_AssignmentEventOnly (ec);
5826 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5828 InstanceExpression = null;
5830 return ml.ResolveMemberAccess (ec, left, original);
5834 return base.ResolveMemberAccess (ec, left, original);
5837 public override Expression CreateExpressionTree (ResolveContext ec)
5839 throw new NotSupportedException ("ET");
5842 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5844 if (right_side == EmptyExpression.EventAddition) {
5845 op = spec.AccessorAdd;
5846 } else if (right_side == EmptyExpression.EventSubtraction) {
5847 op = spec.AccessorRemove;
5851 Error_AssignmentEventOnly (ec);
5855 op = CandidateToBaseOverride (ec, op);
5859 protected override Expression DoResolve (ResolveContext ec)
5861 eclass = ExprClass.EventAccess;
5862 type = spec.MemberType;
5864 ResolveInstanceExpression (ec, null);
5866 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5867 Error_AssignmentEventOnly (ec);
5870 DoBestMemberChecks (ec, spec);
5874 public override void Emit (EmitContext ec)
5876 throw new NotSupportedException ();
5877 //Error_CannotAssign ();
5880 #region IAssignMethod Members
5882 public void Emit (EmitContext ec, bool leave_copy)
5884 throw new NotImplementedException ();
5887 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5889 if (leave_copy || !isCompound)
5890 throw new NotImplementedException ("EventExpr::EmitAssign");
5892 Arguments args = new Arguments (1);
5893 args.Add (new Argument (source));
5895 var call = new CallEmitter ();
5896 call.InstanceExpression = InstanceExpression;
5897 call.Emit (ec, op, args, loc);
5902 void Error_AssignmentEventOnly (ResolveContext ec)
5904 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5905 ec.Report.Error (79, loc,
5906 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5907 GetSignatureForError ());
5909 ec.Report.Error (70, loc,
5910 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5911 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5915 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5917 name = name.Substring (0, name.LastIndexOf ('.'));
5918 base.Error_CannotCallAbstractBase (rc, name);
5921 public override string GetSignatureForError ()
5923 return TypeManager.CSharpSignature (spec);
5926 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5928 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
5932 public class TemporaryVariableReference : VariableReference
5934 public class Declarator : Statement
5936 TemporaryVariableReference variable;
5938 public Declarator (TemporaryVariableReference variable)
5940 this.variable = variable;
5944 protected override void DoEmit (EmitContext ec)
5946 variable.li.CreateBuilder (ec);
5949 protected override void CloneTo (CloneContext clonectx, Statement target)
5957 public TemporaryVariableReference (LocalVariable li, Location loc)
5960 this.type = li.Type;
5964 public override bool IsLockedByStatement {
5972 public LocalVariable LocalInfo {
5978 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5980 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5981 return new TemporaryVariableReference (li, loc);
5984 public override Expression CreateExpressionTree (ResolveContext ec)
5986 throw new NotSupportedException ("ET");
5989 protected override Expression DoResolve (ResolveContext ec)
5991 eclass = ExprClass.Variable;
5994 // Don't capture temporary variables except when using
5995 // iterator redirection
5997 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5998 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5999 storey.CaptureLocalVariable (ec, li);
6005 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6007 return Resolve (ec);
6010 public override void Emit (EmitContext ec)
6012 li.CreateBuilder (ec);
6017 public void EmitAssign (EmitContext ec, Expression source)
6019 li.CreateBuilder (ec);
6021 EmitAssign (ec, source, false, false);
6024 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6026 return li.HoistedVariant;
6029 public override bool IsFixed {
6030 get { return true; }
6033 public override bool IsRef {
6034 get { return false; }
6037 public override string Name {
6038 get { throw new NotImplementedException (); }
6041 public override void SetHasAddressTaken ()
6043 throw new NotImplementedException ();
6046 protected override ILocalVariable Variable {
6050 public override VariableInfo VariableInfo {
6051 get { throw new NotImplementedException (); }
6056 /// Handles `var' contextual keyword; var becomes a keyword only
6057 /// if no type called var exists in a variable scope
6059 class VarExpr : SimpleName
6061 public VarExpr (Location loc)
6066 public bool InferType (ResolveContext ec, Expression right_side)
6069 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6071 type = right_side.Type;
6072 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6073 ec.Report.Error (815, loc,
6074 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6075 type.GetSignatureForError ());
6079 eclass = ExprClass.Variable;
6083 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6085 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6086 base.Error_TypeOrNamespaceNotFound (ec);
6088 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");