2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public ResolveFlags ExprClassToResolveFlags {
380 case ExprClass.Namespace:
381 return ResolveFlags.Type;
383 case ExprClass.MethodGroup:
384 return ResolveFlags.MethodGroup;
386 case ExprClass.TypeParameter:
387 return ResolveFlags.TypeParameter;
389 case ExprClass.Value:
390 case ExprClass.Variable:
391 case ExprClass.PropertyAccess:
392 case ExprClass.EventAccess:
393 case ExprClass.IndexerAccess:
394 return ResolveFlags.VariableOrValue;
397 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
403 // Implements identical simple name and type-name resolution
405 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
408 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
411 // 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
412 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
414 if (left is MemberExpr || left is VariableReference) {
415 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
416 if (identical_type != null && identical_type.Type == left.Type)
417 return identical_type;
423 public virtual string GetSignatureForError ()
425 return type.GetDefinition ().GetSignatureForError ();
429 /// Resolves an expression and performs semantic analysis on it.
433 /// Currently Resolve wraps DoResolve to perform sanity
434 /// checking and assertion checking on what we expect from Resolve.
436 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
438 if (eclass != ExprClass.Unresolved) {
439 if ((flags & ExprClassToResolveFlags) == 0) {
440 Error_UnexpectedKind (ec, flags, loc);
454 if ((flags & e.ExprClassToResolveFlags) == 0) {
455 e.Error_UnexpectedKind (ec, flags, loc);
460 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
463 } catch (Exception ex) {
464 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
467 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
468 return ErrorExpression.Instance; // TODO: Add location
473 /// Resolves an expression and performs semantic analysis on it.
475 public Expression Resolve (ResolveContext rc)
477 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
481 /// Resolves an expression for LValue assignment
485 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
486 /// checking and assertion checking on what we expect from Resolve
488 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
490 int errors = ec.Report.Errors;
491 bool out_access = right_side == EmptyExpression.OutAccess;
493 Expression e = DoResolveLValue (ec, right_side);
495 if (e != null && out_access && !(e is IMemoryLocation)) {
496 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
497 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
499 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
500 // e.GetType () + " " + e.GetSignatureForError ());
505 if (errors == ec.Report.Errors) {
506 Error_ValueAssignment (ec, right_side);
511 if (e.eclass == ExprClass.Unresolved)
512 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
514 if ((e.type == null) && !(e is GenericTypeExpr))
515 throw new Exception ("Expression " + e + " did not set its type after Resolve");
520 public Constant ResolveLabelConstant (ResolveContext rc)
522 var expr = Resolve (rc);
526 Constant c = expr as Constant;
528 if (c.type != InternalType.ErrorType)
529 rc.Report.Error (150, StartLocation, "A constant value is expected");
537 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
539 rc.Module.Compiler.Report.Error (182, loc,
540 "An attribute argument must be a constant expression, typeof expression or array creation expression");
544 /// Emits the code for the expression
548 /// The Emit method is invoked to generate the code
549 /// for the expression.
551 public abstract void Emit (EmitContext ec);
554 // Emit code to branch to @target if this expression is equivalent to @on_true.
555 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
556 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
557 // including the use of conditional branches. Note also that a branch MUST be emitted
558 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
561 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
564 // Emit this expression for its side effects, not for its value.
565 // The default implementation is to emit the value, and then throw it away.
566 // Subclasses can provide more efficient implementations, but those MUST be equivalent
567 public virtual void EmitSideEffect (EmitContext ec)
570 ec.Emit (OpCodes.Pop);
574 // Emits the expression into temporary field variable. The method
575 // should be used for await expressions only
577 public virtual Expression EmitToField (EmitContext ec)
580 // This is the await prepare Emit method. When emitting code like
581 // a + b we emit code like
587 // For await a + await b we have to interfere the flow to keep the
588 // stack clean because await yields from the expression. The emit
591 // a = a.EmitToField () // a is changed to temporary field access
592 // b = b.EmitToField ()
598 // The idea is to emit expression and leave the stack empty with
599 // result value still available.
601 // Expressions should override this default implementation when
602 // optimized version can be provided (e.g. FieldExpr)
605 // We can optimize for side-effect free expressions, they can be
606 // emitted out of order
608 if (IsSideEffectFree)
611 bool needs_temporary = ContainsEmitWithAwait ();
612 if (!needs_temporary)
615 // Emit original code
616 var field = EmitToFieldSource (ec);
619 // Store the result to temporary field when we
620 // cannot load `this' directly
622 field = ec.GetTemporaryField (type);
623 if (needs_temporary) {
625 // Create temporary local (we cannot load `this' before Emit)
627 var temp = ec.GetTemporaryLocal (type);
628 ec.Emit (OpCodes.Stloc, temp);
631 ec.Emit (OpCodes.Ldloc, temp);
632 field.EmitAssignFromStack (ec);
634 ec.FreeTemporaryLocal (temp, type);
636 field.EmitAssignFromStack (ec);
643 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
646 // Default implementation calls Emit method
652 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
654 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
655 bool contains_await = false;
657 for (int i = 1; i < expressions.Count; ++i) {
658 if (expressions[i].ContainsEmitWithAwait ()) {
659 contains_await = true;
664 if (contains_await) {
665 for (int i = 0; i < expressions.Count; ++i) {
666 expressions[i] = expressions[i].EmitToField (ec);
671 for (int i = 0; i < expressions.Count; ++i) {
672 expressions[i].Emit (ec);
677 /// Protected constructor. Only derivate types should
678 /// be able to be created
681 protected Expression ()
686 /// Returns a fully formed expression after a MemberLookup
689 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
691 if (spec is EventSpec)
692 return new EventExpr ((EventSpec) spec, loc);
693 if (spec is ConstSpec)
694 return new ConstantExpr ((ConstSpec) spec, loc);
695 if (spec is FieldSpec)
696 return new FieldExpr ((FieldSpec) spec, loc);
697 if (spec is PropertySpec)
698 return new PropertyExpr ((PropertySpec) spec, loc);
699 if (spec is TypeSpec)
700 return new TypeExpression (((TypeSpec) spec), loc);
705 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
707 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
709 rc.Report.SymbolRelatedToPreviousError (type);
711 // Report meaningful error for struct as they always have default ctor in C# context
712 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
714 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
715 type.GetSignatureForError ());
721 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
722 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
723 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
726 return r.ResolveMember<MethodSpec> (rc, ref args);
730 public enum MemberLookupRestrictions
739 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
740 // `qualifier_type' or null to lookup members in the current class.
742 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
744 var members = MemberCache.FindMembers (queried_type, name, false);
748 MemberSpec non_method = null;
749 MemberSpec ambig_non_method = null;
751 for (int i = 0; i < members.Count; ++i) {
752 var member = members[i];
754 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
755 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
758 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
761 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
765 if (!member.IsAccessible (rc))
769 // With runtime binder we can have a situation where queried type is inaccessible
770 // because it came via dynamic object, the check about inconsisted accessibility
771 // had no effect as the type was unknown during compilation
774 // private class N { }
776 // public dynamic Foo ()
782 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
786 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
787 if (member is MethodSpec) {
789 // Interface members that are hidden by class members are removed from the set. This
790 // step only has an effect if T is a type parameter and T has both an effective base
791 // class other than object and a non-empty effective interface set
793 var tps = queried_type as TypeParameterSpec;
794 if (tps != null && tps.HasTypeConstraint)
795 members = RemoveHiddenTypeParameterMethods (members);
797 return new MethodGroupExpr (members, queried_type, loc);
800 if (!Invocation.IsMemberInvocable (member))
804 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
806 } else if (!errorMode && !member.IsNotCSharpCompatible) {
808 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
809 // T has both an effective base class other than object and a non-empty effective interface set.
811 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
813 var tps = queried_type as TypeParameterSpec;
814 if (tps != null && tps.HasTypeConstraint) {
815 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
818 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
824 ambig_non_method = member;
828 if (non_method != null) {
829 if (ambig_non_method != null && rc != null) {
830 var report = rc.Module.Compiler.Report;
831 report.SymbolRelatedToPreviousError (non_method);
832 report.SymbolRelatedToPreviousError (ambig_non_method);
833 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
834 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
837 if (non_method is MethodSpec)
838 return new MethodGroupExpr (members, queried_type, loc);
840 return ExprClassFromMemberInfo (non_method, loc);
843 if (members[0].DeclaringType.BaseType == null)
846 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
848 } while (members != null);
853 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
855 if (members.Count < 2)
859 // If M is a method, then all non-method members declared in an interface declaration
860 // are removed from the set, and all methods with the same signature as M declared in
861 // an interface declaration are removed from the set
865 for (int i = 0; i < members.Count; ++i) {
866 var method = members[i] as MethodSpec;
867 if (method == null) {
870 members = new List<MemberSpec> (members);
873 members.RemoveAt (i--);
877 if (!method.DeclaringType.IsInterface)
880 for (int ii = 0; ii < members.Count; ++ii) {
881 var candidate = members[ii] as MethodSpec;
882 if (candidate == null || !candidate.DeclaringType.IsClass)
885 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
890 members = new List<MemberSpec> (members);
893 members.RemoveAt (i--);
901 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
903 throw new NotImplementedException ();
906 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
908 if (t == InternalType.ErrorType)
911 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
912 oper, t.GetSignatureForError ());
915 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
917 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
921 /// Returns an expression that can be used to invoke operator true
922 /// on the expression if it exists.
924 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
926 return GetOperatorTrueOrFalse (ec, e, true, loc);
930 /// Returns an expression that can be used to invoke operator false
931 /// on the expression if it exists.
933 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
935 return GetOperatorTrueOrFalse (ec, e, false, loc);
938 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
940 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
941 var methods = MemberCache.GetUserOperator (e.type, op, false);
945 Arguments arguments = new Arguments (1);
946 arguments.Add (new Argument (e));
948 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
949 var oper = res.ResolveOperator (ec, ref arguments);
954 return new UserOperatorCall (oper, arguments, null, loc);
957 public virtual string ExprClassName
961 case ExprClass.Unresolved:
963 case ExprClass.Value:
965 case ExprClass.Variable:
967 case ExprClass.Namespace:
971 case ExprClass.MethodGroup:
972 return "method group";
973 case ExprClass.PropertyAccess:
974 return "property access";
975 case ExprClass.EventAccess:
976 return "event access";
977 case ExprClass.IndexerAccess:
978 return "indexer access";
979 case ExprClass.Nothing:
981 case ExprClass.TypeParameter:
982 return "type parameter";
984 throw new Exception ("Should not happen");
989 /// Reports that we were expecting `expr' to be of class `expected'
991 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
993 var name = memberExpr.GetSignatureForError ();
995 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
998 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1000 string [] valid = new string [4];
1003 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1004 valid [count++] = "variable";
1005 valid [count++] = "value";
1008 if ((flags & ResolveFlags.Type) != 0)
1009 valid [count++] = "type";
1011 if ((flags & ResolveFlags.MethodGroup) != 0)
1012 valid [count++] = "method group";
1015 valid [count++] = "unknown";
1017 StringBuilder sb = new StringBuilder (valid [0]);
1018 for (int i = 1; i < count - 1; i++) {
1020 sb.Append (valid [i]);
1023 sb.Append ("' or `");
1024 sb.Append (valid [count - 1]);
1027 ec.Report.Error (119, loc,
1028 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1031 public static void UnsafeError (ResolveContext ec, Location loc)
1033 UnsafeError (ec.Report, loc);
1036 public static void UnsafeError (Report Report, Location loc)
1038 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1042 // Converts `source' to an int, uint, long or ulong.
1044 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1046 var btypes = ec.BuiltinTypes;
1048 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1049 Arguments args = new Arguments (1);
1050 args.Add (new Argument (source));
1051 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1054 Expression converted;
1056 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1057 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1058 if (converted == null)
1059 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1060 if (converted == null)
1061 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1062 if (converted == null)
1063 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1065 if (converted == null) {
1066 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1072 // Only positive constants are allowed at compile time
1074 Constant c = converted as Constant;
1075 if (c != null && c.IsNegative)
1076 Error_NegativeArrayIndex (ec, source.loc);
1078 // No conversion needed to array index
1079 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1082 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1086 // Derived classes implement this method by cloning the fields that
1087 // could become altered during the Resolve stage
1089 // Only expressions that are created for the parser need to implement
1092 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1094 throw new NotImplementedException (
1096 "CloneTo not implemented for expression {0}", this.GetType ()));
1100 // Clones an expression created by the parser.
1102 // We only support expressions created by the parser so far, not
1103 // expressions that have been resolved (many more classes would need
1104 // to implement CloneTo).
1106 // This infrastructure is here merely for Lambda expressions which
1107 // compile the same code using different type values for the same
1108 // arguments to find the correct overload
1110 public virtual Expression Clone (CloneContext clonectx)
1112 Expression cloned = (Expression) MemberwiseClone ();
1113 CloneTo (clonectx, cloned);
1119 // Implementation of expression to expression tree conversion
1121 public abstract Expression CreateExpressionTree (ResolveContext ec);
1123 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1125 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1128 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1130 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1133 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1135 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1138 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1140 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1144 return new TypeExpression (t, loc);
1148 // Implemented by all expressions which support conversion from
1149 // compiler expression to invokable runtime expression. Used by
1150 // dynamic C# binder.
1152 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1154 throw new NotImplementedException ("MakeExpression for " + GetType ());
1157 public virtual object Accept (StructuralVisitor visitor)
1159 return visitor.Visit (this);
1164 /// This is just a base class for expressions that can
1165 /// appear on statements (invocations, object creation,
1166 /// assignments, post/pre increment and decrement). The idea
1167 /// being that they would support an extra Emition interface that
1168 /// does not leave a result on the stack.
1170 public abstract class ExpressionStatement : Expression
1172 public ExpressionStatement ResolveStatement (BlockContext ec)
1174 Expression e = Resolve (ec);
1178 ExpressionStatement es = e as ExpressionStatement;
1180 Error_InvalidExpressionStatement (ec);
1183 // This is quite expensive warning, try to limit the damage
1185 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1186 WarningAsyncWithoutWait (ec, e);
1192 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1194 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1195 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1200 // Need to do full resolve because GetAwaiter can be extension method
1201 // available only in this context
1203 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1207 var arguments = new Arguments (0);
1208 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1213 // Use same check rules as for real await
1215 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1216 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1219 bc.Report.Warning (4014, 1, e.Location,
1220 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1224 var inv = e as Invocation;
1225 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1226 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1227 bc.Report.Warning (4014, 1, e.Location,
1228 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1234 /// Requests the expression to be emitted in a `statement'
1235 /// context. This means that no new value is left on the
1236 /// stack after invoking this method (constrasted with
1237 /// Emit that will always leave a value on the stack).
1239 public abstract void EmitStatement (EmitContext ec);
1241 public override void EmitSideEffect (EmitContext ec)
1248 /// This kind of cast is used to encapsulate the child
1249 /// whose type is child.Type into an expression that is
1250 /// reported to return "return_type". This is used to encapsulate
1251 /// expressions which have compatible types, but need to be dealt
1252 /// at higher levels with.
1254 /// For example, a "byte" expression could be encapsulated in one
1255 /// of these as an "unsigned int". The type for the expression
1256 /// would be "unsigned int".
1259 public abstract class TypeCast : Expression
1261 protected readonly Expression child;
1263 protected TypeCast (Expression child, TypeSpec return_type)
1265 eclass = child.eclass;
1266 loc = child.Location;
1271 public Expression Child {
1277 public override bool ContainsEmitWithAwait ()
1279 return child.ContainsEmitWithAwait ();
1282 public override Expression CreateExpressionTree (ResolveContext ec)
1284 Arguments args = new Arguments (2);
1285 args.Add (new Argument (child.CreateExpressionTree (ec)));
1286 args.Add (new Argument (new TypeOf (type, loc)));
1288 if (type.IsPointer || child.Type.IsPointer)
1289 Error_PointerInsideExpressionTree (ec);
1291 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1294 protected override Expression DoResolve (ResolveContext ec)
1296 // This should never be invoked, we are born in fully
1297 // initialized state.
1302 public override void Emit (EmitContext ec)
1307 public override SLE.Expression MakeExpression (BuilderContext ctx)
1310 return base.MakeExpression (ctx);
1312 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1313 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1314 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1318 protected override void CloneTo (CloneContext clonectx, Expression t)
1323 public override bool IsNull {
1324 get { return child.IsNull; }
1328 public class EmptyCast : TypeCast {
1329 EmptyCast (Expression child, TypeSpec target_type)
1330 : base (child, target_type)
1334 public static Expression Create (Expression child, TypeSpec type)
1336 Constant c = child as Constant;
1338 var enum_constant = c as EnumConstant;
1339 if (enum_constant != null)
1340 c = enum_constant.Child;
1342 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1346 var res = c.ConvertImplicitly (type);
1352 EmptyCast e = child as EmptyCast;
1354 return new EmptyCast (e.child, type);
1356 return new EmptyCast (child, type);
1359 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1361 child.EmitBranchable (ec, label, on_true);
1364 public override void EmitSideEffect (EmitContext ec)
1366 child.EmitSideEffect (ec);
1371 // Used for predefined type user operator (no obsolete check, etc.)
1373 public class OperatorCast : TypeCast
1375 readonly MethodSpec conversion_operator;
1377 public OperatorCast (Expression expr, TypeSpec target_type)
1378 : this (expr, target_type, target_type, false)
1382 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1383 : this (expr, target_type, target_type, find_explicit)
1387 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1388 : base (expr, returnType)
1390 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1391 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1394 foreach (MethodSpec oper in mi) {
1395 if (oper.ReturnType != returnType)
1398 if (oper.Parameters.Types[0] == expr.Type) {
1399 conversion_operator = oper;
1405 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1406 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1409 public override void Emit (EmitContext ec)
1412 ec.Emit (OpCodes.Call, conversion_operator);
1417 // Constant specialization of EmptyCast.
1418 // We need to special case this since an empty cast of
1419 // a constant is still a constant.
1421 public class EmptyConstantCast : Constant
1423 public readonly Constant child;
1425 public EmptyConstantCast (Constant child, TypeSpec type)
1426 : base (child.Location)
1429 throw new ArgumentNullException ("child");
1432 this.eclass = child.eclass;
1436 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1438 if (child.Type == target_type)
1441 // FIXME: check that 'type' can be converted to 'target_type' first
1442 return child.ConvertExplicitly (in_checked_context, target_type);
1445 public override Expression CreateExpressionTree (ResolveContext ec)
1447 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1448 child.CreateExpressionTree (ec),
1449 new TypeOf (type, loc));
1452 Error_PointerInsideExpressionTree (ec);
1454 return CreateExpressionFactoryCall (ec, "Convert", args);
1457 public override bool IsDefaultValue {
1458 get { return child.IsDefaultValue; }
1461 public override bool IsNegative {
1462 get { return child.IsNegative; }
1465 public override bool IsNull {
1466 get { return child.IsNull; }
1469 public override bool IsOneInteger {
1470 get { return child.IsOneInteger; }
1473 public override bool IsSideEffectFree {
1475 return child.IsSideEffectFree;
1479 public override bool IsZeroInteger {
1480 get { return child.IsZeroInteger; }
1483 public override void Emit (EmitContext ec)
1488 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1490 child.EmitBranchable (ec, label, on_true);
1492 // Only to make verifier happy
1493 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1494 ec.Emit (OpCodes.Unbox_Any, type);
1497 public override void EmitSideEffect (EmitContext ec)
1499 child.EmitSideEffect (ec);
1502 public override object GetValue ()
1504 return child.GetValue ();
1507 public override string GetValueAsLiteral ()
1509 return child.GetValueAsLiteral ();
1512 public override long GetValueAsLong ()
1514 return child.GetValueAsLong ();
1517 public override Constant ConvertImplicitly (TypeSpec target_type)
1519 if (type == target_type)
1522 // FIXME: Do we need to check user conversions?
1523 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1526 return child.ConvertImplicitly (target_type);
1531 /// This class is used to wrap literals which belong inside Enums
1533 public class EnumConstant : Constant
1535 public Constant Child;
1537 public EnumConstant (Constant child, TypeSpec enum_type)
1538 : base (child.Location)
1542 this.eclass = ExprClass.Value;
1543 this.type = enum_type;
1546 protected EnumConstant (Location loc)
1551 public override void Emit (EmitContext ec)
1556 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1558 Child.EncodeAttributeValue (rc, enc, Child.Type);
1561 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1563 Child.EmitBranchable (ec, label, on_true);
1566 public override void EmitSideEffect (EmitContext ec)
1568 Child.EmitSideEffect (ec);
1571 public override string GetSignatureForError()
1573 return Type.GetSignatureForError ();
1576 public override object GetValue ()
1578 return Child.GetValue ();
1582 public override object GetTypedValue ()
1585 // The method can be used in dynamic context only (on closed types)
1587 // System.Enum.ToObject cannot be called on dynamic types
1588 // EnumBuilder has to be used, but we cannot use EnumBuilder
1589 // because it does not properly support generics
1591 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1595 public override string GetValueAsLiteral ()
1597 return Child.GetValueAsLiteral ();
1600 public override long GetValueAsLong ()
1602 return Child.GetValueAsLong ();
1605 public EnumConstant Increment()
1607 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1610 public override bool IsDefaultValue {
1612 return Child.IsDefaultValue;
1616 public override bool IsSideEffectFree {
1618 return Child.IsSideEffectFree;
1622 public override bool IsZeroInteger {
1623 get { return Child.IsZeroInteger; }
1626 public override bool IsNegative {
1628 return Child.IsNegative;
1632 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1634 if (Child.Type == target_type)
1637 return Child.ConvertExplicitly (in_checked_context, target_type);
1640 public override Constant ConvertImplicitly (TypeSpec type)
1642 if (this.type == type) {
1646 if (!Convert.ImplicitStandardConversionExists (this, type)){
1650 return Child.ConvertImplicitly (type);
1655 /// This kind of cast is used to encapsulate Value Types in objects.
1657 /// The effect of it is to box the value type emitted by the previous
1660 public class BoxedCast : TypeCast {
1662 public BoxedCast (Expression expr, TypeSpec target_type)
1663 : base (expr, target_type)
1665 eclass = ExprClass.Value;
1668 protected override Expression DoResolve (ResolveContext ec)
1670 // This should never be invoked, we are born in fully
1671 // initialized state.
1676 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1678 // Only boxing to object type is supported
1679 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1680 base.EncodeAttributeValue (rc, enc, targetType);
1684 enc.Encode (child.Type);
1685 child.EncodeAttributeValue (rc, enc, child.Type);
1688 public override void Emit (EmitContext ec)
1692 ec.Emit (OpCodes.Box, child.Type);
1695 public override void EmitSideEffect (EmitContext ec)
1697 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1698 // so, we need to emit the box+pop instructions in most cases
1699 if (child.Type.IsStruct &&
1700 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1701 child.EmitSideEffect (ec);
1703 base.EmitSideEffect (ec);
1707 public class UnboxCast : TypeCast {
1708 public UnboxCast (Expression expr, TypeSpec return_type)
1709 : base (expr, return_type)
1713 protected override Expression DoResolve (ResolveContext ec)
1715 // This should never be invoked, we are born in fully
1716 // initialized state.
1721 public override void Emit (EmitContext ec)
1725 ec.Emit (OpCodes.Unbox_Any, type);
1730 /// This is used to perform explicit numeric conversions.
1732 /// Explicit numeric conversions might trigger exceptions in a checked
1733 /// context, so they should generate the conv.ovf opcodes instead of
1736 public class ConvCast : TypeCast {
1737 public enum Mode : byte {
1738 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1740 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1741 U2_I1, U2_U1, U2_I2, U2_CH,
1742 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1743 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1744 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1745 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1746 CH_I1, CH_U1, CH_I2,
1747 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1748 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1754 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1755 : base (child, return_type)
1760 protected override Expression DoResolve (ResolveContext ec)
1762 // This should never be invoked, we are born in fully
1763 // initialized state.
1768 public override string ToString ()
1770 return String.Format ("ConvCast ({0}, {1})", mode, child);
1773 public override void Emit (EmitContext ec)
1779 public static void Emit (EmitContext ec, Mode mode)
1781 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1783 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1784 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1785 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1786 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1787 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1789 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1790 case Mode.U1_CH: /* nothing */ break;
1792 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1793 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1794 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1795 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1796 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1797 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1799 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1800 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1801 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1802 case Mode.U2_CH: /* nothing */ break;
1804 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1805 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1806 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1807 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1808 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1809 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1810 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1812 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1813 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1814 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1815 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1816 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1817 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1819 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1820 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1821 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1822 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1823 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1824 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1825 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1826 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1827 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1829 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1830 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1831 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1832 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1833 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1834 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1835 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1836 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1837 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1839 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1840 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1841 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1843 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1844 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1845 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1846 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1847 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1848 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1849 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1850 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1851 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1853 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1854 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1855 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1856 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1857 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1858 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1859 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1860 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1861 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1862 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1864 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1868 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1869 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1870 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1871 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1872 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1874 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1875 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1877 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1878 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1879 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1880 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1881 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1882 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1884 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1885 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1886 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1887 case Mode.U2_CH: /* nothing */ break;
1889 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1890 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1891 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1892 case Mode.I4_U4: /* nothing */ break;
1893 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1894 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1895 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1897 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1898 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1899 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1900 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1901 case Mode.U4_I4: /* nothing */ break;
1902 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1904 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1905 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1906 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1907 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1908 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1909 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1910 case Mode.I8_U8: /* nothing */ break;
1911 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1912 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1914 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1915 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1916 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1917 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1918 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1919 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1920 case Mode.U8_I8: /* nothing */ break;
1921 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1922 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1924 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1925 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1926 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1928 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1929 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1930 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1931 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1932 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1933 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1934 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1935 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1936 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1938 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1939 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1940 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1941 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1942 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1943 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1944 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1945 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1946 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1947 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1949 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1955 class OpcodeCast : TypeCast
1959 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1960 : base (child, return_type)
1965 protected override Expression DoResolve (ResolveContext ec)
1967 // This should never be invoked, we are born in fully
1968 // initialized state.
1973 public override void Emit (EmitContext ec)
1979 public TypeSpec UnderlyingType {
1980 get { return child.Type; }
1985 // Opcode casts expression with 2 opcodes but only
1986 // single expression tree node
1988 class OpcodeCastDuplex : OpcodeCast
1990 readonly OpCode second;
1992 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1993 : base (child, returnType, first)
1995 this.second = second;
1998 public override void Emit (EmitContext ec)
2006 /// This kind of cast is used to encapsulate a child and cast it
2007 /// to the class requested
2009 public sealed class ClassCast : TypeCast {
2010 readonly bool forced;
2012 public ClassCast (Expression child, TypeSpec return_type)
2013 : base (child, return_type)
2017 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2018 : base (child, return_type)
2020 this.forced = forced;
2023 public override void Emit (EmitContext ec)
2027 bool gen = TypeManager.IsGenericParameter (child.Type);
2029 ec.Emit (OpCodes.Box, child.Type);
2031 if (type.IsGenericParameter) {
2032 ec.Emit (OpCodes.Unbox_Any, type);
2039 ec.Emit (OpCodes.Castclass, type);
2044 // Created during resolving pahse when an expression is wrapped or constantified
2045 // and original expression can be used later (e.g. for expression trees)
2047 public class ReducedExpression : Expression
2049 public sealed class ReducedConstantExpression : EmptyConstantCast
2051 readonly Expression orig_expr;
2053 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2054 : base (expr, expr.Type)
2056 this.orig_expr = orig_expr;
2059 public override Constant ConvertImplicitly (TypeSpec target_type)
2061 Constant c = base.ConvertImplicitly (target_type);
2063 c = new ReducedConstantExpression (c, orig_expr);
2068 public override Expression CreateExpressionTree (ResolveContext ec)
2070 return orig_expr.CreateExpressionTree (ec);
2073 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2075 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2077 c = new ReducedConstantExpression (c, orig_expr);
2081 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2084 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2086 if (orig_expr is Conditional)
2087 child.EncodeAttributeValue (rc, enc, targetType);
2089 base.EncodeAttributeValue (rc, enc, targetType);
2093 sealed class ReducedExpressionStatement : ExpressionStatement
2095 readonly Expression orig_expr;
2096 readonly ExpressionStatement stm;
2098 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2100 this.orig_expr = orig;
2102 this.eclass = stm.eclass;
2103 this.type = stm.Type;
2105 this.loc = orig.Location;
2108 public override bool ContainsEmitWithAwait ()
2110 return stm.ContainsEmitWithAwait ();
2113 public override Expression CreateExpressionTree (ResolveContext ec)
2115 return orig_expr.CreateExpressionTree (ec);
2118 protected override Expression DoResolve (ResolveContext ec)
2123 public override void Emit (EmitContext ec)
2128 public override void EmitStatement (EmitContext ec)
2130 stm.EmitStatement (ec);
2134 readonly Expression expr, orig_expr;
2136 private ReducedExpression (Expression expr, Expression orig_expr)
2139 this.eclass = expr.eclass;
2140 this.type = expr.Type;
2141 this.orig_expr = orig_expr;
2142 this.loc = orig_expr.Location;
2147 public override bool IsSideEffectFree {
2149 return expr.IsSideEffectFree;
2153 public Expression OriginalExpression {
2161 public override bool ContainsEmitWithAwait ()
2163 return expr.ContainsEmitWithAwait ();
2167 // Creates fully resolved expression switcher
2169 public static Constant Create (Constant expr, Expression original_expr)
2171 if (expr.eclass == ExprClass.Unresolved)
2172 throw new ArgumentException ("Unresolved expression");
2174 return new ReducedConstantExpression (expr, original_expr);
2177 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2179 return new ReducedExpressionStatement (s, orig);
2182 public static Expression Create (Expression expr, Expression original_expr)
2184 return Create (expr, original_expr, true);
2188 // Creates unresolved reduce expression. The original expression has to be
2189 // already resolved. Created expression is constant based based on `expr'
2190 // value unless canBeConstant is used
2192 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2194 if (canBeConstant) {
2195 Constant c = expr as Constant;
2197 return Create (c, original_expr);
2200 ExpressionStatement s = expr as ExpressionStatement;
2202 return Create (s, original_expr);
2204 if (expr.eclass == ExprClass.Unresolved)
2205 throw new ArgumentException ("Unresolved expression");
2207 return new ReducedExpression (expr, original_expr);
2210 public override Expression CreateExpressionTree (ResolveContext ec)
2212 return orig_expr.CreateExpressionTree (ec);
2215 protected override Expression DoResolve (ResolveContext ec)
2220 public override void Emit (EmitContext ec)
2225 public override Expression EmitToField (EmitContext ec)
2227 return expr.EmitToField(ec);
2230 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2232 expr.EmitBranchable (ec, target, on_true);
2235 public override SLE.Expression MakeExpression (BuilderContext ctx)
2237 return orig_expr.MakeExpression (ctx);
2242 // Standard composite pattern
2244 public abstract class CompositeExpression : Expression
2246 protected Expression expr;
2248 protected CompositeExpression (Expression expr)
2251 this.loc = expr.Location;
2254 public override bool ContainsEmitWithAwait ()
2256 return expr.ContainsEmitWithAwait ();
2259 public override Expression CreateExpressionTree (ResolveContext rc)
2261 return expr.CreateExpressionTree (rc);
2264 public Expression Child {
2265 get { return expr; }
2268 protected override Expression DoResolve (ResolveContext rc)
2270 expr = expr.Resolve (rc);
2273 eclass = expr.eclass;
2279 public override void Emit (EmitContext ec)
2284 public override bool IsNull {
2285 get { return expr.IsNull; }
2290 // Base of expressions used only to narrow resolve flow
2292 public abstract class ShimExpression : Expression
2294 protected Expression expr;
2296 protected ShimExpression (Expression expr)
2301 public Expression Expr {
2307 protected override void CloneTo (CloneContext clonectx, Expression t)
2312 ShimExpression target = (ShimExpression) t;
2313 target.expr = expr.Clone (clonectx);
2316 public override bool ContainsEmitWithAwait ()
2318 return expr.ContainsEmitWithAwait ();
2321 public override Expression CreateExpressionTree (ResolveContext ec)
2323 throw new NotSupportedException ("ET");
2326 public override void Emit (EmitContext ec)
2328 throw new InternalErrorException ("Missing Resolve call");
2334 // Unresolved type name expressions
2336 public abstract class ATypeNameExpression : FullNamedExpression
2339 protected TypeArguments targs;
2341 protected ATypeNameExpression (string name, Location l)
2347 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2354 protected ATypeNameExpression (string name, int arity, Location l)
2355 : this (name, new UnboundTypeArguments (arity), l)
2361 protected int Arity {
2363 return targs == null ? 0 : targs.Count;
2367 public bool HasTypeArguments {
2369 return targs != null && !targs.IsEmpty;
2373 public string Name {
2382 public TypeArguments TypeArguments {
2390 public override bool Equals (object obj)
2392 ATypeNameExpression atne = obj as ATypeNameExpression;
2393 return atne != null && atne.Name == Name &&
2394 (targs == null || targs.Equals (atne.targs));
2397 public override int GetHashCode ()
2399 return Name.GetHashCode ();
2402 // TODO: Move it to MemberCore
2403 public static string GetMemberType (MemberCore mc)
2409 if (mc is FieldBase)
2411 if (mc is MethodCore)
2413 if (mc is EnumMember)
2421 public override string GetSignatureForError ()
2423 if (targs != null) {
2424 return Name + "<" + targs.GetSignatureForError () + ">";
2430 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2434 /// SimpleName expressions are formed of a single word and only happen at the beginning
2435 /// of a dotted-name.
2437 public class SimpleName : ATypeNameExpression
2439 public SimpleName (string name, Location l)
2444 public SimpleName (string name, TypeArguments args, Location l)
2445 : base (name, args, l)
2449 public SimpleName (string name, int arity, Location l)
2450 : base (name, arity, l)
2454 public SimpleName GetMethodGroup ()
2456 return new SimpleName (Name, targs, loc);
2459 protected override Expression DoResolve (ResolveContext rc)
2461 var e = SimpleNameResolve (rc, null);
2463 var fe = e as FieldExpr;
2465 fe.VerifyAssignedStructField (rc, null);
2471 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2473 return SimpleNameResolve (ec, right_side);
2476 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2478 if (ctx.CurrentType != null) {
2479 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2480 if (member != null) {
2481 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2486 var report = ctx.Module.Compiler.Report;
2488 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2489 if (retval != null) {
2490 report.SymbolRelatedToPreviousError (retval.Type);
2491 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2495 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2496 if (retval != null) {
2497 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2501 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2502 if (ns_candidates != null) {
2503 if (ctx is UsingAliasNamespace.AliasContext) {
2504 report.Error (246, loc,
2505 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2506 ns_candidates[0], Name);
2508 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2509 report.Error (246, loc,
2510 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2514 report.Error (246, loc,
2515 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2520 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2522 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2525 if (fne.Type != null && Arity > 0) {
2526 if (HasTypeArguments) {
2527 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2528 if (ct.ResolveAsType (mc) == null)
2534 return new GenericOpenTypeExpr (fne.Type, loc);
2538 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2540 if (!(fne is Namespace))
2544 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2545 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2546 mc.Module.Compiler.Report.Error (1980, Location,
2547 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2548 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2551 fne = new DynamicTypeExpr (loc);
2552 fne.ResolveAsType (mc);
2558 Error_TypeOrNamespaceNotFound (mc);
2562 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2564 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2567 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2569 int lookup_arity = Arity;
2570 bool errorMode = false;
2572 Block current_block = rc.CurrentBlock;
2573 INamedBlockVariable variable = null;
2574 bool variable_found = false;
2578 // Stage 1: binding to local variables or parameters
2580 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2582 if (current_block != null && lookup_arity == 0) {
2583 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2584 if (!variable.IsDeclared) {
2585 // We found local name in accessible block but it's not
2586 // initialized yet, maybe the user wanted to bind to something else
2588 variable_found = true;
2590 e = variable.CreateReferenceExpression (rc, loc);
2593 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2602 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2604 TypeSpec member_type = rc.CurrentType;
2605 for (; member_type != null; member_type = member_type.DeclaringType) {
2606 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2610 var me = e as MemberExpr;
2612 // The name matches a type, defer to ResolveAsTypeStep
2620 if (variable != null) {
2621 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2622 rc.Report.Error (844, loc,
2623 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2624 Name, me.GetSignatureForError ());
2628 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2629 // Leave it to overload resolution to report correct error
2631 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2632 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2635 // LAMESPEC: again, ignores InvocableOnly
2636 if (variable != null) {
2637 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2638 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2642 // MemberLookup does not check accessors availability, this is actually needed for properties only
2644 var pe = me as PropertyExpr;
2647 // Break as there is no other overload available anyway
2648 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2649 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2652 pe.Getter = pe.PropertyInfo.Get;
2654 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2657 pe.Setter = pe.PropertyInfo.Set;
2662 // TODO: It's used by EventExpr -> FieldExpr transformation only
2663 // TODO: Should go to MemberAccess
2664 me = me.ResolveMemberAccess (rc, null, null);
2668 me.SetTypeArguments (rc, targs);
2675 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2677 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2678 if (IsPossibleTypeOrNamespace (rc)) {
2679 if (variable != null) {
2680 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2681 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2684 return ResolveAsTypeOrNamespace (rc);
2689 if (variable_found) {
2690 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2693 var tparams = rc.CurrentTypeParameters;
2694 if (tparams != null) {
2695 if (tparams.Find (Name) != null) {
2696 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2701 var ct = rc.CurrentType;
2703 if (ct.MemberDefinition.TypeParametersCount > 0) {
2704 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2705 if (ctp.Name == Name) {
2706 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2712 ct = ct.DeclaringType;
2713 } while (ct != null);
2716 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2717 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2719 rc.Report.SymbolRelatedToPreviousError (e.Type);
2720 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2724 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2726 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2727 return ErrorExpression.Instance;
2731 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2733 if (e.Type.Arity != Arity) {
2734 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2738 if (e is TypeExpr) {
2739 // TypeExpression does not have correct location
2740 if (e is TypeExpression)
2741 e = new TypeExpression (e.Type, loc);
2747 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2750 return ErrorExpression.Instance;
2753 if (rc.Module.Evaluator != null) {
2754 var fi = rc.Module.Evaluator.LookupField (Name);
2756 return new FieldExpr (fi.Item1, loc);
2764 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2766 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2771 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2772 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2776 if (right_side != null) {
2777 e = e.ResolveLValue (ec, right_side);
2785 public override object Accept (StructuralVisitor visitor)
2787 return visitor.Visit (this);
2792 /// Represents a namespace or a type. The name of the class was inspired by
2793 /// section 10.8.1 (Fully Qualified Names).
2795 public abstract class FullNamedExpression : Expression
2797 protected override void CloneTo (CloneContext clonectx, Expression target)
2799 // Do nothing, most unresolved type expressions cannot be
2800 // resolved to different type
2803 public override bool ContainsEmitWithAwait ()
2808 public override Expression CreateExpressionTree (ResolveContext ec)
2810 throw new NotSupportedException ("ET");
2813 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2816 // This is used to resolve the expression as a type, a null
2817 // value will be returned if the expression is not a type
2820 public override TypeSpec ResolveAsType (IMemberContext mc)
2822 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2827 TypeExpr te = fne as TypeExpr;
2829 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2837 var dep = type.GetMissingDependencies ();
2839 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2842 if (type.Kind == MemberKind.Void) {
2843 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2847 // Obsolete checks cannot be done when resolving base context as they
2848 // require type dependencies to be set but we are in process of resolving them
2850 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2851 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2852 if (obsolete_attr != null && !mc.IsObsolete) {
2853 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2861 public override void Emit (EmitContext ec)
2863 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2864 GetSignatureForError ());
2869 /// Expression that evaluates to a type
2871 public abstract class TypeExpr : FullNamedExpression
2873 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2879 protected sealed override Expression DoResolve (ResolveContext ec)
2885 public override bool Equals (object obj)
2887 TypeExpr tobj = obj as TypeExpr;
2891 return Type == tobj.Type;
2894 public override int GetHashCode ()
2896 return Type.GetHashCode ();
2901 /// Fully resolved Expression that already evaluated to a type
2903 public class TypeExpression : TypeExpr
2905 public TypeExpression (TypeSpec t, Location l)
2908 eclass = ExprClass.Type;
2912 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2919 /// This class denotes an expression which evaluates to a member
2920 /// of a struct or a class.
2922 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2925 // An instance expression associated with this member, if it's a
2926 // non-static member
2928 public Expression InstanceExpression;
2931 /// The name of this member.
2933 public abstract string Name {
2938 // When base.member is used
2940 public bool IsBase {
2941 get { return InstanceExpression is BaseThis; }
2945 /// Whether this is an instance member.
2947 public abstract bool IsInstance {
2952 /// Whether this is a static member.
2954 public abstract bool IsStatic {
2958 public abstract string KindName {
2962 protected abstract TypeSpec DeclaringType {
2966 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2968 return InstanceExpression.Type;
2973 // Converts best base candidate for virtual method starting from QueriedBaseType
2975 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2978 // Only when base.member is used and method is virtual
2984 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2985 // means for base.member access we have to find the closest match after we found best candidate
2987 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2989 // The method could already be what we are looking for
2991 TypeSpec[] targs = null;
2992 if (method.DeclaringType != InstanceExpression.Type) {
2993 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2994 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2995 if (base_override.IsGeneric)
2996 targs = method.TypeArguments;
2998 method = base_override;
3003 // When base access is used inside anonymous method/iterator/etc we need to
3004 // get back to the context of original type. We do it by emiting proxy
3005 // method in original class and rewriting base call to this compiler
3006 // generated method call which does the actual base invocation. This may
3007 // introduce redundant storey but with `this' only but it's tricky to avoid
3008 // at this stage as we don't know what expressions follow base
3010 if (rc.CurrentAnonymousMethod != null) {
3011 if (targs == null && method.IsGeneric) {
3012 targs = method.TypeArguments;
3013 method = method.GetGenericMethodDefinition ();
3016 if (method.Parameters.HasArglist)
3017 throw new NotImplementedException ("__arglist base call proxy");
3019 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3021 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3022 // get/set member expressions second call would fail to proxy because left expression
3023 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3024 // FIXME: The async check is another hack but will probably fail with mutators
3025 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3026 InstanceExpression = new This (loc).Resolve (rc);
3030 method = method.MakeGenericMethod (rc, targs);
3034 // Only base will allow this invocation to happen.
3036 if (method.IsAbstract) {
3037 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3043 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3045 if (InstanceExpression == null)
3048 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3049 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3050 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3055 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3057 if (InstanceExpression == null)
3060 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3063 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3065 var ct = rc.CurrentType;
3066 if (ct == qualifier)
3069 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3072 qualifier = qualifier.GetDefinition ();
3073 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3080 public override bool ContainsEmitWithAwait ()
3082 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3085 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3088 type = type.GetDefinition ();
3090 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3093 type = type.DeclaringType;
3094 } while (type != null);
3099 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3101 if (InstanceExpression != null) {
3102 InstanceExpression = InstanceExpression.Resolve (rc);
3103 CheckProtectedMemberAccess (rc, member);
3106 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3107 UnsafeError (rc, loc);
3110 var dep = member.GetMissingDependencies ();
3112 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3115 if (!rc.IsObsolete) {
3116 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3118 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3121 if (!(member is FieldSpec))
3122 member.MemberDefinition.SetIsUsed ();
3125 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3127 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3130 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3132 rc.Report.SymbolRelatedToPreviousError (member);
3133 rc.Report.Error (1540, loc,
3134 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3135 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3138 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3140 if (!ResolveInstanceExpressionCore (rc, rhs))
3144 // Check intermediate value modification which won't have any effect
3146 if (rhs != null && InstanceExpression.Type.IsStruct &&
3147 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3149 if (rc.CurrentInitializerVariable != null) {
3150 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3151 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3153 rc.Report.Error (1612, loc,
3154 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3155 InstanceExpression.GetSignatureForError ());
3162 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3165 if (InstanceExpression != null) {
3166 if (InstanceExpression is TypeExpr) {
3167 var t = InstanceExpression.Type;
3169 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3170 if (oa != null && !rc.IsObsolete) {
3171 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3174 t = t.DeclaringType;
3175 } while (t != null);
3177 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3178 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3179 rc.Report.Error (176, loc,
3180 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3181 GetSignatureForError ());
3185 InstanceExpression = null;
3191 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3192 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3193 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3194 rc.Report.Error (236, loc,
3195 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3196 GetSignatureForError ());
3198 rc.Report.Error (120, loc,
3199 "An object reference is required to access non-static member `{0}'",
3200 GetSignatureForError ());
3202 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3206 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3207 rc.Report.Error (38, loc,
3208 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3209 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3212 InstanceExpression = new This (loc);
3213 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3214 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3215 InstanceExpression = InstanceExpression.Resolve (rc);
3218 InstanceExpression = InstanceExpression.Resolve (rc);
3224 var me = InstanceExpression as MemberExpr;
3226 me.ResolveInstanceExpressionCore (rc, rhs);
3228 // Using this check to detect probing instance expression resolve
3229 if (!rc.OmitStructFlowAnalysis) {
3230 var fe = me as FieldExpr;
3231 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3232 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3233 rc.Report.Warning (1690, 1, loc,
3234 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3235 me.GetSignatureForError ());
3243 // Run member-access postponed check once we know that
3244 // the expression is not field expression which is the only
3245 // expression which can use uninitialized this
3247 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3248 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3252 // Additional checks for l-value member access
3255 if (InstanceExpression is UnboxCast) {
3256 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3263 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3265 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3266 ec.Report.Warning (1720, 1, left.Location,
3267 "Expression will always cause a `{0}'", "System.NullReferenceException");
3270 InstanceExpression = left;
3274 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3276 TypeSpec instance_type = InstanceExpression.Type;
3277 if (TypeSpec.IsValueType (instance_type)) {
3278 if (InstanceExpression is IMemoryLocation) {
3279 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3281 // Cannot release the temporary variable when its address
3282 // is required to be on stack for any parent
3283 LocalTemporary t = new LocalTemporary (instance_type);
3284 InstanceExpression.Emit (ec);
3286 t.AddressOf (ec, AddressOp.Store);
3289 InstanceExpression.Emit (ec);
3291 // Only to make verifier happy
3292 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3293 ec.Emit (OpCodes.Box, instance_type);
3296 if (prepare_for_load)
3297 ec.Emit (OpCodes.Dup);
3300 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3303 public class ExtensionMethodCandidates
3305 readonly NamespaceContainer container;
3306 readonly IList<MethodSpec> methods;
3308 readonly IMemberContext context;
3310 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3312 this.context = context;
3313 this.methods = methods;
3314 this.container = nsContainer;
3315 this.index = lookupIndex;
3318 public NamespaceContainer Container {
3324 public IMemberContext Context {
3330 public int LookupIndex {
3336 public IList<MethodSpec> Methods {
3344 // Represents a group of extension method candidates for whole namespace
3346 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3348 ExtensionMethodCandidates candidates;
3349 public Expression ExtensionExpression;
3351 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3352 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3354 this.candidates = candidates;
3355 this.ExtensionExpression = extensionExpr;
3358 public override bool IsStatic {
3359 get { return true; }
3363 // For extension methodgroup we are not looking for base members but parent
3364 // namespace extension methods
3366 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3368 // TODO: candidates are null only when doing error reporting, that's
3369 // incorrect. We have to discover same extension methods in error mode
3370 if (candidates == null)
3373 int arity = type_arguments == null ? 0 : type_arguments.Count;
3375 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3376 if (candidates == null)
3379 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3382 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3384 // We are already here
3388 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3390 if (arguments == null)
3391 arguments = new Arguments (1);
3393 ExtensionExpression = ExtensionExpression.Resolve (ec);
3394 if (ExtensionExpression == null)
3397 var cand = candidates;
3398 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3399 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3401 // Restore candidates in case we are running in probing mode
3404 // Store resolved argument and restore original arguments
3406 // Clean-up modified arguments for error reporting
3407 arguments.RemoveAt (0);
3411 var me = ExtensionExpression as MemberExpr;
3413 me.ResolveInstanceExpression (ec, null);
3414 var fe = me as FieldExpr;
3416 fe.Spec.MemberDefinition.SetIsUsed ();
3419 InstanceExpression = null;
3423 #region IErrorHandler Members
3425 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3430 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3432 rc.Report.SymbolRelatedToPreviousError (best);
3433 rc.Report.Error (1928, loc,
3434 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3435 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3438 rc.Report.Error (1929, loc,
3439 "Extension method instance type `{0}' cannot be converted to `{1}'",
3440 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3446 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3451 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3460 /// MethodGroupExpr represents a group of method candidates which
3461 /// can be resolved to the best method overload
3463 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3465 protected IList<MemberSpec> Methods;
3466 MethodSpec best_candidate;
3467 TypeSpec best_candidate_return;
3468 protected TypeArguments type_arguments;
3470 SimpleName simple_name;
3471 protected TypeSpec queried_type;
3473 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3477 this.type = InternalType.MethodGroup;
3479 eclass = ExprClass.MethodGroup;
3480 queried_type = type;
3483 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3484 : this (new MemberSpec[] { m }, type, loc)
3490 public MethodSpec BestCandidate {
3492 return best_candidate;
3496 public TypeSpec BestCandidateReturnType {
3498 return best_candidate_return;
3502 public IList<MemberSpec> Candidates {
3508 protected override TypeSpec DeclaringType {
3510 return queried_type;
3514 public override bool IsInstance {
3516 if (best_candidate != null)
3517 return !best_candidate.IsStatic;
3523 public override bool IsStatic {
3525 if (best_candidate != null)
3526 return best_candidate.IsStatic;
3532 public override string KindName {
3533 get { return "method"; }
3536 public override string Name {
3538 if (best_candidate != null)
3539 return best_candidate.Name;
3542 return Methods.First ().Name;
3549 // When best candidate is already know this factory can be used
3550 // to avoid expensive overload resolution to be called
3552 // NOTE: InstanceExpression has to be set manually
3554 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3556 return new MethodGroupExpr (best, queriedType, loc) {
3557 best_candidate = best,
3558 best_candidate_return = best.ReturnType
3562 public override string GetSignatureForError ()
3564 if (best_candidate != null)
3565 return best_candidate.GetSignatureForError ();
3567 return Methods.First ().GetSignatureForError ();
3570 public override Expression CreateExpressionTree (ResolveContext ec)
3572 if (best_candidate == null) {
3573 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3577 if (best_candidate.IsConditionallyExcluded (ec, loc))
3578 ec.Report.Error (765, loc,
3579 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3581 return new TypeOfMethod (best_candidate, loc);
3584 protected override Expression DoResolve (ResolveContext ec)
3586 this.eclass = ExprClass.MethodGroup;
3588 if (InstanceExpression != null) {
3589 InstanceExpression = InstanceExpression.Resolve (ec);
3590 if (InstanceExpression == null)
3597 public override void Emit (EmitContext ec)
3599 throw new NotSupportedException ();
3602 public void EmitCall (EmitContext ec, Arguments arguments)
3604 var call = new CallEmitter ();
3605 call.InstanceExpression = InstanceExpression;
3606 call.Emit (ec, best_candidate, arguments, loc);
3609 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3611 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3612 Name, target.GetSignatureForError ());
3615 public static bool IsExtensionMethodArgument (Expression expr)
3618 // LAMESPEC: No details about which expressions are not allowed
3620 return !(expr is TypeExpr) && !(expr is BaseThis);
3624 /// Find the Applicable Function Members (7.4.2.1)
3626 /// me: Method Group expression with the members to select.
3627 /// it might contain constructors or methods (or anything
3628 /// that maps to a method).
3630 /// Arguments: ArrayList containing resolved Argument objects.
3632 /// loc: The location if we want an error to be reported, or a Null
3633 /// location for "probing" purposes.
3635 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3636 /// that is the best match of me on Arguments.
3639 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3641 // TODO: causes issues with probing mode, remove explicit Kind check
3642 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3645 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3646 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3647 r.BaseMembersProvider = this;
3648 r.InstanceQualifier = this;
3651 if (cerrors != null)
3652 r.CustomErrors = cerrors;
3654 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3655 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3656 if (best_candidate == null)
3657 return r.BestCandidateIsDynamic ? this : null;
3659 // Overload resolver had to create a new method group, all checks bellow have already been executed
3660 if (r.BestCandidateNewMethodGroup != null)
3661 return r.BestCandidateNewMethodGroup;
3663 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3664 if (InstanceExpression != null) {
3665 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3666 InstanceExpression = null;
3668 if (best_candidate.IsStatic && simple_name != null) {
3669 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3672 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3676 ResolveInstanceExpression (ec, null);
3679 var base_override = CandidateToBaseOverride (ec, best_candidate);
3680 if (base_override == best_candidate) {
3681 best_candidate_return = r.BestCandidateReturnType;
3683 best_candidate = base_override;
3684 best_candidate_return = best_candidate.ReturnType;
3687 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3688 ConstraintChecker cc = new ConstraintChecker (ec);
3689 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3693 // Additional check for possible imported base override method which
3694 // could not be done during IsOverrideMethodBaseTypeAccessible
3696 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3697 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3698 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3699 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3705 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3707 var fe = left as FieldExpr;
3710 // Using method-group on struct fields makes the struct assigned. I am not sure
3711 // why but that's what .net does
3713 fe.Spec.MemberDefinition.SetIsAssigned ();
3716 simple_name = original;
3717 return base.ResolveMemberAccess (ec, left, original);
3720 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3722 type_arguments = ta;
3725 #region IBaseMembersProvider Members
3727 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3729 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3732 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3734 if (queried_type == member.DeclaringType)
3737 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3738 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3742 // Extension methods lookup after ordinary methods candidates failed to apply
3744 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3746 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3749 InstanceExpression = InstanceExpression.Resolve (rc);
3750 if (!IsExtensionMethodArgument (InstanceExpression))
3753 int arity = type_arguments == null ? 0 : type_arguments.Count;
3754 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3755 if (methods == null)
3758 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3759 emg.SetTypeArguments (rc, type_arguments);
3766 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3768 public ConstructorInstanceQualifier (TypeSpec type)
3771 InstanceType = type;
3774 public TypeSpec InstanceType { get; private set; }
3776 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3778 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3782 public struct OverloadResolver
3785 public enum Restrictions
3789 ProbingOnly = 1 << 1,
3790 CovariantDelegate = 1 << 2,
3791 NoBaseMembers = 1 << 3,
3792 BaseMembersIncluded = 1 << 4
3795 public interface IBaseMembersProvider
3797 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3798 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3799 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3802 public interface IErrorHandler
3804 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3805 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3806 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3807 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3810 public interface IInstanceQualifier
3812 TypeSpec InstanceType { get; }
3813 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3816 sealed class NoBaseMembers : IBaseMembersProvider
3818 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3820 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3825 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3830 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3836 struct AmbiguousCandidate
3838 public readonly MemberSpec Member;
3839 public readonly bool Expanded;
3840 public readonly AParametersCollection Parameters;
3842 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3845 Parameters = parameters;
3846 Expanded = expanded;
3851 IList<MemberSpec> members;
3852 TypeArguments type_arguments;
3853 IBaseMembersProvider base_provider;
3854 IErrorHandler custom_errors;
3855 IInstanceQualifier instance_qualifier;
3856 Restrictions restrictions;
3857 MethodGroupExpr best_candidate_extension_group;
3858 TypeSpec best_candidate_return_type;
3860 SessionReportPrinter lambda_conv_msgs;
3862 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3863 : this (members, null, restrictions, loc)
3867 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3870 if (members == null || members.Count == 0)
3871 throw new ArgumentException ("empty members set");
3873 this.members = members;
3875 type_arguments = targs;
3876 this.restrictions = restrictions;
3877 if (IsDelegateInvoke)
3878 this.restrictions |= Restrictions.NoBaseMembers;
3880 base_provider = NoBaseMembers.Instance;
3885 public IBaseMembersProvider BaseMembersProvider {
3887 return base_provider;
3890 base_provider = value;
3894 public bool BestCandidateIsDynamic { get; set; }
3897 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3899 public MethodGroupExpr BestCandidateNewMethodGroup {
3901 return best_candidate_extension_group;
3906 // Return type can be different between best candidate and closest override
3908 public TypeSpec BestCandidateReturnType {
3910 return best_candidate_return_type;
3914 public IErrorHandler CustomErrors {
3916 return custom_errors;
3919 custom_errors = value;
3923 TypeSpec DelegateType {
3925 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3926 throw new InternalErrorException ("Not running in delegate mode", loc);
3928 return members [0].DeclaringType;
3932 public IInstanceQualifier InstanceQualifier {
3934 return instance_qualifier;
3937 instance_qualifier = value;
3941 bool IsProbingOnly {
3943 return (restrictions & Restrictions.ProbingOnly) != 0;
3947 bool IsDelegateInvoke {
3949 return (restrictions & Restrictions.DelegateInvoke) != 0;
3956 // 7.4.3.3 Better conversion from expression
3957 // Returns : 1 if a->p is better,
3958 // 2 if a->q is better,
3959 // 0 if neither is better
3961 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3963 TypeSpec argument_type = a.Type;
3966 // If argument is an anonymous function
3968 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3970 // p and q are delegate types or expression tree types
3972 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3973 if (q.MemberDefinition != p.MemberDefinition) {
3978 // Uwrap delegate from Expression<T>
3980 q = TypeManager.GetTypeArguments (q)[0];
3981 p = TypeManager.GetTypeArguments (p)[0];
3984 var p_m = Delegate.GetInvokeMethod (p);
3985 var q_m = Delegate.GetInvokeMethod (q);
3988 // With identical parameter lists
3990 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3999 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4001 if (p.Kind == MemberKind.Void) {
4002 return q.Kind != MemberKind.Void ? 2 : 0;
4006 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4008 if (q.Kind == MemberKind.Void) {
4009 return p.Kind != MemberKind.Void ? 1: 0;
4012 var am = (AnonymousMethodExpression) a.Expr;
4015 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4016 // better conversion is performed between underlying types Y1 and Y2
4018 if (p.IsGenericTask || q.IsGenericTask) {
4019 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4020 q = q.TypeArguments[0];
4021 p = p.TypeArguments[0];
4023 } else if (q != p) {
4025 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4027 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4028 var am_rt = am.InferReturnType (ec, null, orig_q);
4029 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4031 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4032 var am_rt = am.InferReturnType (ec, null, orig_p);
4033 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4039 // The parameters are identicial and return type is not void, use better type conversion
4040 // on return type to determine better one
4043 if (argument_type == p)
4046 if (argument_type == q)
4050 return BetterTypeConversion (ec, p, q);
4054 // 7.4.3.4 Better conversion from type
4056 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4058 if (p == null || q == null)
4059 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4061 switch (p.BuiltinType) {
4062 case BuiltinTypeSpec.Type.Int:
4063 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4066 case BuiltinTypeSpec.Type.Long:
4067 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4070 case BuiltinTypeSpec.Type.SByte:
4071 switch (q.BuiltinType) {
4072 case BuiltinTypeSpec.Type.Byte:
4073 case BuiltinTypeSpec.Type.UShort:
4074 case BuiltinTypeSpec.Type.UInt:
4075 case BuiltinTypeSpec.Type.ULong:
4079 case BuiltinTypeSpec.Type.Short:
4080 switch (q.BuiltinType) {
4081 case BuiltinTypeSpec.Type.UShort:
4082 case BuiltinTypeSpec.Type.UInt:
4083 case BuiltinTypeSpec.Type.ULong:
4087 case BuiltinTypeSpec.Type.Dynamic:
4088 // Dynamic is never better
4092 switch (q.BuiltinType) {
4093 case BuiltinTypeSpec.Type.Int:
4094 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4097 case BuiltinTypeSpec.Type.Long:
4098 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4101 case BuiltinTypeSpec.Type.SByte:
4102 switch (p.BuiltinType) {
4103 case BuiltinTypeSpec.Type.Byte:
4104 case BuiltinTypeSpec.Type.UShort:
4105 case BuiltinTypeSpec.Type.UInt:
4106 case BuiltinTypeSpec.Type.ULong:
4110 case BuiltinTypeSpec.Type.Short:
4111 switch (p.BuiltinType) {
4112 case BuiltinTypeSpec.Type.UShort:
4113 case BuiltinTypeSpec.Type.UInt:
4114 case BuiltinTypeSpec.Type.ULong:
4118 case BuiltinTypeSpec.Type.Dynamic:
4119 // Dynamic is never better
4123 // FIXME: handle lifted operators
4125 // TODO: this is expensive
4126 Expression p_tmp = new EmptyExpression (p);
4127 Expression q_tmp = new EmptyExpression (q);
4129 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4130 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4132 if (p_to_q && !q_to_p)
4135 if (q_to_p && !p_to_q)
4142 /// Determines "Better function" between candidate
4143 /// and the current best match
4146 /// Returns a boolean indicating :
4147 /// false if candidate ain't better
4148 /// true if candidate is better than the current best match
4150 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4151 MemberSpec best, AParametersCollection bparam, bool best_params)
4153 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4154 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4156 bool better_at_least_one = false;
4158 int args_count = args == null ? 0 : args.Count;
4162 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4165 // Default arguments are ignored for better decision
4166 if (a.IsDefaultArgument)
4170 // When comparing named argument the parameter type index has to be looked up
4171 // in original parameter set (override version for virtual members)
4173 NamedArgument na = a as NamedArgument;
4175 int idx = cparam.GetParameterIndexByName (na.Name);
4176 ct = candidate_pd.Types[idx];
4177 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4178 ct = TypeManager.GetElementType (ct);
4180 idx = bparam.GetParameterIndexByName (na.Name);
4181 bt = best_pd.Types[idx];
4182 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4183 bt = TypeManager.GetElementType (bt);
4185 ct = candidate_pd.Types[c_idx];
4186 bt = best_pd.Types[b_idx];
4188 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4189 ct = TypeManager.GetElementType (ct);
4193 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4194 bt = TypeManager.GetElementType (bt);
4199 if (TypeSpecComparer.IsEqual (ct, bt))
4203 int result = BetterExpressionConversion (ec, a, ct, bt);
4205 // for each argument, the conversion to 'ct' should be no worse than
4206 // the conversion to 'bt'.
4210 // for at least one argument, the conversion to 'ct' should be better than
4211 // the conversion to 'bt'.
4213 better_at_least_one = true;
4216 if (better_at_least_one)
4220 // This handles the case
4222 // Add (float f1, float f2, float f3);
4223 // Add (params decimal [] foo);
4225 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4226 // first candidate would've chosen as better.
4228 if (!same && !a.IsDefaultArgument)
4232 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4236 // This handles the following cases:
4238 // Foo (int i) is better than Foo (int i, long l = 0)
4239 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4240 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4242 // Prefer non-optional version
4244 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4246 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4247 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4250 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4253 return candidate_pd.Count >= best_pd.Count;
4257 // One is a non-generic method and second is a generic method, then non-generic is better
4259 if (best.IsGeneric != candidate.IsGeneric)
4260 return best.IsGeneric;
4263 // This handles the following cases:
4265 // Trim () is better than Trim (params char[] chars)
4266 // Concat (string s1, string s2, string s3) is better than
4267 // Concat (string s1, params string [] srest)
4268 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4270 // Prefer non-expanded version
4272 if (candidate_params != best_params)
4275 int candidate_param_count = candidate_pd.Count;
4276 int best_param_count = best_pd.Count;
4278 if (candidate_param_count != best_param_count)
4279 // can only happen if (candidate_params && best_params)
4280 return candidate_param_count > best_param_count && best_pd.HasParams;
4283 // Both methods have the same number of parameters, and the parameters have equal types
4284 // Pick the "more specific" signature using rules over original (non-inflated) types
4286 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4287 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4289 bool specific_at_least_once = false;
4290 for (j = 0; j < args_count; ++j) {
4291 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4293 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4294 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4296 ct = candidate_def_pd.Types[j];
4297 bt = best_def_pd.Types[j];
4302 TypeSpec specific = MoreSpecific (ct, bt);
4306 specific_at_least_once = true;
4309 if (specific_at_least_once)
4315 static bool CheckInflatedArguments (MethodSpec ms)
4317 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4320 // Setup constraint checker for probing only
4321 ConstraintChecker cc = new ConstraintChecker (null);
4323 var mp = ms.Parameters.Types;
4324 for (int i = 0; i < mp.Length; ++i) {
4325 var type = mp[i] as InflatedTypeSpec;
4329 var targs = type.TypeArguments;
4330 if (targs.Length == 0)
4333 // TODO: Checking inflated MVAR arguments should be enough
4334 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4341 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4343 rc.Report.Error (1729, loc,
4344 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4345 type.GetSignatureForError (), argCount.ToString ());
4349 // Determines if the candidate method is applicable to the given set of arguments
4350 // There could be two different set of parameters for same candidate where one
4351 // is the closest override for default values and named arguments checks and second
4352 // one being the virtual base for the parameter types and modifiers.
4354 // A return value rates candidate method compatibility,
4355 // 0 = the best, int.MaxValue = the worst
4358 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)
4360 // Parameters of most-derived type used mainly for named and optional parameters
4361 var pd = pm.Parameters;
4363 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4364 // params modifier instead of most-derived type
4365 var cpd = ((IParametersMember) candidate).Parameters;
4366 int param_count = pd.Count;
4367 int optional_count = 0;
4369 Arguments orig_args = arguments;
4371 if (arg_count != param_count) {
4373 // No arguments expansion when doing exact match for delegates
4375 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4376 for (int i = 0; i < pd.Count; ++i) {
4377 if (pd.FixedParameters[i].HasDefaultValue) {
4378 optional_count = pd.Count - i;
4384 if (optional_count != 0) {
4385 // Readjust expected number when params used
4386 if (cpd.HasParams) {
4388 if (arg_count < param_count)
4390 } else if (arg_count > param_count) {
4391 int args_gap = System.Math.Abs (arg_count - param_count);
4392 return int.MaxValue - 10000 + args_gap;
4393 } else if (arg_count < param_count - optional_count) {
4394 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4395 return int.MaxValue - 10000 + args_gap;
4397 } else if (arg_count != param_count) {
4398 int args_gap = System.Math.Abs (arg_count - param_count);
4400 return int.MaxValue - 10000 + args_gap;
4401 if (arg_count < param_count - 1)
4402 return int.MaxValue - 10000 + args_gap;
4405 // Resize to fit optional arguments
4406 if (optional_count != 0) {
4407 if (arguments == null) {
4408 arguments = new Arguments (optional_count);
4410 // Have to create a new container, so the next run can do same
4411 var resized = new Arguments (param_count);
4412 resized.AddRange (arguments);
4413 arguments = resized;
4416 for (int i = arg_count; i < param_count; ++i)
4417 arguments.Add (null);
4421 if (arg_count > 0) {
4423 // Shuffle named arguments to the right positions if there are any
4425 if (arguments[arg_count - 1] is NamedArgument) {
4426 arg_count = arguments.Count;
4428 for (int i = 0; i < arg_count; ++i) {
4429 bool arg_moved = false;
4431 NamedArgument na = arguments[i] as NamedArgument;
4435 int index = pd.GetParameterIndexByName (na.Name);
4437 // Named parameter not found
4441 // already reordered
4446 if (index >= param_count) {
4447 // When using parameters which should not be available to the user
4448 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4451 arguments.Add (null);
4455 temp = arguments[index];
4457 // The slot has been taken by positional argument
4458 if (temp != null && !(temp is NamedArgument))
4463 arguments = arguments.MarkOrderedArgument (na);
4467 arguments[index] = arguments[i];
4468 arguments[i] = temp;
4475 arg_count = arguments.Count;
4477 } else if (arguments != null) {
4478 arg_count = arguments.Count;
4482 // Don't do any expensive checks when the candidate cannot succeed
4484 if (arg_count != param_count && !cpd.HasParams)
4485 return (param_count - arg_count) * 2 + 1;
4487 var dep = candidate.GetMissingDependencies ();
4489 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4494 // 1. Handle generic method using type arguments when specified or type inference
4497 var ms = candidate as MethodSpec;
4498 if (ms != null && ms.IsGeneric) {
4499 if (type_arguments != null) {
4500 var g_args_count = ms.Arity;
4501 if (g_args_count != type_arguments.Count)
4502 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4504 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4507 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4508 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4509 // candidate was found use the set to report more details about what was wrong with lambda body.
4510 // The general idea is to distinguish between code errors and errors caused by
4511 // trial-and-error type inference
4513 if (lambda_conv_msgs == null) {
4514 for (int i = 0; i < arg_count; i++) {
4515 Argument a = arguments[i];
4519 var am = a.Expr as AnonymousMethodExpression;
4521 if (lambda_conv_msgs == null)
4522 lambda_conv_msgs = new SessionReportPrinter ();
4524 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4529 var ti = new TypeInference (arguments);
4530 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4533 return ti.InferenceScore - 20000;
4536 // Clear any error messages when the result was success
4538 if (lambda_conv_msgs != null)
4539 lambda_conv_msgs.ClearSession ();
4541 if (i_args.Length != 0) {
4542 ms = ms.MakeGenericMethod (ec, i_args);
4547 // Type arguments constraints have to match for the method to be applicable
4549 if (!CheckInflatedArguments (ms)) {
4551 return int.MaxValue - 25000;
4555 // We have a generic return type and at same time the method is override which
4556 // means we have to also inflate override return type in case the candidate is
4557 // best candidate and override return type is different to base return type.
4559 // virtual Foo<T, object> with override Foo<T, dynamic>
4561 if (candidate != pm) {
4562 MethodSpec override_ms = (MethodSpec) pm;
4563 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4564 returnType = inflator.Inflate (returnType);
4566 returnType = ms.ReturnType;
4573 if (type_arguments != null)
4574 return int.MaxValue - 15000;
4580 // 2. Each argument has to be implicitly convertible to method parameter
4582 Parameter.Modifier p_mod = 0;
4585 for (int i = 0; i < arg_count; i++) {
4586 Argument a = arguments[i];
4588 var fp = pd.FixedParameters[i];
4589 if (!fp.HasDefaultValue) {
4590 arguments = orig_args;
4591 return arg_count * 2 + 2;
4595 // Get the default value expression, we can use the same expression
4596 // if the type matches
4598 Expression e = fp.DefaultValue;
4600 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4602 // Restore for possible error reporting
4603 for (int ii = i; ii < arg_count; ++ii)
4604 arguments.RemoveAt (i);
4606 return (arg_count - i) * 2 + 1;
4610 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4612 // LAMESPEC: Attributes can be mixed together with build-in priority
4614 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4615 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4616 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4617 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4618 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4619 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4623 arguments[i] = new Argument (e, Argument.AType.Default);
4627 if (p_mod != Parameter.Modifier.PARAMS) {
4628 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4630 } else if (!params_expanded_form) {
4631 params_expanded_form = true;
4632 pt = ((ElementTypeSpec) pt).Element;
4638 if (!params_expanded_form) {
4639 if (a.ArgType == Argument.AType.ExtensionType) {
4641 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4643 // LAMESPEC: or implicit type parameter conversion
4646 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4647 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4648 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4653 score = IsArgumentCompatible (ec, a, p_mod, pt);
4656 dynamicArgument = true;
4661 // It can be applicable in expanded form (when not doing exact match like for delegates)
4663 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4664 if (!params_expanded_form) {
4665 pt = ((ElementTypeSpec) pt).Element;
4669 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4672 params_expanded_form = true;
4673 dynamicArgument = true;
4674 } else if (score == 0 || arg_count > pd.Count) {
4675 params_expanded_form = true;
4680 if (params_expanded_form)
4682 return (arg_count - i) * 2 + score;
4687 // When params parameter has no argument it will be provided later if the method is the best candidate
4689 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4690 params_expanded_form = true;
4693 // Restore original arguments for dynamic binder to keep the intention of original source code
4695 if (dynamicArgument)
4696 arguments = orig_args;
4701 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4703 if (e is Constant && e.Type == ptype)
4707 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4709 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4710 e = new MemberAccess (new MemberAccess (new MemberAccess (
4711 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4712 } else if (e is Constant) {
4714 // Handles int to int? conversions, DefaultParameterValue check
4716 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4720 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4723 return e.Resolve (ec);
4727 // Tests argument compatibility with the parameter
4728 // The possible return values are
4730 // 1 - modifier mismatch
4731 // 2 - type mismatch
4732 // -1 - dynamic binding required
4734 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4737 // Types have to be identical when ref or out modifer
4738 // is used and argument is not of dynamic type
4740 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4741 if (argument.Type != parameter) {
4743 // Do full equality check after quick path
4745 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4747 // Using dynamic for ref/out parameter can still succeed at runtime
4749 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4756 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4758 // Using dynamic for ref/out parameter can still succeed at runtime
4760 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4767 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4771 // Use implicit conversion in all modes to return same candidates when the expression
4772 // is used as argument or delegate conversion
4774 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4775 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4782 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4784 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4786 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4789 var ac_p = p as ArrayContainer;
4791 var ac_q = q as ArrayContainer;
4795 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4796 if (specific == ac_p.Element)
4798 if (specific == ac_q.Element)
4800 } else if (p.IsGeneric && q.IsGeneric) {
4801 var pargs = TypeManager.GetTypeArguments (p);
4802 var qargs = TypeManager.GetTypeArguments (q);
4804 bool p_specific_at_least_once = false;
4805 bool q_specific_at_least_once = false;
4807 for (int i = 0; i < pargs.Length; i++) {
4808 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4809 if (specific == pargs[i])
4810 p_specific_at_least_once = true;
4811 if (specific == qargs[i])
4812 q_specific_at_least_once = true;
4815 if (p_specific_at_least_once && !q_specific_at_least_once)
4817 if (!p_specific_at_least_once && q_specific_at_least_once)
4825 // Find the best method from candidate list
4827 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4829 List<AmbiguousCandidate> ambiguous_candidates = null;
4831 MemberSpec best_candidate;
4832 Arguments best_candidate_args = null;
4833 bool best_candidate_params = false;
4834 bool best_candidate_dynamic = false;
4835 int best_candidate_rate;
4836 IParametersMember best_parameter_member = null;
4838 int args_count = args != null ? args.Count : 0;
4840 Arguments candidate_args = args;
4841 bool error_mode = false;
4842 MemberSpec invocable_member = null;
4845 best_candidate = null;
4846 best_candidate_rate = int.MaxValue;
4848 var type_members = members;
4850 for (int i = 0; i < type_members.Count; ++i) {
4851 var member = type_members[i];
4854 // Methods in a base class are not candidates if any method in a derived
4855 // class is applicable
4857 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4861 if (!member.IsAccessible (rc))
4864 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4867 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4868 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4873 IParametersMember pm = member as IParametersMember;
4876 // Will use it later to report ambiguity between best method and invocable member
4878 if (Invocation.IsMemberInvocable (member))
4879 invocable_member = member;
4885 // Overload resolution is looking for base member but using parameter names
4886 // and default values from the closest member. That means to do expensive lookup
4887 // for the closest override for virtual or abstract members
4889 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4890 var override_params = base_provider.GetOverrideMemberParameters (member);
4891 if (override_params != null)
4892 pm = override_params;
4896 // Check if the member candidate is applicable
4898 bool params_expanded_form = false;
4899 bool dynamic_argument = false;
4900 TypeSpec rt = pm.MemberType;
4901 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4903 if (lambda_conv_msgs != null)
4904 lambda_conv_msgs.EndSession ();
4907 // How does it score compare to others
4909 if (candidate_rate < best_candidate_rate) {
4911 // Fatal error (missing dependency), cannot continue
4912 if (candidate_rate < 0)
4915 best_candidate_rate = candidate_rate;
4916 best_candidate = member;
4917 best_candidate_args = candidate_args;
4918 best_candidate_params = params_expanded_form;
4919 best_candidate_dynamic = dynamic_argument;
4920 best_parameter_member = pm;
4921 best_candidate_return_type = rt;
4922 } else if (candidate_rate == 0) {
4924 // The member look is done per type for most operations but sometimes
4925 // it's not possible like for binary operators overload because they
4926 // are unioned between 2 sides
4928 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4929 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4934 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4936 // We pack all interface members into top level type which makes the overload resolution
4937 // more complicated for interfaces. We compensate it by removing methods with same
4938 // signature when building the cache hence this path should not really be hit often
4941 // interface IA { void Foo (int arg); }
4942 // interface IB : IA { void Foo (params int[] args); }
4944 // IB::Foo is the best overload when calling IB.Foo (1)
4947 if (ambiguous_candidates != null) {
4948 foreach (var amb_cand in ambiguous_candidates) {
4949 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4958 ambiguous_candidates = null;
4961 // Is the new candidate better
4962 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4966 best_candidate = member;
4967 best_candidate_args = candidate_args;
4968 best_candidate_params = params_expanded_form;
4969 best_candidate_dynamic = dynamic_argument;
4970 best_parameter_member = pm;
4971 best_candidate_return_type = rt;
4973 // It's not better but any other found later could be but we are not sure yet
4974 if (ambiguous_candidates == null)
4975 ambiguous_candidates = new List<AmbiguousCandidate> ();
4977 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4981 // Restore expanded arguments
4982 if (candidate_args != args)
4983 candidate_args = args;
4985 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4988 // We've found exact match
4990 if (best_candidate_rate == 0)
4994 // Try extension methods lookup when no ordinary method match was found and provider enables it
4997 var emg = base_provider.LookupExtensionMethod (rc);
4999 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5001 best_candidate_extension_group = emg;
5002 return (T) (MemberSpec) emg.BestCandidate;
5007 // Don't run expensive error reporting mode for probing
5014 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5017 lambda_conv_msgs = null;
5022 // No best member match found, report an error
5024 if (best_candidate_rate != 0 || error_mode) {
5025 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5029 if (best_candidate_dynamic) {
5030 if (args[0].ArgType == Argument.AType.ExtensionType) {
5031 rc.Report.Error (1973, loc,
5032 "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",
5033 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5037 // Check type constraints only when explicit type arguments are used
5039 if (best_candidate.IsGeneric && type_arguments != null) {
5040 MethodSpec bc = best_candidate as MethodSpec;
5041 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5042 ConstraintChecker cc = new ConstraintChecker (rc);
5043 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5047 BestCandidateIsDynamic = true;
5052 // These flags indicates we are running delegate probing conversion. No need to
5053 // do more expensive checks
5055 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5056 return (T) best_candidate;
5058 if (ambiguous_candidates != null) {
5060 // Now check that there are no ambiguities i.e the selected method
5061 // should be better than all the others
5063 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5064 var candidate = ambiguous_candidates [ix];
5066 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5067 var ambiguous = candidate.Member;
5068 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5069 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5070 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5071 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5072 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5075 return (T) best_candidate;
5080 if (invocable_member != null && !IsProbingOnly) {
5081 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5082 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5083 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5084 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5088 // And now check if the arguments are all
5089 // compatible, perform conversions if
5090 // necessary etc. and return if everything is
5093 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5096 if (best_candidate == null)
5100 // Don't run possibly expensive checks in probing mode
5102 if (!IsProbingOnly && !rc.IsInProbingMode) {
5104 // Check ObsoleteAttribute on the best method
5106 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5107 if (oa != null && !rc.IsObsolete)
5108 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5110 best_candidate.MemberDefinition.SetIsUsed ();
5113 args = best_candidate_args;
5114 return (T) best_candidate;
5117 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5119 return ResolveMember<MethodSpec> (rc, ref args);
5122 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5123 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5125 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5128 if (a.Type == InternalType.ErrorType)
5131 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5132 ec.Report.SymbolRelatedToPreviousError (method);
5133 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5134 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5135 TypeManager.CSharpSignature (method));
5138 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5139 TypeManager.CSharpSignature (method));
5140 } else if (IsDelegateInvoke) {
5141 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5142 DelegateType.GetSignatureForError ());
5144 ec.Report.SymbolRelatedToPreviousError (method);
5145 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5146 method.GetSignatureForError ());
5149 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5151 string index = (idx + 1).ToString ();
5152 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5153 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5154 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5155 index, Parameter.GetModifierSignature (a.Modifier));
5157 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5158 index, Parameter.GetModifierSignature (mod));
5160 string p1 = a.GetSignatureForError ();
5161 string p2 = paramType.GetSignatureForError ();
5164 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5165 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5168 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5169 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5170 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5173 ec.Report.Error (1503, a.Expr.Location,
5174 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5179 // We have failed to find exact match so we return error info about the closest match
5181 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5183 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5184 int arg_count = args == null ? 0 : args.Count;
5186 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5187 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5188 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5192 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5197 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5198 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5199 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5203 // For candidates which match on parameters count report more details about incorrect arguments
5206 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5207 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5208 // Reject any inaccessible member
5209 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5210 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5211 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5215 var ms = best_candidate as MethodSpec;
5216 if (ms != null && ms.IsGeneric) {
5217 bool constr_ok = true;
5218 if (ms.TypeArguments != null)
5219 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5221 if (ta_count == 0) {
5222 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5226 rc.Report.Error (411, loc,
5227 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5228 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5235 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5241 // We failed to find any method with correct argument count, report best candidate
5243 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5246 if (best_candidate.Kind == MemberKind.Constructor) {
5247 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5248 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5249 } else if (IsDelegateInvoke) {
5250 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5251 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5252 DelegateType.GetSignatureForError (), arg_count.ToString ());
5254 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5255 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5256 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5257 name, arg_count.ToString ());
5261 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5263 var pd = pm.Parameters;
5264 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5266 Parameter.Modifier p_mod = 0;
5268 int a_idx = 0, a_pos = 0;
5270 ArrayInitializer params_initializers = null;
5271 bool has_unsafe_arg = pm.MemberType.IsPointer;
5272 int arg_count = args == null ? 0 : args.Count;
5274 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5276 if (p_mod != Parameter.Modifier.PARAMS) {
5277 p_mod = pd.FixedParameters[a_idx].ModFlags;
5279 has_unsafe_arg |= pt.IsPointer;
5281 if (p_mod == Parameter.Modifier.PARAMS) {
5282 if (chose_params_expanded) {
5283 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5284 pt = TypeManager.GetElementType (pt);
5290 // Types have to be identical when ref or out modifer is used
5292 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5293 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5296 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5302 NamedArgument na = a as NamedArgument;
5304 int name_index = pd.GetParameterIndexByName (na.Name);
5305 if (name_index < 0 || name_index >= pd.Count) {
5306 if (IsDelegateInvoke) {
5307 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5308 ec.Report.Error (1746, na.Location,
5309 "The delegate `{0}' does not contain a parameter named `{1}'",
5310 DelegateType.GetSignatureForError (), na.Name);
5312 ec.Report.SymbolRelatedToPreviousError (member);
5313 ec.Report.Error (1739, na.Location,
5314 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5315 TypeManager.CSharpSignature (member), na.Name);
5317 } else if (args[name_index] != a) {
5318 if (IsDelegateInvoke)
5319 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5321 ec.Report.SymbolRelatedToPreviousError (member);
5323 ec.Report.Error (1744, na.Location,
5324 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5329 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5332 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5333 custom_errors.NoArgumentMatch (ec, member);
5337 Expression conv = null;
5338 if (a.ArgType == Argument.AType.ExtensionType) {
5339 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5342 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5344 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5347 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5354 // Convert params arguments to an array initializer
5356 if (params_initializers != null) {
5357 // we choose to use 'a.Expr' rather than 'conv' so that
5358 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5359 params_initializers.Add (a.Expr);
5360 args.RemoveAt (a_idx--);
5365 // Update the argument with the implicit conversion
5369 if (a_idx != arg_count) {
5370 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5375 // Fill not provided arguments required by params modifier
5377 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5379 args = new Arguments (1);
5381 pt = ptypes[pd.Count - 1];
5382 pt = TypeManager.GetElementType (pt);
5383 has_unsafe_arg |= pt.IsPointer;
5384 params_initializers = new ArrayInitializer (0, loc);
5388 // Append an array argument with all params arguments
5390 if (params_initializers != null) {
5391 args.Add (new Argument (
5392 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5396 if (has_unsafe_arg && !ec.IsUnsafe) {
5397 Expression.UnsafeError (ec, loc);
5401 // We could infer inaccesible type arguments
5403 if (type_arguments == null && member.IsGeneric) {
5404 var ms = (MethodSpec) member;
5405 foreach (var ta in ms.TypeArguments) {
5406 if (!ta.IsAccessible (ec)) {
5407 ec.Report.SymbolRelatedToPreviousError (ta);
5408 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5418 public class ConstantExpr : MemberExpr
5420 readonly ConstSpec constant;
5422 public ConstantExpr (ConstSpec constant, Location loc)
5424 this.constant = constant;
5428 public override string Name {
5429 get { throw new NotImplementedException (); }
5432 public override string KindName {
5433 get { return "constant"; }
5436 public override bool IsInstance {
5437 get { return !IsStatic; }
5440 public override bool IsStatic {
5441 get { return true; }
5444 protected override TypeSpec DeclaringType {
5445 get { return constant.DeclaringType; }
5448 public override Expression CreateExpressionTree (ResolveContext ec)
5450 throw new NotSupportedException ("ET");
5453 protected override Expression DoResolve (ResolveContext rc)
5455 ResolveInstanceExpression (rc, null);
5456 DoBestMemberChecks (rc, constant);
5458 var c = constant.GetConstant (rc);
5460 // Creates reference expression to the constant value
5461 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5464 public override void Emit (EmitContext ec)
5466 throw new NotSupportedException ();
5469 public override string GetSignatureForError ()
5471 return constant.GetSignatureForError ();
5474 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5476 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5481 // Fully resolved expression that references a Field
5483 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5485 protected FieldSpec spec;
5486 VariableInfo variable_info;
5488 LocalTemporary temp;
5491 protected FieldExpr (Location l)
5496 public FieldExpr (FieldSpec spec, Location loc)
5501 type = spec.MemberType;
5504 public FieldExpr (FieldBase fi, Location l)
5511 public override string Name {
5517 public bool IsHoisted {
5519 IVariableReference hv = InstanceExpression as IVariableReference;
5520 return hv != null && hv.IsHoisted;
5524 public override bool IsInstance {
5526 return !spec.IsStatic;
5530 public override bool IsStatic {
5532 return spec.IsStatic;
5536 public override string KindName {
5537 get { return "field"; }
5540 public FieldSpec Spec {
5546 protected override TypeSpec DeclaringType {
5548 return spec.DeclaringType;
5552 public VariableInfo VariableInfo {
5554 return variable_info;
5560 public override string GetSignatureForError ()
5562 return spec.GetSignatureForError ();
5565 public bool IsMarshalByRefAccess (ResolveContext rc)
5567 // Checks possible ldflda of field access expression
5568 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5569 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5570 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5573 public void SetHasAddressTaken ()
5575 IVariableReference vr = InstanceExpression as IVariableReference;
5577 vr.SetHasAddressTaken ();
5581 public override Expression CreateExpressionTree (ResolveContext ec)
5583 return CreateExpressionTree (ec, true);
5586 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5589 Expression instance;
5591 if (InstanceExpression == null) {
5592 instance = new NullLiteral (loc);
5593 } else if (convertInstance) {
5594 instance = InstanceExpression.CreateExpressionTree (ec);
5596 args = new Arguments (1);
5597 args.Add (new Argument (InstanceExpression));
5598 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5601 args = Arguments.CreateForExpressionTree (ec, null,
5603 CreateTypeOfExpression ());
5605 return CreateExpressionFactoryCall (ec, "Field", args);
5608 public Expression CreateTypeOfExpression ()
5610 return new TypeOfField (spec, loc);
5613 protected override Expression DoResolve (ResolveContext ec)
5615 spec.MemberDefinition.SetIsUsed ();
5617 return DoResolve (ec, null);
5620 Expression DoResolve (ResolveContext ec, Expression rhs)
5622 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5625 if (ResolveInstanceExpression (ec, rhs)) {
5626 // Resolve the field's instance expression while flow analysis is turned
5627 // off: when accessing a field "a.b", we must check whether the field
5628 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5630 if (lvalue_instance) {
5631 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5632 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5634 Expression right_side =
5635 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5637 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5640 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5641 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5645 if (InstanceExpression == null)
5649 DoBestMemberChecks (ec, spec);
5652 var fb = spec as FixedFieldSpec;
5653 IVariableReference var = InstanceExpression as IVariableReference;
5655 if (lvalue_instance && var != null && var.VariableInfo != null) {
5656 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5660 IFixedExpression fe = InstanceExpression as IFixedExpression;
5661 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5662 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5665 if (InstanceExpression.eclass != ExprClass.Variable) {
5666 ec.Report.SymbolRelatedToPreviousError (spec);
5667 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5668 TypeManager.GetFullNameSignature (spec));
5669 } else if (var != null && var.IsHoisted) {
5670 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5673 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5677 // Set flow-analysis variable info for struct member access. It will be check later
5678 // for precise error reporting
5680 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5681 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5682 if (rhs != null && variable_info != null)
5683 variable_info.SetStructFieldAssigned (ec, Name);
5686 eclass = ExprClass.Variable;
5690 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5695 var var = fe.InstanceExpression as IVariableReference;
5697 var vi = var.VariableInfo;
5699 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5701 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5703 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5710 fe = fe.InstanceExpression as FieldExpr;
5712 } while (fe != null);
5715 static readonly int [] codes = {
5716 191, // instance, write access
5717 192, // instance, out access
5718 198, // static, write access
5719 199, // static, out access
5720 1648, // member of value instance, write access
5721 1649, // member of value instance, out access
5722 1650, // member of value static, write access
5723 1651 // member of value static, out access
5726 static readonly string [] msgs = {
5727 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5728 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5729 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5730 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5731 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5732 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5733 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5734 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5737 // The return value is always null. Returning a value simplifies calling code.
5738 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5741 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5745 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5747 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5752 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5754 if (spec is FixedFieldSpec) {
5755 // It could be much better error message but we want to be error compatible
5756 Error_ValueAssignment (ec, right_side);
5759 Expression e = DoResolve (ec, right_side);
5764 spec.MemberDefinition.SetIsAssigned ();
5766 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5767 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5768 ec.Report.Warning (420, 1, loc,
5769 "`{0}': A volatile field references will not be treated as volatile",
5770 spec.GetSignatureForError ());
5773 if (spec.IsReadOnly) {
5774 // InitOnly fields can only be assigned in constructors or initializers
5775 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5776 return Report_AssignToReadonly (ec, right_side);
5778 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5780 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5781 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5782 return Report_AssignToReadonly (ec, right_side);
5783 // static InitOnly fields cannot be assigned-to in an instance constructor
5784 if (IsStatic && !ec.IsStatic)
5785 return Report_AssignToReadonly (ec, right_side);
5786 // instance constructors can't modify InitOnly fields of other instances of the same type
5787 if (!IsStatic && !(InstanceExpression is This))
5788 return Report_AssignToReadonly (ec, right_side);
5792 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5793 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5794 ec.Report.Warning (197, 1, loc,
5795 "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",
5796 GetSignatureForError ());
5799 eclass = ExprClass.Variable;
5803 public override int GetHashCode ()
5805 return spec.GetHashCode ();
5808 public bool IsFixed {
5811 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5813 IVariableReference variable = InstanceExpression as IVariableReference;
5814 if (variable != null)
5815 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5817 IFixedExpression fe = InstanceExpression as IFixedExpression;
5818 return fe != null && fe.IsFixed;
5822 public override bool Equals (object obj)
5824 FieldExpr fe = obj as FieldExpr;
5828 if (spec != fe.spec)
5831 if (InstanceExpression == null || fe.InstanceExpression == null)
5834 return InstanceExpression.Equals (fe.InstanceExpression);
5837 public void Emit (EmitContext ec, bool leave_copy)
5839 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5843 ec.Emit (OpCodes.Volatile);
5845 ec.Emit (OpCodes.Ldsfld, spec);
5848 EmitInstance (ec, false);
5850 // Optimization for build-in types
5851 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5852 ec.EmitLoadFromPtr (type);
5854 var ff = spec as FixedFieldSpec;
5856 ec.Emit (OpCodes.Ldflda, spec);
5857 ec.Emit (OpCodes.Ldflda, ff.Element);
5860 ec.Emit (OpCodes.Volatile);
5862 ec.Emit (OpCodes.Ldfld, spec);
5868 ec.Emit (OpCodes.Dup);
5870 temp = new LocalTemporary (this.Type);
5876 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5878 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5879 if (isCompound && !(source is DynamicExpressionStatement)) {
5880 if (has_await_source) {
5882 InstanceExpression = InstanceExpression.EmitToField (ec);
5889 if (has_await_source)
5890 source = source.EmitToField (ec);
5892 EmitInstance (ec, prepared);
5898 ec.Emit (OpCodes.Dup);
5900 temp = new LocalTemporary (this.Type);
5905 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5906 ec.Emit (OpCodes.Volatile);
5908 spec.MemberDefinition.SetIsAssigned ();
5911 ec.Emit (OpCodes.Stsfld, spec);
5913 ec.Emit (OpCodes.Stfld, spec);
5923 // Emits store to field with prepared values on stack
5925 public void EmitAssignFromStack (EmitContext ec)
5928 ec.Emit (OpCodes.Stsfld, spec);
5930 ec.Emit (OpCodes.Stfld, spec);
5934 public override void Emit (EmitContext ec)
5939 public override void EmitSideEffect (EmitContext ec)
5941 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5943 if (is_volatile) // || is_marshal_by_ref ())
5944 base.EmitSideEffect (ec);
5947 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5949 if ((mode & AddressOp.Store) != 0)
5950 spec.MemberDefinition.SetIsAssigned ();
5951 if ((mode & AddressOp.Load) != 0)
5952 spec.MemberDefinition.SetIsUsed ();
5955 // Handle initonly fields specially: make a copy and then
5956 // get the address of the copy.
5959 if (spec.IsReadOnly){
5961 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5973 var temp = ec.GetTemporaryLocal (type);
5974 ec.Emit (OpCodes.Stloc, temp);
5975 ec.Emit (OpCodes.Ldloca, temp);
5976 ec.FreeTemporaryLocal (temp, type);
5982 ec.Emit (OpCodes.Ldsflda, spec);
5985 EmitInstance (ec, false);
5986 ec.Emit (OpCodes.Ldflda, spec);
5990 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5992 return MakeExpression (ctx);
5995 public override SLE.Expression MakeExpression (BuilderContext ctx)
5998 return base.MakeExpression (ctx);
6000 return SLE.Expression.Field (
6001 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6002 spec.GetMetaInfo ());
6006 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6008 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6014 // Expression that evaluates to a Property.
6016 // This is not an LValue because we need to re-write the expression. We
6017 // can not take data from the stack and store it.
6019 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6021 Arguments arguments;
6023 public PropertyExpr (PropertySpec spec, Location l)
6026 best_candidate = spec;
6027 type = spec.MemberType;
6032 protected override Arguments Arguments {
6041 protected override TypeSpec DeclaringType {
6043 return best_candidate.DeclaringType;
6047 public override string Name {
6049 return best_candidate.Name;
6053 public override bool IsInstance {
6059 public override bool IsStatic {
6061 return best_candidate.IsStatic;
6065 public override string KindName {
6066 get { return "property"; }
6069 public PropertySpec PropertyInfo {
6071 return best_candidate;
6077 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6079 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6082 var args_count = arguments == null ? 0 : arguments.Count;
6083 if (args_count != body.Parameters.Count && args_count == 0)
6086 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6087 mg.InstanceExpression = InstanceExpression;
6092 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6094 return new PropertyExpr (spec, loc) {
6100 public override Expression CreateExpressionTree (ResolveContext ec)
6103 if (IsSingleDimensionalArrayLength ()) {
6104 args = new Arguments (1);
6105 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6106 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6109 args = new Arguments (2);
6110 if (InstanceExpression == null)
6111 args.Add (new Argument (new NullLiteral (loc)));
6113 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6114 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6115 return CreateExpressionFactoryCall (ec, "Property", args);
6118 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6120 DoResolveLValue (rc, null);
6121 return new TypeOfMethod (Setter, loc);
6124 public override string GetSignatureForError ()
6126 return best_candidate.GetSignatureForError ();
6129 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6132 return base.MakeExpression (ctx);
6134 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6138 public override SLE.Expression MakeExpression (BuilderContext ctx)
6141 return base.MakeExpression (ctx);
6143 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6147 void Error_PropertyNotValid (ResolveContext ec)
6149 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6150 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6151 GetSignatureForError ());
6154 bool IsSingleDimensionalArrayLength ()
6156 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6159 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6160 return ac != null && ac.Rank == 1;
6163 public override void Emit (EmitContext ec, bool leave_copy)
6166 // Special case: length of single dimension array property is turned into ldlen
6168 if (IsSingleDimensionalArrayLength ()) {
6169 EmitInstance (ec, false);
6170 ec.Emit (OpCodes.Ldlen);
6171 ec.Emit (OpCodes.Conv_I4);
6175 base.Emit (ec, leave_copy);
6178 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6181 LocalTemporary await_source_arg = null;
6183 if (isCompound && !(source is DynamicExpressionStatement)) {
6184 emitting_compound_assignment = true;
6187 if (has_await_arguments) {
6188 await_source_arg = new LocalTemporary (Type);
6189 await_source_arg.Store (ec);
6191 args = new Arguments (1);
6192 args.Add (new Argument (await_source_arg));
6195 temp = await_source_arg;
6198 has_await_arguments = false;
6203 ec.Emit (OpCodes.Dup);
6204 temp = new LocalTemporary (this.Type);
6209 args = arguments == null ? new Arguments (1) : arguments;
6213 temp = new LocalTemporary (this.Type);
6215 args.Add (new Argument (temp));
6217 args.Add (new Argument (source));
6221 emitting_compound_assignment = false;
6223 var call = new CallEmitter ();
6224 call.InstanceExpression = InstanceExpression;
6226 call.InstanceExpressionOnStack = true;
6228 call.Emit (ec, Setter, args, loc);
6235 if (await_source_arg != null) {
6236 await_source_arg.Release (ec);
6240 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6242 eclass = ExprClass.PropertyAccess;
6244 if (best_candidate.IsNotCSharpCompatible) {
6245 Error_PropertyNotValid (rc);
6248 ResolveInstanceExpression (rc, right_side);
6250 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6251 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6252 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6254 type = p.MemberType;
6258 DoBestMemberChecks (rc, best_candidate);
6260 // Handling of com-imported properties with any number of default property parameters
6261 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6262 var p = best_candidate.Get.Parameters;
6263 arguments = new Arguments (p.Count);
6264 for (int i = 0; i < p.Count; ++i) {
6265 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6267 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6268 var p = best_candidate.Set.Parameters;
6269 arguments = new Arguments (p.Count - 1);
6270 for (int i = 0; i < p.Count - 1; ++i) {
6271 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6278 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6280 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6284 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6286 // getter and setter can be different for base calls
6287 MethodSpec getter, setter;
6288 protected T best_candidate;
6290 protected LocalTemporary temp;
6291 protected bool emitting_compound_assignment;
6292 protected bool has_await_arguments;
6294 protected PropertyOrIndexerExpr (Location l)
6301 protected abstract Arguments Arguments { get; set; }
6303 public MethodSpec Getter {
6312 public MethodSpec Setter {
6323 protected override Expression DoResolve (ResolveContext ec)
6325 if (eclass == ExprClass.Unresolved) {
6326 var expr = OverloadResolve (ec, null);
6331 return expr.Resolve (ec);
6334 if (!ResolveGetter (ec))
6340 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6342 if (right_side == EmptyExpression.OutAccess) {
6343 // TODO: best_candidate can be null at this point
6344 INamedBlockVariable variable = null;
6345 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6346 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6347 best_candidate.Name);
6349 right_side.DoResolveLValue (ec, this);
6354 if (eclass == ExprClass.Unresolved) {
6355 var expr = OverloadResolve (ec, right_side);
6360 return expr.ResolveLValue (ec, right_side);
6363 if (!ResolveSetter (ec))
6370 // Implements the IAssignMethod interface for assignments
6372 public virtual void Emit (EmitContext ec, bool leave_copy)
6374 var call = new CallEmitter ();
6375 call.InstanceExpression = InstanceExpression;
6376 if (has_await_arguments)
6377 call.HasAwaitArguments = true;
6379 call.DuplicateArguments = emitting_compound_assignment;
6381 call.Emit (ec, Getter, Arguments, loc);
6383 if (call.HasAwaitArguments) {
6384 InstanceExpression = call.InstanceExpression;
6385 Arguments = call.EmittedArguments;
6386 has_await_arguments = true;
6390 ec.Emit (OpCodes.Dup);
6391 temp = new LocalTemporary (Type);
6396 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6398 public override void Emit (EmitContext ec)
6403 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6405 has_await_arguments = true;
6410 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6412 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6414 bool ResolveGetter (ResolveContext rc)
6416 if (!best_candidate.HasGet) {
6417 if (InstanceExpression != EmptyExpression.Null) {
6418 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6419 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6420 best_candidate.GetSignatureForError ());
6423 } else if (!best_candidate.Get.IsAccessible (rc)) {
6424 if (best_candidate.HasDifferentAccessibility) {
6425 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6426 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6427 TypeManager.CSharpSignature (best_candidate));
6429 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6430 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6434 if (best_candidate.HasDifferentAccessibility) {
6435 CheckProtectedMemberAccess (rc, best_candidate.Get);
6438 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6442 bool ResolveSetter (ResolveContext rc)
6444 if (!best_candidate.HasSet) {
6445 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6446 GetSignatureForError ());
6450 if (!best_candidate.Set.IsAccessible (rc)) {
6451 if (best_candidate.HasDifferentAccessibility) {
6452 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6453 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6454 GetSignatureForError ());
6456 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6457 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6461 if (best_candidate.HasDifferentAccessibility)
6462 CheckProtectedMemberAccess (rc, best_candidate.Set);
6464 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6470 /// Fully resolved expression that evaluates to an Event
6472 public class EventExpr : MemberExpr, IAssignMethod
6474 readonly EventSpec spec;
6477 public EventExpr (EventSpec spec, Location loc)
6485 protected override TypeSpec DeclaringType {
6487 return spec.DeclaringType;
6491 public override string Name {
6497 public override bool IsInstance {
6499 return !spec.IsStatic;
6503 public override bool IsStatic {
6505 return spec.IsStatic;
6509 public override string KindName {
6510 get { return "event"; }
6513 public MethodSpec Operator {
6521 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6524 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6526 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6527 if (spec.BackingField != null &&
6528 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6530 spec.MemberDefinition.SetIsUsed ();
6532 if (!ec.IsObsolete) {
6533 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6535 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6538 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6539 Error_AssignmentEventOnly (ec);
6541 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6543 InstanceExpression = null;
6545 return ml.ResolveMemberAccess (ec, left, original);
6549 return base.ResolveMemberAccess (ec, left, original);
6552 public override Expression CreateExpressionTree (ResolveContext ec)
6554 throw new NotSupportedException ("ET");
6557 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6559 if (right_side == EmptyExpression.EventAddition) {
6560 op = spec.AccessorAdd;
6561 } else if (right_side == EmptyExpression.EventSubtraction) {
6562 op = spec.AccessorRemove;
6566 Error_AssignmentEventOnly (ec);
6570 op = CandidateToBaseOverride (ec, op);
6574 protected override Expression DoResolve (ResolveContext ec)
6576 eclass = ExprClass.EventAccess;
6577 type = spec.MemberType;
6579 ResolveInstanceExpression (ec, null);
6581 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6582 Error_AssignmentEventOnly (ec);
6585 DoBestMemberChecks (ec, spec);
6589 public override void Emit (EmitContext ec)
6591 throw new NotSupportedException ();
6592 //Error_CannotAssign ();
6595 #region IAssignMethod Members
6597 public void Emit (EmitContext ec, bool leave_copy)
6599 throw new NotImplementedException ();
6602 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6604 if (leave_copy || !isCompound)
6605 throw new NotImplementedException ("EventExpr::EmitAssign");
6607 Arguments args = new Arguments (1);
6608 args.Add (new Argument (source));
6610 var call = new CallEmitter ();
6611 call.InstanceExpression = InstanceExpression;
6612 call.Emit (ec, op, args, loc);
6617 void Error_AssignmentEventOnly (ResolveContext ec)
6619 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6620 ec.Report.Error (79, loc,
6621 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6622 GetSignatureForError ());
6624 ec.Report.Error (70, loc,
6625 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6626 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6630 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6632 name = name.Substring (0, name.LastIndexOf ('.'));
6633 base.Error_CannotCallAbstractBase (rc, name);
6636 public override string GetSignatureForError ()
6638 return TypeManager.CSharpSignature (spec);
6641 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6643 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6647 public class TemporaryVariableReference : VariableReference
6649 public class Declarator : Statement
6651 TemporaryVariableReference variable;
6653 public Declarator (TemporaryVariableReference variable)
6655 this.variable = variable;
6659 protected override void DoEmit (EmitContext ec)
6661 variable.li.CreateBuilder (ec);
6664 public override void Emit (EmitContext ec)
6666 // Don't create sequence point
6670 protected override void CloneTo (CloneContext clonectx, Statement target)
6678 public TemporaryVariableReference (LocalVariable li, Location loc)
6681 this.type = li.Type;
6685 public override bool IsLockedByStatement {
6693 public LocalVariable LocalInfo {
6699 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6701 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6702 return new TemporaryVariableReference (li, loc);
6705 protected override Expression DoResolve (ResolveContext ec)
6707 eclass = ExprClass.Variable;
6710 // Don't capture temporary variables except when using
6711 // state machine redirection and block yields
6713 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6714 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6715 ec.IsVariableCapturingRequired) {
6716 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6717 storey.CaptureLocalVariable (ec, li);
6723 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6725 return Resolve (ec);
6728 public override void Emit (EmitContext ec)
6730 li.CreateBuilder (ec);
6735 public void EmitAssign (EmitContext ec, Expression source)
6737 li.CreateBuilder (ec);
6739 EmitAssign (ec, source, false, false);
6742 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6744 return li.HoistedVariant;
6747 public override bool IsFixed {
6748 get { return true; }
6751 public override bool IsRef {
6752 get { return false; }
6755 public override string Name {
6756 get { throw new NotImplementedException (); }
6759 public override void SetHasAddressTaken ()
6761 throw new NotImplementedException ();
6764 protected override ILocalVariable Variable {
6768 public override VariableInfo VariableInfo {
6769 get { return null; }
6772 public override void VerifyAssigned (ResolveContext rc)
6778 /// Handles `var' contextual keyword; var becomes a keyword only
6779 /// if no type called var exists in a variable scope
6781 class VarExpr : SimpleName
6783 public VarExpr (Location loc)
6788 public bool InferType (ResolveContext ec, Expression right_side)
6791 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6793 type = right_side.Type;
6794 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6795 ec.Report.Error (815, loc,
6796 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6797 type.GetSignatureForError ());
6801 eclass = ExprClass.Variable;
6805 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6807 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6808 base.Error_TypeOrNamespaceNotFound (ec);
6810 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");