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, 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 static 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 static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // 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
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
434 /// Resolves an expression and performs semantic analysis on it.
438 /// Currently Resolve wraps DoResolve to perform sanity
439 /// checking and assertion checking on what we expect from Resolve.
441 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
443 if (eclass != ExprClass.Unresolved) {
444 if ((flags & ExprClassToResolveFlags) == 0) {
445 Error_UnexpectedKind (ec, flags, loc);
459 if ((flags & e.ExprClassToResolveFlags) == 0) {
460 e.Error_UnexpectedKind (ec, flags, loc);
465 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
468 } catch (Exception ex) {
469 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
470 ec.Report.Printer is NullReportPrinter)
473 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
474 return ErrorExpression.Instance; // TODO: Add location
479 /// Resolves an expression and performs semantic analysis on it.
481 public Expression Resolve (ResolveContext rc)
483 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
487 /// Resolves an expression for LValue assignment
491 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
492 /// checking and assertion checking on what we expect from Resolve
494 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
496 int errors = ec.Report.Errors;
497 bool out_access = right_side == EmptyExpression.OutAccess;
499 Expression e = DoResolveLValue (ec, right_side);
501 if (e != null && out_access && !(e is IMemoryLocation)) {
502 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
503 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
505 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
506 // e.GetType () + " " + e.GetSignatureForError ());
511 if (errors == ec.Report.Errors) {
512 Error_ValueAssignment (ec, right_side);
517 if (e.eclass == ExprClass.Unresolved)
518 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
520 if ((e.type == null) && !(e is GenericTypeExpr))
521 throw new Exception ("Expression " + e + " did not set its type after Resolve");
526 public Constant ResolveLabelConstant (ResolveContext rc)
528 var expr = Resolve (rc);
532 Constant c = expr as Constant;
534 if (expr.type != InternalType.ErrorType)
535 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
543 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
545 rc.Module.Compiler.Report.Error (182, loc,
546 "An attribute argument must be a constant expression, typeof expression or array creation expression");
550 /// Emits the code for the expression
554 /// The Emit method is invoked to generate the code
555 /// for the expression.
557 public abstract void Emit (EmitContext ec);
560 // Emit code to branch to @target if this expression is equivalent to @on_true.
561 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
562 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
563 // including the use of conditional branches. Note also that a branch MUST be emitted
564 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
567 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
570 // Emit this expression for its side effects, not for its value.
571 // The default implementation is to emit the value, and then throw it away.
572 // Subclasses can provide more efficient implementations, but those MUST be equivalent
573 public virtual void EmitSideEffect (EmitContext ec)
576 ec.Emit (OpCodes.Pop);
580 // Emits the expression into temporary field variable. The method
581 // should be used for await expressions only
583 public virtual Expression EmitToField (EmitContext ec)
586 // This is the await prepare Emit method. When emitting code like
587 // a + b we emit code like
593 // For await a + await b we have to interfere the flow to keep the
594 // stack clean because await yields from the expression. The emit
597 // a = a.EmitToField () // a is changed to temporary field access
598 // b = b.EmitToField ()
604 // The idea is to emit expression and leave the stack empty with
605 // result value still available.
607 // Expressions should override this default implementation when
608 // optimized version can be provided (e.g. FieldExpr)
611 // We can optimize for side-effect free expressions, they can be
612 // emitted out of order
614 if (IsSideEffectFree)
617 bool needs_temporary = ContainsEmitWithAwait ();
618 if (!needs_temporary)
621 // Emit original code
622 var field = EmitToFieldSource (ec);
625 // Store the result to temporary field when we
626 // cannot load `this' directly
628 field = ec.GetTemporaryField (type);
629 if (needs_temporary) {
631 // Create temporary local (we cannot load `this' before Emit)
633 var temp = ec.GetTemporaryLocal (type);
634 ec.Emit (OpCodes.Stloc, temp);
637 ec.Emit (OpCodes.Ldloc, temp);
638 field.EmitAssignFromStack (ec);
640 ec.FreeTemporaryLocal (temp, type);
642 field.EmitAssignFromStack (ec);
649 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
652 // Default implementation calls Emit method
658 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
660 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
661 bool contains_await = false;
663 for (int i = 1; i < expressions.Count; ++i) {
664 if (expressions[i].ContainsEmitWithAwait ()) {
665 contains_await = true;
670 if (contains_await) {
671 for (int i = 0; i < expressions.Count; ++i) {
672 expressions[i] = expressions[i].EmitToField (ec);
677 for (int i = 0; i < expressions.Count; ++i) {
678 expressions[i].Emit (ec);
683 /// Protected constructor. Only derivate types should
684 /// be able to be created
687 protected Expression ()
692 /// Returns a fully formed expression after a MemberLookup
695 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
697 if (spec is EventSpec)
698 return new EventExpr ((EventSpec) spec, loc);
699 if (spec is ConstSpec)
700 return new ConstantExpr ((ConstSpec) spec, loc);
701 if (spec is FieldSpec)
702 return new FieldExpr ((FieldSpec) spec, loc);
703 if (spec is PropertySpec)
704 return new PropertyExpr ((PropertySpec) spec, loc);
705 if (spec is TypeSpec)
706 return new TypeExpression (((TypeSpec) spec), loc);
711 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
713 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
715 rc.Report.SymbolRelatedToPreviousError (type);
717 // Report meaningful error for struct as they always have default ctor in C# context
718 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
720 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
721 type.GetSignatureForError ());
727 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
728 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
729 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
732 return r.ResolveMember<MethodSpec> (rc, ref args);
736 public enum MemberLookupRestrictions
745 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
746 // `qualifier_type' or null to lookup members in the current class.
748 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
750 var members = MemberCache.FindMembers (queried_type, name, false);
754 MemberSpec non_method = null;
755 MemberSpec ambig_non_method = null;
757 for (int i = 0; i < members.Count; ++i) {
758 var member = members[i];
760 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
761 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
764 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
767 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
771 if (!member.IsAccessible (rc))
775 // With runtime binder we can have a situation where queried type is inaccessible
776 // because it came via dynamic object, the check about inconsisted accessibility
777 // had no effect as the type was unknown during compilation
780 // private class N { }
782 // public dynamic Foo ()
788 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
792 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
793 if (member is MethodSpec) {
795 // Interface members that are hidden by class members are removed from the set. This
796 // step only has an effect if T is a type parameter and T has both an effective base
797 // class other than object and a non-empty effective interface set
799 var tps = queried_type as TypeParameterSpec;
800 if (tps != null && tps.HasTypeConstraint)
801 members = RemoveHiddenTypeParameterMethods (members);
803 return new MethodGroupExpr (members, queried_type, loc);
806 if (!Invocation.IsMemberInvocable (member))
810 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
812 } else if (!errorMode && !member.IsNotCSharpCompatible) {
814 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
815 // T has both an effective base class other than object and a non-empty effective interface set.
817 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
819 var tps = queried_type as TypeParameterSpec;
820 if (tps != null && tps.HasTypeConstraint) {
821 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
824 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
830 ambig_non_method = member;
834 if (non_method != null) {
835 if (ambig_non_method != null && rc != null) {
836 var report = rc.Module.Compiler.Report;
837 report.SymbolRelatedToPreviousError (non_method);
838 report.SymbolRelatedToPreviousError (ambig_non_method);
839 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
840 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
843 if (non_method is MethodSpec)
844 return new MethodGroupExpr (members, queried_type, loc);
846 return ExprClassFromMemberInfo (non_method, loc);
849 if (members[0].DeclaringType.BaseType == null)
852 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
854 } while (members != null);
859 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
861 if (members.Count < 2)
865 // If M is a method, then all non-method members declared in an interface declaration
866 // are removed from the set, and all methods with the same signature as M declared in
867 // an interface declaration are removed from the set
871 for (int i = 0; i < members.Count; ++i) {
872 var method = members[i] as MethodSpec;
873 if (method == null) {
876 members = new List<MemberSpec> (members);
879 members.RemoveAt (i--);
883 if (!method.DeclaringType.IsInterface)
886 for (int ii = 0; ii < members.Count; ++ii) {
887 var candidate = members[ii] as MethodSpec;
888 if (candidate == null || !candidate.DeclaringType.IsClass)
891 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
896 members = new List<MemberSpec> (members);
899 members.RemoveAt (i--);
907 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
909 throw new NotImplementedException ();
912 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
914 if (t == InternalType.ErrorType)
917 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
918 oper, t.GetSignatureForError ());
921 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
923 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
927 /// Returns an expression that can be used to invoke operator true
928 /// on the expression if it exists.
930 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
932 return GetOperatorTrueOrFalse (ec, e, true, loc);
936 /// Returns an expression that can be used to invoke operator false
937 /// on the expression if it exists.
939 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
941 return GetOperatorTrueOrFalse (ec, e, false, loc);
944 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
946 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
947 var methods = MemberCache.GetUserOperator (e.type, op, false);
951 Arguments arguments = new Arguments (1);
952 arguments.Add (new Argument (e));
954 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
955 var oper = res.ResolveOperator (ec, ref arguments);
960 return new UserOperatorCall (oper, arguments, null, loc);
963 public virtual string ExprClassName
967 case ExprClass.Unresolved:
969 case ExprClass.Value:
971 case ExprClass.Variable:
973 case ExprClass.Namespace:
977 case ExprClass.MethodGroup:
978 return "method group";
979 case ExprClass.PropertyAccess:
980 return "property access";
981 case ExprClass.EventAccess:
982 return "event access";
983 case ExprClass.IndexerAccess:
984 return "indexer access";
985 case ExprClass.Nothing:
987 case ExprClass.TypeParameter:
988 return "type parameter";
990 throw new Exception ("Should not happen");
995 /// Reports that we were expecting `expr' to be of class `expected'
997 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
999 var name = memberExpr.GetSignatureForError ();
1001 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1004 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1006 string [] valid = new string [4];
1009 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1010 valid [count++] = "variable";
1011 valid [count++] = "value";
1014 if ((flags & ResolveFlags.Type) != 0)
1015 valid [count++] = "type";
1017 if ((flags & ResolveFlags.MethodGroup) != 0)
1018 valid [count++] = "method group";
1021 valid [count++] = "unknown";
1023 StringBuilder sb = new StringBuilder (valid [0]);
1024 for (int i = 1; i < count - 1; i++) {
1026 sb.Append (valid [i]);
1029 sb.Append ("' or `");
1030 sb.Append (valid [count - 1]);
1033 ec.Report.Error (119, loc,
1034 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1037 public static void UnsafeError (ResolveContext ec, Location loc)
1039 UnsafeError (ec.Report, loc);
1042 public static void UnsafeError (Report Report, Location loc)
1044 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1048 // Converts `source' to an int, uint, long or ulong.
1050 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1052 var btypes = ec.BuiltinTypes;
1054 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1055 Arguments args = new Arguments (1);
1056 args.Add (new Argument (source));
1057 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1060 Expression converted;
1062 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1063 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1064 if (converted == null)
1065 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1066 if (converted == null)
1067 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1068 if (converted == null)
1069 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1071 if (converted == null) {
1072 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1078 // Only positive constants are allowed at compile time
1080 Constant c = converted as Constant;
1081 if (c != null && c.IsNegative)
1082 Error_NegativeArrayIndex (ec, source.loc);
1084 // No conversion needed to array index
1085 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1088 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1092 // Derived classes implement this method by cloning the fields that
1093 // could become altered during the Resolve stage
1095 // Only expressions that are created for the parser need to implement
1098 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1100 throw new NotImplementedException (
1102 "CloneTo not implemented for expression {0}", this.GetType ()));
1106 // Clones an expression created by the parser.
1108 // We only support expressions created by the parser so far, not
1109 // expressions that have been resolved (many more classes would need
1110 // to implement CloneTo).
1112 // This infrastructure is here merely for Lambda expressions which
1113 // compile the same code using different type values for the same
1114 // arguments to find the correct overload
1116 public virtual Expression Clone (CloneContext clonectx)
1118 Expression cloned = (Expression) MemberwiseClone ();
1119 CloneTo (clonectx, cloned);
1125 // Implementation of expression to expression tree conversion
1127 public abstract Expression CreateExpressionTree (ResolveContext ec);
1129 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1131 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1134 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1136 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1139 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1141 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1144 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1146 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1150 return new TypeExpression (t, loc);
1154 // Implemented by all expressions which support conversion from
1155 // compiler expression to invokable runtime expression. Used by
1156 // dynamic C# binder.
1158 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1160 throw new NotImplementedException ("MakeExpression for " + GetType ());
1163 public virtual object Accept (StructuralVisitor visitor)
1165 return visitor.Visit (this);
1170 /// This is just a base class for expressions that can
1171 /// appear on statements (invocations, object creation,
1172 /// assignments, post/pre increment and decrement). The idea
1173 /// being that they would support an extra Emition interface that
1174 /// does not leave a result on the stack.
1176 public abstract class ExpressionStatement : Expression
1178 public ExpressionStatement ResolveStatement (BlockContext ec)
1180 Expression e = Resolve (ec);
1184 ExpressionStatement es = e as ExpressionStatement;
1186 Error_InvalidExpressionStatement (ec);
1189 // This is quite expensive warning, try to limit the damage
1191 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1192 WarningAsyncWithoutWait (ec, e);
1198 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1200 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1201 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1206 // Need to do full resolve because GetAwaiter can be extension method
1207 // available only in this context
1209 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1213 var arguments = new Arguments (0);
1214 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1219 // Use same check rules as for real await
1221 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1222 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1225 bc.Report.Warning (4014, 1, e.Location,
1226 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1230 var inv = e as Invocation;
1231 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1232 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1233 bc.Report.Warning (4014, 1, e.Location,
1234 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1240 /// Requests the expression to be emitted in a `statement'
1241 /// context. This means that no new value is left on the
1242 /// stack after invoking this method (constrasted with
1243 /// Emit that will always leave a value on the stack).
1245 public abstract void EmitStatement (EmitContext ec);
1247 public override void EmitSideEffect (EmitContext ec)
1254 /// This kind of cast is used to encapsulate the child
1255 /// whose type is child.Type into an expression that is
1256 /// reported to return "return_type". This is used to encapsulate
1257 /// expressions which have compatible types, but need to be dealt
1258 /// at higher levels with.
1260 /// For example, a "byte" expression could be encapsulated in one
1261 /// of these as an "unsigned int". The type for the expression
1262 /// would be "unsigned int".
1265 public abstract class TypeCast : Expression
1267 protected readonly Expression child;
1269 protected TypeCast (Expression child, TypeSpec return_type)
1271 eclass = child.eclass;
1272 loc = child.Location;
1277 public Expression Child {
1283 public override bool ContainsEmitWithAwait ()
1285 return child.ContainsEmitWithAwait ();
1288 public override Expression CreateExpressionTree (ResolveContext ec)
1290 Arguments args = new Arguments (2);
1291 args.Add (new Argument (child.CreateExpressionTree (ec)));
1292 args.Add (new Argument (new TypeOf (type, loc)));
1294 if (type.IsPointer || child.Type.IsPointer)
1295 Error_PointerInsideExpressionTree (ec);
1297 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1300 protected override Expression DoResolve (ResolveContext ec)
1302 // This should never be invoked, we are born in fully
1303 // initialized state.
1308 public override void Emit (EmitContext ec)
1313 public override SLE.Expression MakeExpression (BuilderContext ctx)
1316 return base.MakeExpression (ctx);
1318 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1319 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1320 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1324 protected override void CloneTo (CloneContext clonectx, Expression t)
1329 public override bool IsNull {
1330 get { return child.IsNull; }
1334 public class EmptyCast : TypeCast {
1335 EmptyCast (Expression child, TypeSpec target_type)
1336 : base (child, target_type)
1340 public static Expression Create (Expression child, TypeSpec type)
1342 Constant c = child as Constant;
1344 var enum_constant = c as EnumConstant;
1345 if (enum_constant != null)
1346 c = enum_constant.Child;
1348 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1352 var res = c.ConvertImplicitly (type);
1358 EmptyCast e = child as EmptyCast;
1360 return new EmptyCast (e.child, type);
1362 return new EmptyCast (child, type);
1365 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1367 child.EmitBranchable (ec, label, on_true);
1370 public override void EmitSideEffect (EmitContext ec)
1372 child.EmitSideEffect (ec);
1377 // Used for predefined type user operator (no obsolete check, etc.)
1379 public class OperatorCast : TypeCast
1381 readonly MethodSpec conversion_operator;
1383 public OperatorCast (Expression expr, TypeSpec target_type)
1384 : this (expr, target_type, target_type, false)
1388 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1389 : this (expr, target_type, target_type, find_explicit)
1393 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1394 : base (expr, returnType)
1396 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1397 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1400 foreach (MethodSpec oper in mi) {
1401 if (oper.ReturnType != returnType)
1404 if (oper.Parameters.Types[0] == expr.Type) {
1405 conversion_operator = oper;
1411 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1412 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1415 public override void Emit (EmitContext ec)
1418 ec.Emit (OpCodes.Call, conversion_operator);
1423 // Constant specialization of EmptyCast.
1424 // We need to special case this since an empty cast of
1425 // a constant is still a constant.
1427 public class EmptyConstantCast : Constant
1429 public readonly Constant child;
1431 public EmptyConstantCast (Constant child, TypeSpec type)
1432 : base (child.Location)
1435 throw new ArgumentNullException ("child");
1438 this.eclass = child.eclass;
1442 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1444 if (child.Type == target_type)
1447 // FIXME: check that 'type' can be converted to 'target_type' first
1448 return child.ConvertExplicitly (in_checked_context, target_type);
1451 public override Expression CreateExpressionTree (ResolveContext ec)
1453 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1454 child.CreateExpressionTree (ec),
1455 new TypeOf (type, loc));
1458 Error_PointerInsideExpressionTree (ec);
1460 return CreateExpressionFactoryCall (ec, "Convert", args);
1463 public override bool IsDefaultValue {
1464 get { return child.IsDefaultValue; }
1467 public override bool IsNegative {
1468 get { return child.IsNegative; }
1471 public override bool IsNull {
1472 get { return child.IsNull; }
1475 public override bool IsOneInteger {
1476 get { return child.IsOneInteger; }
1479 public override bool IsSideEffectFree {
1481 return child.IsSideEffectFree;
1485 public override bool IsZeroInteger {
1486 get { return child.IsZeroInteger; }
1489 public override void Emit (EmitContext ec)
1494 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1496 child.EmitBranchable (ec, label, on_true);
1498 // Only to make verifier happy
1499 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1500 ec.Emit (OpCodes.Unbox_Any, type);
1503 public override void EmitSideEffect (EmitContext ec)
1505 child.EmitSideEffect (ec);
1508 public override object GetValue ()
1510 return child.GetValue ();
1513 public override string GetValueAsLiteral ()
1515 return child.GetValueAsLiteral ();
1518 public override long GetValueAsLong ()
1520 return child.GetValueAsLong ();
1523 public override Constant ConvertImplicitly (TypeSpec target_type)
1525 if (type == target_type)
1528 // FIXME: Do we need to check user conversions?
1529 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1532 return child.ConvertImplicitly (target_type);
1537 /// This class is used to wrap literals which belong inside Enums
1539 public class EnumConstant : Constant
1541 public Constant Child;
1543 public EnumConstant (Constant child, TypeSpec enum_type)
1544 : base (child.Location)
1548 this.eclass = ExprClass.Value;
1549 this.type = enum_type;
1552 protected EnumConstant (Location loc)
1557 public override void Emit (EmitContext ec)
1562 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1564 Child.EncodeAttributeValue (rc, enc, Child.Type);
1567 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1569 Child.EmitBranchable (ec, label, on_true);
1572 public override void EmitSideEffect (EmitContext ec)
1574 Child.EmitSideEffect (ec);
1577 public override string GetSignatureForError()
1579 return Type.GetSignatureForError ();
1582 public override object GetValue ()
1584 return Child.GetValue ();
1588 public override object GetTypedValue ()
1591 // The method can be used in dynamic context only (on closed types)
1593 // System.Enum.ToObject cannot be called on dynamic types
1594 // EnumBuilder has to be used, but we cannot use EnumBuilder
1595 // because it does not properly support generics
1597 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1601 public override string GetValueAsLiteral ()
1603 return Child.GetValueAsLiteral ();
1606 public override long GetValueAsLong ()
1608 return Child.GetValueAsLong ();
1611 public EnumConstant Increment()
1613 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1616 public override bool IsDefaultValue {
1618 return Child.IsDefaultValue;
1622 public override bool IsSideEffectFree {
1624 return Child.IsSideEffectFree;
1628 public override bool IsZeroInteger {
1629 get { return Child.IsZeroInteger; }
1632 public override bool IsNegative {
1634 return Child.IsNegative;
1638 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1640 if (Child.Type == target_type)
1643 return Child.ConvertExplicitly (in_checked_context, target_type);
1646 public override Constant ConvertImplicitly (TypeSpec type)
1648 if (this.type == type) {
1652 if (!Convert.ImplicitStandardConversionExists (this, type)){
1656 return Child.ConvertImplicitly (type);
1661 /// This kind of cast is used to encapsulate Value Types in objects.
1663 /// The effect of it is to box the value type emitted by the previous
1666 public class BoxedCast : TypeCast {
1668 public BoxedCast (Expression expr, TypeSpec target_type)
1669 : base (expr, target_type)
1671 eclass = ExprClass.Value;
1674 protected override Expression DoResolve (ResolveContext ec)
1676 // This should never be invoked, we are born in fully
1677 // initialized state.
1682 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1684 // Only boxing to object type is supported
1685 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1686 base.EncodeAttributeValue (rc, enc, targetType);
1690 enc.Encode (child.Type);
1691 child.EncodeAttributeValue (rc, enc, child.Type);
1694 public override void Emit (EmitContext ec)
1698 ec.Emit (OpCodes.Box, child.Type);
1701 public override void EmitSideEffect (EmitContext ec)
1703 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1704 // so, we need to emit the box+pop instructions in most cases
1705 if (child.Type.IsStruct &&
1706 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1707 child.EmitSideEffect (ec);
1709 base.EmitSideEffect (ec);
1713 public class UnboxCast : TypeCast {
1714 public UnboxCast (Expression expr, TypeSpec return_type)
1715 : base (expr, return_type)
1719 protected override Expression DoResolve (ResolveContext ec)
1721 // This should never be invoked, we are born in fully
1722 // initialized state.
1727 public override void Emit (EmitContext ec)
1731 ec.Emit (OpCodes.Unbox_Any, type);
1736 /// This is used to perform explicit numeric conversions.
1738 /// Explicit numeric conversions might trigger exceptions in a checked
1739 /// context, so they should generate the conv.ovf opcodes instead of
1742 public class ConvCast : TypeCast {
1743 public enum Mode : byte {
1744 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1746 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1747 U2_I1, U2_U1, U2_I2, U2_CH,
1748 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1749 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1750 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1751 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1752 CH_I1, CH_U1, CH_I2,
1753 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1754 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1760 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1761 : base (child, return_type)
1766 protected override Expression DoResolve (ResolveContext ec)
1768 // This should never be invoked, we are born in fully
1769 // initialized state.
1774 public override string ToString ()
1776 return String.Format ("ConvCast ({0}, {1})", mode, child);
1779 public override void Emit (EmitContext ec)
1785 public static void Emit (EmitContext ec, Mode mode)
1787 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1789 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1790 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1791 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1792 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1793 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1795 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1796 case Mode.U1_CH: /* nothing */ break;
1798 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1799 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1800 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1801 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1802 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1803 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1805 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1806 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1807 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1808 case Mode.U2_CH: /* nothing */ break;
1810 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1811 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1812 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1813 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1814 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1815 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1820 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1821 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1822 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1823 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1825 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1826 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1827 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1828 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1829 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1830 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1831 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1832 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1833 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1835 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1836 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1837 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1838 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1839 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1840 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1841 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1842 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1843 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1845 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1846 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1847 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1849 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1850 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1851 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1852 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1853 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1854 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1855 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1856 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1857 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1859 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1860 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1861 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1862 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1863 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1864 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1865 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1866 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1867 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1868 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1870 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1874 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1875 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1876 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1877 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1878 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1880 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1881 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1883 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1884 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1885 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1886 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1887 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1888 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1890 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1891 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1892 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1893 case Mode.U2_CH: /* nothing */ break;
1895 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1896 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1897 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1898 case Mode.I4_U4: /* nothing */ break;
1899 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1900 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1901 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1905 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1906 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1907 case Mode.U4_I4: /* nothing */ break;
1908 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1910 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1911 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1912 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1913 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1914 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1915 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1916 case Mode.I8_U8: /* nothing */ break;
1917 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1918 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1920 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1921 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1922 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1923 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1924 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1925 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1926 case Mode.U8_I8: /* nothing */ break;
1927 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1928 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1930 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1931 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1932 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1934 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1935 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1936 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1937 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1938 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1939 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1940 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1941 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1942 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1944 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1945 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1946 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1947 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1949 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1950 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1951 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1952 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1953 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1955 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1961 class OpcodeCast : TypeCast
1965 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1966 : base (child, return_type)
1971 protected override Expression DoResolve (ResolveContext ec)
1973 // This should never be invoked, we are born in fully
1974 // initialized state.
1979 public override void Emit (EmitContext ec)
1985 public TypeSpec UnderlyingType {
1986 get { return child.Type; }
1991 // Opcode casts expression with 2 opcodes but only
1992 // single expression tree node
1994 class OpcodeCastDuplex : OpcodeCast
1996 readonly OpCode second;
1998 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1999 : base (child, returnType, first)
2001 this.second = second;
2004 public override void Emit (EmitContext ec)
2012 /// This kind of cast is used to encapsulate a child and cast it
2013 /// to the class requested
2015 public sealed class ClassCast : TypeCast {
2016 readonly bool forced;
2018 public ClassCast (Expression child, TypeSpec return_type)
2019 : base (child, return_type)
2023 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2024 : base (child, return_type)
2026 this.forced = forced;
2029 public override void Emit (EmitContext ec)
2033 bool gen = TypeManager.IsGenericParameter (child.Type);
2035 ec.Emit (OpCodes.Box, child.Type);
2037 if (type.IsGenericParameter) {
2038 ec.Emit (OpCodes.Unbox_Any, type);
2045 ec.Emit (OpCodes.Castclass, type);
2050 // Created during resolving pahse when an expression is wrapped or constantified
2051 // and original expression can be used later (e.g. for expression trees)
2053 public class ReducedExpression : Expression
2055 public sealed class ReducedConstantExpression : EmptyConstantCast
2057 readonly Expression orig_expr;
2059 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2060 : base (expr, expr.Type)
2062 this.orig_expr = orig_expr;
2065 public Expression OriginalExpression {
2071 public override Constant ConvertImplicitly (TypeSpec target_type)
2073 Constant c = base.ConvertImplicitly (target_type);
2075 c = new ReducedConstantExpression (c, orig_expr);
2080 public override Expression CreateExpressionTree (ResolveContext ec)
2082 return orig_expr.CreateExpressionTree (ec);
2085 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2087 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2089 c = new ReducedConstantExpression (c, orig_expr);
2093 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2096 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2098 if (orig_expr is Conditional)
2099 child.EncodeAttributeValue (rc, enc, targetType);
2101 base.EncodeAttributeValue (rc, enc, targetType);
2105 sealed class ReducedExpressionStatement : ExpressionStatement
2107 readonly Expression orig_expr;
2108 readonly ExpressionStatement stm;
2110 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2112 this.orig_expr = orig;
2114 this.eclass = stm.eclass;
2115 this.type = stm.Type;
2117 this.loc = orig.Location;
2120 public override bool ContainsEmitWithAwait ()
2122 return stm.ContainsEmitWithAwait ();
2125 public override Expression CreateExpressionTree (ResolveContext ec)
2127 return orig_expr.CreateExpressionTree (ec);
2130 protected override Expression DoResolve (ResolveContext ec)
2135 public override void Emit (EmitContext ec)
2140 public override void EmitStatement (EmitContext ec)
2142 stm.EmitStatement (ec);
2146 readonly Expression expr, orig_expr;
2148 private ReducedExpression (Expression expr, Expression orig_expr)
2151 this.eclass = expr.eclass;
2152 this.type = expr.Type;
2153 this.orig_expr = orig_expr;
2154 this.loc = orig_expr.Location;
2159 public override bool IsSideEffectFree {
2161 return expr.IsSideEffectFree;
2165 public Expression OriginalExpression {
2173 public override bool ContainsEmitWithAwait ()
2175 return expr.ContainsEmitWithAwait ();
2179 // Creates fully resolved expression switcher
2181 public static Constant Create (Constant expr, Expression original_expr)
2183 if (expr.eclass == ExprClass.Unresolved)
2184 throw new ArgumentException ("Unresolved expression");
2186 return new ReducedConstantExpression (expr, original_expr);
2189 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2191 return new ReducedExpressionStatement (s, orig);
2194 public static Expression Create (Expression expr, Expression original_expr)
2196 return Create (expr, original_expr, true);
2200 // Creates unresolved reduce expression. The original expression has to be
2201 // already resolved. Created expression is constant based based on `expr'
2202 // value unless canBeConstant is used
2204 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2206 if (canBeConstant) {
2207 Constant c = expr as Constant;
2209 return Create (c, original_expr);
2212 ExpressionStatement s = expr as ExpressionStatement;
2214 return Create (s, original_expr);
2216 if (expr.eclass == ExprClass.Unresolved)
2217 throw new ArgumentException ("Unresolved expression");
2219 return new ReducedExpression (expr, original_expr);
2222 public override Expression CreateExpressionTree (ResolveContext ec)
2224 return orig_expr.CreateExpressionTree (ec);
2227 protected override Expression DoResolve (ResolveContext ec)
2232 public override void Emit (EmitContext ec)
2237 public override Expression EmitToField (EmitContext ec)
2239 return expr.EmitToField(ec);
2242 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2244 expr.EmitBranchable (ec, target, on_true);
2247 public override SLE.Expression MakeExpression (BuilderContext ctx)
2249 return orig_expr.MakeExpression (ctx);
2254 // Standard composite pattern
2256 public abstract class CompositeExpression : Expression
2258 protected Expression expr;
2260 protected CompositeExpression (Expression expr)
2263 this.loc = expr.Location;
2266 public override bool ContainsEmitWithAwait ()
2268 return expr.ContainsEmitWithAwait ();
2271 public override Expression CreateExpressionTree (ResolveContext rc)
2273 return expr.CreateExpressionTree (rc);
2276 public Expression Child {
2277 get { return expr; }
2280 protected override Expression DoResolve (ResolveContext rc)
2282 expr = expr.Resolve (rc);
2285 eclass = expr.eclass;
2291 public override void Emit (EmitContext ec)
2296 public override bool IsNull {
2297 get { return expr.IsNull; }
2302 // Base of expressions used only to narrow resolve flow
2304 public abstract class ShimExpression : Expression
2306 protected Expression expr;
2308 protected ShimExpression (Expression expr)
2313 public Expression Expr {
2319 protected override void CloneTo (CloneContext clonectx, Expression t)
2324 ShimExpression target = (ShimExpression) t;
2325 target.expr = expr.Clone (clonectx);
2328 public override bool ContainsEmitWithAwait ()
2330 return expr.ContainsEmitWithAwait ();
2333 public override Expression CreateExpressionTree (ResolveContext ec)
2335 throw new NotSupportedException ("ET");
2338 public override void Emit (EmitContext ec)
2340 throw new InternalErrorException ("Missing Resolve call");
2346 // Unresolved type name expressions
2348 public abstract class ATypeNameExpression : FullNamedExpression
2351 protected TypeArguments targs;
2353 protected ATypeNameExpression (string name, Location l)
2359 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2366 protected ATypeNameExpression (string name, int arity, Location l)
2367 : this (name, new UnboundTypeArguments (arity), l)
2373 protected int Arity {
2375 return targs == null ? 0 : targs.Count;
2379 public bool HasTypeArguments {
2381 return targs != null && !targs.IsEmpty;
2385 public string Name {
2394 public TypeArguments TypeArguments {
2402 public override bool Equals (object obj)
2404 ATypeNameExpression atne = obj as ATypeNameExpression;
2405 return atne != null && atne.Name == Name &&
2406 (targs == null || targs.Equals (atne.targs));
2409 public override int GetHashCode ()
2411 return Name.GetHashCode ();
2414 // TODO: Move it to MemberCore
2415 public static string GetMemberType (MemberCore mc)
2421 if (mc is FieldBase)
2423 if (mc is MethodCore)
2425 if (mc is EnumMember)
2433 public override string GetSignatureForError ()
2435 if (targs != null) {
2436 return Name + "<" + targs.GetSignatureForError () + ">";
2442 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2446 /// SimpleName expressions are formed of a single word and only happen at the beginning
2447 /// of a dotted-name.
2449 public class SimpleName : ATypeNameExpression
2451 public SimpleName (string name, Location l)
2456 public SimpleName (string name, TypeArguments args, Location l)
2457 : base (name, args, l)
2461 public SimpleName (string name, int arity, Location l)
2462 : base (name, arity, l)
2466 public SimpleName GetMethodGroup ()
2468 return new SimpleName (Name, targs, loc);
2471 protected override Expression DoResolve (ResolveContext rc)
2473 var e = SimpleNameResolve (rc, null);
2475 var fe = e as FieldExpr;
2477 fe.VerifyAssignedStructField (rc, null);
2483 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2485 return SimpleNameResolve (ec, right_side);
2488 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2490 if (ctx.CurrentType != null) {
2491 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2492 if (member != null) {
2493 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2498 var report = ctx.Module.Compiler.Report;
2500 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2501 if (retval != null) {
2502 report.SymbolRelatedToPreviousError (retval.Type);
2503 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2507 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2508 if (retval != null) {
2509 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2513 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2514 if (ns_candidates != null) {
2515 if (ctx is UsingAliasNamespace.AliasContext) {
2516 report.Error (246, loc,
2517 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2518 ns_candidates[0], Name);
2520 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2521 report.Error (246, loc,
2522 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2526 report.Error (246, loc,
2527 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2532 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2534 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2537 if (fne.Type != null && Arity > 0) {
2538 if (HasTypeArguments) {
2539 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2540 if (ct.ResolveAsType (mc) == null)
2546 return new GenericOpenTypeExpr (fne.Type, loc);
2550 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2552 if (!(fne is Namespace))
2556 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2557 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2558 mc.Module.Compiler.Report.Error (1980, Location,
2559 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2560 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2563 fne = new DynamicTypeExpr (loc);
2564 fne.ResolveAsType (mc);
2570 Error_TypeOrNamespaceNotFound (mc);
2574 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2576 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2579 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2581 int lookup_arity = Arity;
2582 bool errorMode = false;
2584 Block current_block = rc.CurrentBlock;
2585 INamedBlockVariable variable = null;
2586 bool variable_found = false;
2590 // Stage 1: binding to local variables or parameters
2592 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2594 if (current_block != null && lookup_arity == 0) {
2595 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2596 if (!variable.IsDeclared) {
2597 // We found local name in accessible block but it's not
2598 // initialized yet, maybe the user wanted to bind to something else
2600 variable_found = true;
2602 e = variable.CreateReferenceExpression (rc, loc);
2605 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2614 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2616 TypeSpec member_type = rc.CurrentType;
2617 for (; member_type != null; member_type = member_type.DeclaringType) {
2618 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2622 var me = e as MemberExpr;
2624 // The name matches a type, defer to ResolveAsTypeStep
2632 if (variable != null) {
2633 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2634 rc.Report.Error (844, loc,
2635 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2636 Name, me.GetSignatureForError ());
2640 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2641 // Leave it to overload resolution to report correct error
2643 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2644 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2647 // LAMESPEC: again, ignores InvocableOnly
2648 if (variable != null) {
2649 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2650 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2654 // MemberLookup does not check accessors availability, this is actually needed for properties only
2656 var pe = me as PropertyExpr;
2659 // Break as there is no other overload available anyway
2660 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2661 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2664 pe.Getter = pe.PropertyInfo.Get;
2666 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2669 pe.Setter = pe.PropertyInfo.Set;
2674 // TODO: It's used by EventExpr -> FieldExpr transformation only
2675 // TODO: Should go to MemberAccess
2676 me = me.ResolveMemberAccess (rc, null, null);
2680 me.SetTypeArguments (rc, targs);
2687 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2689 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2690 if (IsPossibleTypeOrNamespace (rc)) {
2691 if (variable != null) {
2692 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2693 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2696 return ResolveAsTypeOrNamespace (rc);
2701 if (variable_found) {
2702 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2705 var tparams = rc.CurrentTypeParameters;
2706 if (tparams != null) {
2707 if (tparams.Find (Name) != null) {
2708 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2713 var ct = rc.CurrentType;
2715 if (ct.MemberDefinition.TypeParametersCount > 0) {
2716 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2717 if (ctp.Name == Name) {
2718 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2724 ct = ct.DeclaringType;
2725 } while (ct != null);
2728 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2729 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2731 rc.Report.SymbolRelatedToPreviousError (e.Type);
2732 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2736 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2738 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2739 return ErrorExpression.Instance;
2743 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2745 if (e.Type.Arity != Arity) {
2746 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2750 if (e is TypeExpr) {
2751 // TypeExpression does not have correct location
2752 if (e is TypeExpression)
2753 e = new TypeExpression (e.Type, loc);
2759 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2762 return ErrorExpression.Instance;
2765 if (rc.Module.Evaluator != null) {
2766 var fi = rc.Module.Evaluator.LookupField (Name);
2768 return new FieldExpr (fi.Item1, loc);
2776 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2778 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2783 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2784 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2788 if (right_side != null) {
2789 e = e.ResolveLValue (ec, right_side);
2797 public override object Accept (StructuralVisitor visitor)
2799 return visitor.Visit (this);
2804 /// Represents a namespace or a type. The name of the class was inspired by
2805 /// section 10.8.1 (Fully Qualified Names).
2807 public abstract class FullNamedExpression : Expression
2809 protected override void CloneTo (CloneContext clonectx, Expression target)
2811 // Do nothing, most unresolved type expressions cannot be
2812 // resolved to different type
2815 public override bool ContainsEmitWithAwait ()
2820 public override Expression CreateExpressionTree (ResolveContext ec)
2822 throw new NotSupportedException ("ET");
2825 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2828 // This is used to resolve the expression as a type, a null
2829 // value will be returned if the expression is not a type
2832 public override TypeSpec ResolveAsType (IMemberContext mc)
2834 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2839 TypeExpr te = fne as TypeExpr;
2841 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2849 var dep = type.GetMissingDependencies ();
2851 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2854 if (type.Kind == MemberKind.Void) {
2855 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2859 // Obsolete checks cannot be done when resolving base context as they
2860 // require type dependencies to be set but we are in process of resolving them
2862 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2863 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2864 if (obsolete_attr != null && !mc.IsObsolete) {
2865 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2873 public override void Emit (EmitContext ec)
2875 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2876 GetSignatureForError ());
2881 /// Expression that evaluates to a type
2883 public abstract class TypeExpr : FullNamedExpression
2885 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2891 protected sealed override Expression DoResolve (ResolveContext ec)
2897 public override bool Equals (object obj)
2899 TypeExpr tobj = obj as TypeExpr;
2903 return Type == tobj.Type;
2906 public override int GetHashCode ()
2908 return Type.GetHashCode ();
2913 /// Fully resolved Expression that already evaluated to a type
2915 public class TypeExpression : TypeExpr
2917 public TypeExpression (TypeSpec t, Location l)
2920 eclass = ExprClass.Type;
2924 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2931 /// This class denotes an expression which evaluates to a member
2932 /// of a struct or a class.
2934 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2937 // An instance expression associated with this member, if it's a
2938 // non-static member
2940 public Expression InstanceExpression;
2943 /// The name of this member.
2945 public abstract string Name {
2950 // When base.member is used
2952 public bool IsBase {
2953 get { return InstanceExpression is BaseThis; }
2957 /// Whether this is an instance member.
2959 public abstract bool IsInstance {
2964 /// Whether this is a static member.
2966 public abstract bool IsStatic {
2970 public abstract string KindName {
2974 protected abstract TypeSpec DeclaringType {
2978 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2980 return InstanceExpression.Type;
2985 // Converts best base candidate for virtual method starting from QueriedBaseType
2987 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2990 // Only when base.member is used and method is virtual
2996 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2997 // means for base.member access we have to find the closest match after we found best candidate
2999 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3001 // The method could already be what we are looking for
3003 TypeSpec[] targs = null;
3004 if (method.DeclaringType != InstanceExpression.Type) {
3006 // Candidate can have inflated MVAR parameters and we need to find
3007 // base match for original definition not inflated parameter types
3009 var parameters = method.Parameters;
3010 if (method.Arity > 0) {
3011 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3012 var inflated = method.DeclaringType as InflatedTypeSpec;
3013 if (inflated != null) {
3014 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3018 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3019 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3020 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3021 if (base_override.IsGeneric)
3022 targs = method.TypeArguments;
3024 method = base_override;
3029 // When base access is used inside anonymous method/iterator/etc we need to
3030 // get back to the context of original type. We do it by emiting proxy
3031 // method in original class and rewriting base call to this compiler
3032 // generated method call which does the actual base invocation. This may
3033 // introduce redundant storey but with `this' only but it's tricky to avoid
3034 // at this stage as we don't know what expressions follow base
3036 if (rc.CurrentAnonymousMethod != null) {
3037 if (targs == null && method.IsGeneric) {
3038 targs = method.TypeArguments;
3039 method = method.GetGenericMethodDefinition ();
3042 if (method.Parameters.HasArglist)
3043 throw new NotImplementedException ("__arglist base call proxy");
3045 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3047 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3048 // get/set member expressions second call would fail to proxy because left expression
3049 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3050 // FIXME: The async check is another hack but will probably fail with mutators
3051 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3052 InstanceExpression = new This (loc).Resolve (rc);
3056 method = method.MakeGenericMethod (rc, targs);
3060 // Only base will allow this invocation to happen.
3062 if (method.IsAbstract) {
3063 rc.Report.SymbolRelatedToPreviousError (method);
3064 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3070 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3072 if (InstanceExpression == null)
3075 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3076 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3077 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3082 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3084 if (InstanceExpression == null)
3087 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3090 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3092 var ct = rc.CurrentType;
3093 if (ct == qualifier)
3096 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3099 qualifier = qualifier.GetDefinition ();
3100 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3107 public override bool ContainsEmitWithAwait ()
3109 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3112 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3115 type = type.GetDefinition ();
3117 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3120 type = type.DeclaringType;
3121 } while (type != null);
3126 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3128 if (InstanceExpression != null) {
3129 InstanceExpression = InstanceExpression.Resolve (rc);
3130 CheckProtectedMemberAccess (rc, member);
3133 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3134 UnsafeError (rc, loc);
3137 var dep = member.GetMissingDependencies ();
3139 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3142 if (!rc.IsObsolete) {
3143 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3145 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3148 if (!(member is FieldSpec))
3149 member.MemberDefinition.SetIsUsed ();
3152 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3154 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3157 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3159 rc.Report.SymbolRelatedToPreviousError (member);
3160 rc.Report.Error (1540, loc,
3161 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3162 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3165 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3167 if (!ResolveInstanceExpressionCore (rc, rhs))
3171 // Check intermediate value modification which won't have any effect
3173 if (rhs != null && InstanceExpression.Type.IsStruct) {
3174 var fexpr = InstanceExpression as FieldExpr;
3175 if (fexpr != null) {
3176 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3179 if (fexpr.IsStatic) {
3180 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3181 fexpr.GetSignatureForError ());
3183 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3184 fexpr.GetSignatureForError ());
3190 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3191 if (rc.CurrentInitializerVariable != null) {
3192 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3193 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3195 rc.Report.Error (1612, loc,
3196 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3197 InstanceExpression.GetSignatureForError ());
3203 var lvr = InstanceExpression as LocalVariableReference;
3206 if (!lvr.local_info.IsReadonly)
3209 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3210 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3217 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3220 if (InstanceExpression != null) {
3221 if (InstanceExpression is TypeExpr) {
3222 var t = InstanceExpression.Type;
3224 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3225 if (oa != null && !rc.IsObsolete) {
3226 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3229 t = t.DeclaringType;
3230 } while (t != null);
3232 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3233 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3234 rc.Report.Error (176, loc,
3235 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3236 GetSignatureForError ());
3240 InstanceExpression = null;
3246 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3247 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3248 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3249 rc.Report.Error (236, loc,
3250 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3251 GetSignatureForError ());
3253 rc.Report.Error (120, loc,
3254 "An object reference is required to access non-static member `{0}'",
3255 GetSignatureForError ());
3257 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3261 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3262 rc.Report.Error (38, loc,
3263 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3264 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3267 InstanceExpression = new This (loc);
3268 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3269 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3270 InstanceExpression = InstanceExpression.Resolve (rc);
3273 InstanceExpression = InstanceExpression.Resolve (rc);
3279 var me = InstanceExpression as MemberExpr;
3281 me.ResolveInstanceExpressionCore (rc, rhs);
3283 // Using this check to detect probing instance expression resolve
3284 if (!rc.OmitStructFlowAnalysis) {
3285 var fe = me as FieldExpr;
3286 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3287 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3288 rc.Report.Warning (1690, 1, loc,
3289 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3290 me.GetSignatureForError ());
3298 // Run member-access postponed check once we know that
3299 // the expression is not field expression which is the only
3300 // expression which can use uninitialized this
3302 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3303 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3307 // Additional checks for l-value member access
3310 if (InstanceExpression is UnboxCast) {
3311 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3318 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3320 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3321 ec.Report.Warning (1720, 1, left.Location,
3322 "Expression will always cause a `{0}'", "System.NullReferenceException");
3325 InstanceExpression = left;
3329 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3331 TypeSpec instance_type = InstanceExpression.Type;
3332 if (TypeSpec.IsValueType (instance_type)) {
3333 if (InstanceExpression is IMemoryLocation) {
3334 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3336 // Cannot release the temporary variable when its address
3337 // is required to be on stack for any parent
3338 LocalTemporary t = new LocalTemporary (instance_type);
3339 InstanceExpression.Emit (ec);
3341 t.AddressOf (ec, AddressOp.Store);
3344 InstanceExpression.Emit (ec);
3346 // Only to make verifier happy
3347 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3348 ec.Emit (OpCodes.Box, instance_type);
3351 if (prepare_for_load)
3352 ec.Emit (OpCodes.Dup);
3355 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3358 public class ExtensionMethodCandidates
3360 readonly NamespaceContainer container;
3361 readonly IList<MethodSpec> methods;
3363 readonly IMemberContext context;
3365 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3367 this.context = context;
3368 this.methods = methods;
3369 this.container = nsContainer;
3370 this.index = lookupIndex;
3373 public NamespaceContainer Container {
3379 public IMemberContext Context {
3385 public int LookupIndex {
3391 public IList<MethodSpec> Methods {
3399 // Represents a group of extension method candidates for whole namespace
3401 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3403 ExtensionMethodCandidates candidates;
3404 public Expression ExtensionExpression;
3406 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3407 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3409 this.candidates = candidates;
3410 this.ExtensionExpression = extensionExpr;
3413 public override bool IsStatic {
3414 get { return true; }
3418 // For extension methodgroup we are not looking for base members but parent
3419 // namespace extension methods
3421 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3423 // TODO: candidates are null only when doing error reporting, that's
3424 // incorrect. We have to discover same extension methods in error mode
3425 if (candidates == null)
3428 int arity = type_arguments == null ? 0 : type_arguments.Count;
3430 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3431 if (candidates == null)
3434 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3437 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3439 // We are already here
3443 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3445 if (arguments == null)
3446 arguments = new Arguments (1);
3448 ExtensionExpression = ExtensionExpression.Resolve (ec);
3449 if (ExtensionExpression == null)
3452 var cand = candidates;
3453 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3454 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3456 // Restore candidates in case we are running in probing mode
3459 // Store resolved argument and restore original arguments
3461 // Clean-up modified arguments for error reporting
3462 arguments.RemoveAt (0);
3466 var me = ExtensionExpression as MemberExpr;
3468 me.ResolveInstanceExpression (ec, null);
3469 var fe = me as FieldExpr;
3471 fe.Spec.MemberDefinition.SetIsUsed ();
3474 InstanceExpression = null;
3478 #region IErrorHandler Members
3480 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3485 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3487 rc.Report.SymbolRelatedToPreviousError (best);
3488 rc.Report.Error (1928, loc,
3489 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3490 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3493 rc.Report.Error (1929, loc,
3494 "Extension method instance type `{0}' cannot be converted to `{1}'",
3495 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3501 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3506 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3515 /// MethodGroupExpr represents a group of method candidates which
3516 /// can be resolved to the best method overload
3518 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3520 protected IList<MemberSpec> Methods;
3521 MethodSpec best_candidate;
3522 TypeSpec best_candidate_return;
3523 protected TypeArguments type_arguments;
3525 SimpleName simple_name;
3526 protected TypeSpec queried_type;
3528 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3532 this.type = InternalType.MethodGroup;
3534 eclass = ExprClass.MethodGroup;
3535 queried_type = type;
3538 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3539 : this (new MemberSpec[] { m }, type, loc)
3545 public MethodSpec BestCandidate {
3547 return best_candidate;
3551 public TypeSpec BestCandidateReturnType {
3553 return best_candidate_return;
3557 public IList<MemberSpec> Candidates {
3563 protected override TypeSpec DeclaringType {
3565 return queried_type;
3569 public override bool IsInstance {
3571 if (best_candidate != null)
3572 return !best_candidate.IsStatic;
3578 public override bool IsSideEffectFree {
3580 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3584 public override bool IsStatic {
3586 if (best_candidate != null)
3587 return best_candidate.IsStatic;
3593 public override string KindName {
3594 get { return "method"; }
3597 public override string Name {
3599 if (best_candidate != null)
3600 return best_candidate.Name;
3603 return Methods.First ().Name;
3610 // When best candidate is already know this factory can be used
3611 // to avoid expensive overload resolution to be called
3613 // NOTE: InstanceExpression has to be set manually
3615 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3617 return new MethodGroupExpr (best, queriedType, loc) {
3618 best_candidate = best,
3619 best_candidate_return = best.ReturnType
3623 public override string GetSignatureForError ()
3625 if (best_candidate != null)
3626 return best_candidate.GetSignatureForError ();
3628 return Methods.First ().GetSignatureForError ();
3631 public override Expression CreateExpressionTree (ResolveContext ec)
3633 if (best_candidate == null) {
3634 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3638 if (best_candidate.IsConditionallyExcluded (ec))
3639 ec.Report.Error (765, loc,
3640 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3642 return new TypeOfMethod (best_candidate, loc);
3645 protected override Expression DoResolve (ResolveContext ec)
3647 this.eclass = ExprClass.MethodGroup;
3649 if (InstanceExpression != null) {
3650 InstanceExpression = InstanceExpression.Resolve (ec);
3651 if (InstanceExpression == null)
3658 public override void Emit (EmitContext ec)
3660 throw new NotSupportedException ();
3663 public void EmitCall (EmitContext ec, Arguments arguments)
3665 var call = new CallEmitter ();
3666 call.InstanceExpression = InstanceExpression;
3667 call.Emit (ec, best_candidate, arguments, loc);
3670 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3672 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3673 Name, target.GetSignatureForError ());
3676 public static bool IsExtensionMethodArgument (Expression expr)
3679 // LAMESPEC: No details about which expressions are not allowed
3681 return !(expr is TypeExpr) && !(expr is BaseThis);
3685 /// Find the Applicable Function Members (7.4.2.1)
3687 /// me: Method Group expression with the members to select.
3688 /// it might contain constructors or methods (or anything
3689 /// that maps to a method).
3691 /// Arguments: ArrayList containing resolved Argument objects.
3693 /// loc: The location if we want an error to be reported, or a Null
3694 /// location for "probing" purposes.
3696 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3697 /// that is the best match of me on Arguments.
3700 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3702 // TODO: causes issues with probing mode, remove explicit Kind check
3703 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3706 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3707 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3708 r.BaseMembersProvider = this;
3709 r.InstanceQualifier = this;
3712 if (cerrors != null)
3713 r.CustomErrors = cerrors;
3715 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3716 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3717 if (best_candidate == null)
3718 return r.BestCandidateIsDynamic ? this : null;
3720 // Overload resolver had to create a new method group, all checks bellow have already been executed
3721 if (r.BestCandidateNewMethodGroup != null)
3722 return r.BestCandidateNewMethodGroup;
3724 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3725 if (InstanceExpression != null) {
3726 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3727 InstanceExpression = null;
3729 if (best_candidate.IsStatic && simple_name != null) {
3730 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3733 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3737 ResolveInstanceExpression (ec, null);
3740 var base_override = CandidateToBaseOverride (ec, best_candidate);
3741 if (base_override == best_candidate) {
3742 best_candidate_return = r.BestCandidateReturnType;
3744 best_candidate = base_override;
3745 best_candidate_return = best_candidate.ReturnType;
3748 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3749 ConstraintChecker cc = new ConstraintChecker (ec);
3750 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3754 // Additional check for possible imported base override method which
3755 // could not be done during IsOverrideMethodBaseTypeAccessible
3757 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3758 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3759 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3760 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3766 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3768 var fe = left as FieldExpr;
3771 // Using method-group on struct fields makes the struct assigned. I am not sure
3772 // why but that's what .net does
3774 fe.Spec.MemberDefinition.SetIsAssigned ();
3777 simple_name = original;
3778 return base.ResolveMemberAccess (ec, left, original);
3781 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3783 type_arguments = ta;
3786 #region IBaseMembersProvider Members
3788 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3790 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3793 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3795 if (queried_type == member.DeclaringType)
3798 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3799 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3803 // Extension methods lookup after ordinary methods candidates failed to apply
3805 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3807 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3810 if (!IsExtensionMethodArgument (InstanceExpression))
3813 int arity = type_arguments == null ? 0 : type_arguments.Count;
3814 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3815 if (methods == null)
3818 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3819 emg.SetTypeArguments (rc, type_arguments);
3826 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3828 public ConstructorInstanceQualifier (TypeSpec type)
3831 InstanceType = type;
3834 public TypeSpec InstanceType { get; private set; }
3836 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3838 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3842 public struct OverloadResolver
3845 public enum Restrictions
3849 ProbingOnly = 1 << 1,
3850 CovariantDelegate = 1 << 2,
3851 NoBaseMembers = 1 << 3,
3852 BaseMembersIncluded = 1 << 4
3855 public interface IBaseMembersProvider
3857 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3858 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3859 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3862 public interface IErrorHandler
3864 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3865 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3866 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3867 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3870 public interface IInstanceQualifier
3872 TypeSpec InstanceType { get; }
3873 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3876 sealed class NoBaseMembers : IBaseMembersProvider
3878 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3880 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3885 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3890 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3896 struct AmbiguousCandidate
3898 public readonly MemberSpec Member;
3899 public readonly bool Expanded;
3900 public readonly AParametersCollection Parameters;
3902 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3905 Parameters = parameters;
3906 Expanded = expanded;
3911 IList<MemberSpec> members;
3912 TypeArguments type_arguments;
3913 IBaseMembersProvider base_provider;
3914 IErrorHandler custom_errors;
3915 IInstanceQualifier instance_qualifier;
3916 Restrictions restrictions;
3917 MethodGroupExpr best_candidate_extension_group;
3918 TypeSpec best_candidate_return_type;
3920 SessionReportPrinter lambda_conv_msgs;
3922 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3923 : this (members, null, restrictions, loc)
3927 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3930 if (members == null || members.Count == 0)
3931 throw new ArgumentException ("empty members set");
3933 this.members = members;
3935 type_arguments = targs;
3936 this.restrictions = restrictions;
3937 if (IsDelegateInvoke)
3938 this.restrictions |= Restrictions.NoBaseMembers;
3940 base_provider = NoBaseMembers.Instance;
3945 public IBaseMembersProvider BaseMembersProvider {
3947 return base_provider;
3950 base_provider = value;
3954 public bool BestCandidateIsDynamic { get; set; }
3957 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3959 public MethodGroupExpr BestCandidateNewMethodGroup {
3961 return best_candidate_extension_group;
3966 // Return type can be different between best candidate and closest override
3968 public TypeSpec BestCandidateReturnType {
3970 return best_candidate_return_type;
3974 public IErrorHandler CustomErrors {
3976 return custom_errors;
3979 custom_errors = value;
3983 TypeSpec DelegateType {
3985 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3986 throw new InternalErrorException ("Not running in delegate mode", loc);
3988 return members [0].DeclaringType;
3992 public IInstanceQualifier InstanceQualifier {
3994 return instance_qualifier;
3997 instance_qualifier = value;
4001 bool IsProbingOnly {
4003 return (restrictions & Restrictions.ProbingOnly) != 0;
4007 bool IsDelegateInvoke {
4009 return (restrictions & Restrictions.DelegateInvoke) != 0;
4016 // 7.4.3.3 Better conversion from expression
4017 // Returns : 1 if a->p is better,
4018 // 2 if a->q is better,
4019 // 0 if neither is better
4021 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4023 TypeSpec argument_type = a.Type;
4026 // If argument is an anonymous function
4028 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4030 // p and q are delegate types or expression tree types
4032 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4033 if (q.MemberDefinition != p.MemberDefinition) {
4038 // Uwrap delegate from Expression<T>
4040 q = TypeManager.GetTypeArguments (q)[0];
4041 p = TypeManager.GetTypeArguments (p)[0];
4044 var p_m = Delegate.GetInvokeMethod (p);
4045 var q_m = Delegate.GetInvokeMethod (q);
4048 // With identical parameter lists
4050 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4059 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4061 if (p.Kind == MemberKind.Void) {
4062 return q.Kind != MemberKind.Void ? 2 : 0;
4066 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4068 if (q.Kind == MemberKind.Void) {
4069 return p.Kind != MemberKind.Void ? 1: 0;
4072 var am = (AnonymousMethodExpression) a.Expr;
4075 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4076 // better conversion is performed between underlying types Y1 and Y2
4078 if (p.IsGenericTask || q.IsGenericTask) {
4079 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4080 q = q.TypeArguments[0];
4081 p = p.TypeArguments[0];
4083 } else if (q != p) {
4085 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4087 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4088 var am_rt = am.InferReturnType (ec, null, orig_q);
4089 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4091 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4092 var am_rt = am.InferReturnType (ec, null, orig_p);
4093 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4099 // The parameters are identicial and return type is not void, use better type conversion
4100 // on return type to determine better one
4103 if (argument_type == p)
4106 if (argument_type == q)
4110 return BetterTypeConversion (ec, p, q);
4114 // 7.4.3.4 Better conversion from type
4116 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4118 if (p == null || q == null)
4119 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4121 switch (p.BuiltinType) {
4122 case BuiltinTypeSpec.Type.Int:
4123 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4126 case BuiltinTypeSpec.Type.Long:
4127 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4130 case BuiltinTypeSpec.Type.SByte:
4131 switch (q.BuiltinType) {
4132 case BuiltinTypeSpec.Type.Byte:
4133 case BuiltinTypeSpec.Type.UShort:
4134 case BuiltinTypeSpec.Type.UInt:
4135 case BuiltinTypeSpec.Type.ULong:
4139 case BuiltinTypeSpec.Type.Short:
4140 switch (q.BuiltinType) {
4141 case BuiltinTypeSpec.Type.UShort:
4142 case BuiltinTypeSpec.Type.UInt:
4143 case BuiltinTypeSpec.Type.ULong:
4147 case BuiltinTypeSpec.Type.Dynamic:
4148 // Dynamic is never better
4152 switch (q.BuiltinType) {
4153 case BuiltinTypeSpec.Type.Int:
4154 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4157 case BuiltinTypeSpec.Type.Long:
4158 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4161 case BuiltinTypeSpec.Type.SByte:
4162 switch (p.BuiltinType) {
4163 case BuiltinTypeSpec.Type.Byte:
4164 case BuiltinTypeSpec.Type.UShort:
4165 case BuiltinTypeSpec.Type.UInt:
4166 case BuiltinTypeSpec.Type.ULong:
4170 case BuiltinTypeSpec.Type.Short:
4171 switch (p.BuiltinType) {
4172 case BuiltinTypeSpec.Type.UShort:
4173 case BuiltinTypeSpec.Type.UInt:
4174 case BuiltinTypeSpec.Type.ULong:
4178 case BuiltinTypeSpec.Type.Dynamic:
4179 // Dynamic is never better
4183 // FIXME: handle lifted operators
4185 // TODO: this is expensive
4186 Expression p_tmp = new EmptyExpression (p);
4187 Expression q_tmp = new EmptyExpression (q);
4189 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4190 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4192 if (p_to_q && !q_to_p)
4195 if (q_to_p && !p_to_q)
4202 /// Determines "Better function" between candidate
4203 /// and the current best match
4206 /// Returns a boolean indicating :
4207 /// false if candidate ain't better
4208 /// true if candidate is better than the current best match
4210 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4211 MemberSpec best, AParametersCollection bparam, bool best_params)
4213 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4214 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4216 bool better_at_least_one = false;
4218 int args_count = args == null ? 0 : args.Count;
4222 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4225 // Default arguments are ignored for better decision
4226 if (a.IsDefaultArgument)
4230 // When comparing named argument the parameter type index has to be looked up
4231 // in original parameter set (override version for virtual members)
4233 NamedArgument na = a as NamedArgument;
4235 int idx = cparam.GetParameterIndexByName (na.Name);
4236 ct = candidate_pd.Types[idx];
4237 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4238 ct = TypeManager.GetElementType (ct);
4240 idx = bparam.GetParameterIndexByName (na.Name);
4241 bt = best_pd.Types[idx];
4242 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4243 bt = TypeManager.GetElementType (bt);
4245 ct = candidate_pd.Types[c_idx];
4246 bt = best_pd.Types[b_idx];
4248 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4249 ct = TypeManager.GetElementType (ct);
4253 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4254 bt = TypeManager.GetElementType (bt);
4259 if (TypeSpecComparer.IsEqual (ct, bt))
4263 int result = BetterExpressionConversion (ec, a, ct, bt);
4265 // for each argument, the conversion to 'ct' should be no worse than
4266 // the conversion to 'bt'.
4270 // for at least one argument, the conversion to 'ct' should be better than
4271 // the conversion to 'bt'.
4273 better_at_least_one = true;
4276 if (better_at_least_one)
4280 // This handles the case
4282 // Add (float f1, float f2, float f3);
4283 // Add (params decimal [] foo);
4285 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4286 // first candidate would've chosen as better.
4288 if (!same && !a.IsDefaultArgument)
4292 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4296 // This handles the following cases:
4298 // Foo (int i) is better than Foo (int i, long l = 0)
4299 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4300 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4302 // Prefer non-optional version
4304 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4306 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4307 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4310 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4313 return candidate_pd.Count >= best_pd.Count;
4317 // One is a non-generic method and second is a generic method, then non-generic is better
4319 if (best.IsGeneric != candidate.IsGeneric)
4320 return best.IsGeneric;
4323 // This handles the following cases:
4325 // Trim () is better than Trim (params char[] chars)
4326 // Concat (string s1, string s2, string s3) is better than
4327 // Concat (string s1, params string [] srest)
4328 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4330 // Prefer non-expanded version
4332 if (candidate_params != best_params)
4335 int candidate_param_count = candidate_pd.Count;
4336 int best_param_count = best_pd.Count;
4338 if (candidate_param_count != best_param_count)
4339 // can only happen if (candidate_params && best_params)
4340 return candidate_param_count > best_param_count && best_pd.HasParams;
4343 // Both methods have the same number of parameters, and the parameters have equal types
4344 // Pick the "more specific" signature using rules over original (non-inflated) types
4346 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4347 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4349 bool specific_at_least_once = false;
4350 for (j = 0; j < args_count; ++j) {
4351 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4353 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4354 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4356 ct = candidate_def_pd.Types[j];
4357 bt = best_def_pd.Types[j];
4362 TypeSpec specific = MoreSpecific (ct, bt);
4366 specific_at_least_once = true;
4369 if (specific_at_least_once)
4375 static bool CheckInflatedArguments (MethodSpec ms)
4377 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4380 // Setup constraint checker for probing only
4381 ConstraintChecker cc = new ConstraintChecker (null);
4383 var mp = ms.Parameters.Types;
4384 for (int i = 0; i < mp.Length; ++i) {
4385 var type = mp[i] as InflatedTypeSpec;
4389 var targs = type.TypeArguments;
4390 if (targs.Length == 0)
4393 // TODO: Checking inflated MVAR arguments should be enough
4394 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4401 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4403 rc.Report.Error (1729, loc,
4404 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4405 type.GetSignatureForError (), argCount.ToString ());
4409 // Determines if the candidate method is applicable to the given set of arguments
4410 // There could be two different set of parameters for same candidate where one
4411 // is the closest override for default values and named arguments checks and second
4412 // one being the virtual base for the parameter types and modifiers.
4414 // A return value rates candidate method compatibility,
4415 // 0 = the best, int.MaxValue = the worst
4418 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)
4420 // Parameters of most-derived type used mainly for named and optional parameters
4421 var pd = pm.Parameters;
4423 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4424 // params modifier instead of most-derived type
4425 var cpd = ((IParametersMember) candidate).Parameters;
4426 int param_count = pd.Count;
4427 int optional_count = 0;
4429 Arguments orig_args = arguments;
4431 if (arg_count != param_count) {
4433 // No arguments expansion when doing exact match for delegates
4435 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4436 for (int i = 0; i < pd.Count; ++i) {
4437 if (pd.FixedParameters[i].HasDefaultValue) {
4438 optional_count = pd.Count - i;
4444 if (optional_count != 0) {
4445 // Readjust expected number when params used
4446 if (cpd.HasParams) {
4448 if (arg_count < param_count)
4450 } else if (arg_count > param_count) {
4451 int args_gap = System.Math.Abs (arg_count - param_count);
4452 return int.MaxValue - 10000 + args_gap;
4453 } else if (arg_count < param_count - optional_count) {
4454 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4455 return int.MaxValue - 10000 + args_gap;
4457 } else if (arg_count != param_count) {
4458 int args_gap = System.Math.Abs (arg_count - param_count);
4460 return int.MaxValue - 10000 + args_gap;
4461 if (arg_count < param_count - 1)
4462 return int.MaxValue - 10000 + args_gap;
4465 // Resize to fit optional arguments
4466 if (optional_count != 0) {
4467 if (arguments == null) {
4468 arguments = new Arguments (optional_count);
4470 // Have to create a new container, so the next run can do same
4471 var resized = new Arguments (param_count);
4472 resized.AddRange (arguments);
4473 arguments = resized;
4476 for (int i = arg_count; i < param_count; ++i)
4477 arguments.Add (null);
4481 if (arg_count > 0) {
4483 // Shuffle named arguments to the right positions if there are any
4485 if (arguments[arg_count - 1] is NamedArgument) {
4486 arg_count = arguments.Count;
4488 for (int i = 0; i < arg_count; ++i) {
4489 bool arg_moved = false;
4491 NamedArgument na = arguments[i] as NamedArgument;
4495 int index = pd.GetParameterIndexByName (na.Name);
4497 // Named parameter not found
4501 // already reordered
4506 if (index >= param_count) {
4507 // When using parameters which should not be available to the user
4508 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4511 arguments.Add (null);
4515 temp = arguments[index];
4517 // The slot has been taken by positional argument
4518 if (temp != null && !(temp is NamedArgument))
4523 arguments = arguments.MarkOrderedArgument (na);
4527 if (arguments == orig_args) {
4528 arguments = new Arguments (orig_args.Count);
4529 arguments.AddRange (orig_args);
4532 arguments[index] = arguments[i];
4533 arguments[i] = temp;
4540 arg_count = arguments.Count;
4542 } else if (arguments != null) {
4543 arg_count = arguments.Count;
4547 // Don't do any expensive checks when the candidate cannot succeed
4549 if (arg_count != param_count && !cpd.HasParams)
4550 return (param_count - arg_count) * 2 + 1;
4552 var dep = candidate.GetMissingDependencies ();
4554 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4559 // 1. Handle generic method using type arguments when specified or type inference
4562 var ms = candidate as MethodSpec;
4563 if (ms != null && ms.IsGeneric) {
4564 if (type_arguments != null) {
4565 var g_args_count = ms.Arity;
4566 if (g_args_count != type_arguments.Count)
4567 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4569 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4572 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4573 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4574 // candidate was found use the set to report more details about what was wrong with lambda body.
4575 // The general idea is to distinguish between code errors and errors caused by
4576 // trial-and-error type inference
4578 if (lambda_conv_msgs == null) {
4579 for (int i = 0; i < arg_count; i++) {
4580 Argument a = arguments[i];
4584 var am = a.Expr as AnonymousMethodExpression;
4586 if (lambda_conv_msgs == null)
4587 lambda_conv_msgs = new SessionReportPrinter ();
4589 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4594 var ti = new TypeInference (arguments);
4595 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4598 return ti.InferenceScore - 20000;
4601 // Clear any error messages when the result was success
4603 if (lambda_conv_msgs != null)
4604 lambda_conv_msgs.ClearSession ();
4606 if (i_args.Length != 0) {
4607 ms = ms.MakeGenericMethod (ec, i_args);
4612 // Type arguments constraints have to match for the method to be applicable
4614 if (!CheckInflatedArguments (ms)) {
4616 return int.MaxValue - 25000;
4620 // We have a generic return type and at same time the method is override which
4621 // means we have to also inflate override return type in case the candidate is
4622 // best candidate and override return type is different to base return type.
4624 // virtual Foo<T, object> with override Foo<T, dynamic>
4626 if (candidate != pm) {
4627 MethodSpec override_ms = (MethodSpec) pm;
4628 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4629 returnType = inflator.Inflate (returnType);
4631 returnType = ms.ReturnType;
4638 if (type_arguments != null)
4639 return int.MaxValue - 15000;
4645 // 2. Each argument has to be implicitly convertible to method parameter
4647 Parameter.Modifier p_mod = 0;
4650 for (int i = 0; i < arg_count; i++) {
4651 Argument a = arguments[i];
4653 var fp = pd.FixedParameters[i];
4654 if (!fp.HasDefaultValue) {
4655 arguments = orig_args;
4656 return arg_count * 2 + 2;
4660 // Get the default value expression, we can use the same expression
4661 // if the type matches
4663 Expression e = fp.DefaultValue;
4665 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4667 // Restore for possible error reporting
4668 for (int ii = i; ii < arg_count; ++ii)
4669 arguments.RemoveAt (i);
4671 return (arg_count - i) * 2 + 1;
4675 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4677 // LAMESPEC: Attributes can be mixed together with build-in priority
4679 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4680 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4681 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4682 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4683 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4684 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4688 arguments[i] = new Argument (e, Argument.AType.Default);
4692 if (p_mod != Parameter.Modifier.PARAMS) {
4693 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4695 } else if (!params_expanded_form) {
4696 params_expanded_form = true;
4697 pt = ((ElementTypeSpec) pt).Element;
4703 if (!params_expanded_form) {
4704 if (a.ArgType == Argument.AType.ExtensionType) {
4706 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4708 // LAMESPEC: or implicit type parameter conversion
4711 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4712 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4713 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4718 score = IsArgumentCompatible (ec, a, p_mod, pt);
4721 dynamicArgument = true;
4726 // It can be applicable in expanded form (when not doing exact match like for delegates)
4728 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4729 if (!params_expanded_form) {
4730 pt = ((ElementTypeSpec) pt).Element;
4734 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4737 params_expanded_form = true;
4738 dynamicArgument = true;
4739 } else if (score == 0 || arg_count > pd.Count) {
4740 params_expanded_form = true;
4745 if (params_expanded_form)
4747 return (arg_count - i) * 2 + score;
4752 // When params parameter has no argument it will be provided later if the method is the best candidate
4754 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4755 params_expanded_form = true;
4758 // Restore original arguments for dynamic binder to keep the intention of original source code
4760 if (dynamicArgument)
4761 arguments = orig_args;
4766 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4768 if (e is Constant && e.Type == ptype)
4772 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4774 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4775 e = new MemberAccess (new MemberAccess (new MemberAccess (
4776 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4777 } else if (e is Constant) {
4779 // Handles int to int? conversions, DefaultParameterValue check
4781 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4785 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4788 return e.Resolve (ec);
4792 // Tests argument compatibility with the parameter
4793 // The possible return values are
4795 // 1 - modifier mismatch
4796 // 2 - type mismatch
4797 // -1 - dynamic binding required
4799 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4802 // Types have to be identical when ref or out modifer
4803 // is used and argument is not of dynamic type
4805 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4806 if (argument.Type != parameter) {
4808 // Do full equality check after quick path
4810 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4812 // Using dynamic for ref/out parameter can still succeed at runtime
4814 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4821 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4823 // Using dynamic for ref/out parameter can still succeed at runtime
4825 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4832 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4836 // Use implicit conversion in all modes to return same candidates when the expression
4837 // is used as argument or delegate conversion
4839 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4840 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4847 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4849 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4851 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4854 var ac_p = p as ArrayContainer;
4856 var ac_q = q as ArrayContainer;
4860 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4861 if (specific == ac_p.Element)
4863 if (specific == ac_q.Element)
4865 } else if (p.IsGeneric && q.IsGeneric) {
4866 var pargs = TypeManager.GetTypeArguments (p);
4867 var qargs = TypeManager.GetTypeArguments (q);
4869 bool p_specific_at_least_once = false;
4870 bool q_specific_at_least_once = false;
4872 for (int i = 0; i < pargs.Length; i++) {
4873 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4874 if (specific == pargs[i])
4875 p_specific_at_least_once = true;
4876 if (specific == qargs[i])
4877 q_specific_at_least_once = true;
4880 if (p_specific_at_least_once && !q_specific_at_least_once)
4882 if (!p_specific_at_least_once && q_specific_at_least_once)
4890 // Find the best method from candidate list
4892 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4894 List<AmbiguousCandidate> ambiguous_candidates = null;
4896 MemberSpec best_candidate;
4897 Arguments best_candidate_args = null;
4898 bool best_candidate_params = false;
4899 bool best_candidate_dynamic = false;
4900 int best_candidate_rate;
4901 IParametersMember best_parameter_member = null;
4903 int args_count = args != null ? args.Count : 0;
4905 Arguments candidate_args = args;
4906 bool error_mode = false;
4907 MemberSpec invocable_member = null;
4910 best_candidate = null;
4911 best_candidate_rate = int.MaxValue;
4913 var type_members = members;
4915 for (int i = 0; i < type_members.Count; ++i) {
4916 var member = type_members[i];
4919 // Methods in a base class are not candidates if any method in a derived
4920 // class is applicable
4922 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4926 if (!member.IsAccessible (rc))
4929 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4932 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4933 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4938 IParametersMember pm = member as IParametersMember;
4941 // Will use it later to report ambiguity between best method and invocable member
4943 if (Invocation.IsMemberInvocable (member))
4944 invocable_member = member;
4950 // Overload resolution is looking for base member but using parameter names
4951 // and default values from the closest member. That means to do expensive lookup
4952 // for the closest override for virtual or abstract members
4954 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4955 var override_params = base_provider.GetOverrideMemberParameters (member);
4956 if (override_params != null)
4957 pm = override_params;
4961 // Check if the member candidate is applicable
4963 bool params_expanded_form = false;
4964 bool dynamic_argument = false;
4965 TypeSpec rt = pm.MemberType;
4966 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4968 if (lambda_conv_msgs != null)
4969 lambda_conv_msgs.EndSession ();
4972 // How does it score compare to others
4974 if (candidate_rate < best_candidate_rate) {
4976 // Fatal error (missing dependency), cannot continue
4977 if (candidate_rate < 0)
4980 best_candidate_rate = candidate_rate;
4981 best_candidate = member;
4982 best_candidate_args = candidate_args;
4983 best_candidate_params = params_expanded_form;
4984 best_candidate_dynamic = dynamic_argument;
4985 best_parameter_member = pm;
4986 best_candidate_return_type = rt;
4987 } else if (candidate_rate == 0) {
4989 // The member look is done per type for most operations but sometimes
4990 // it's not possible like for binary operators overload because they
4991 // are unioned between 2 sides
4993 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4994 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4999 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5001 // We pack all interface members into top level type which makes the overload resolution
5002 // more complicated for interfaces. We compensate it by removing methods with same
5003 // signature when building the cache hence this path should not really be hit often
5006 // interface IA { void Foo (int arg); }
5007 // interface IB : IA { void Foo (params int[] args); }
5009 // IB::Foo is the best overload when calling IB.Foo (1)
5012 if (ambiguous_candidates != null) {
5013 foreach (var amb_cand in ambiguous_candidates) {
5014 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5023 ambiguous_candidates = null;
5026 // Is the new candidate better
5027 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5031 best_candidate = member;
5032 best_candidate_args = candidate_args;
5033 best_candidate_params = params_expanded_form;
5034 best_candidate_dynamic = dynamic_argument;
5035 best_parameter_member = pm;
5036 best_candidate_return_type = rt;
5038 // It's not better but any other found later could be but we are not sure yet
5039 if (ambiguous_candidates == null)
5040 ambiguous_candidates = new List<AmbiguousCandidate> ();
5042 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5046 // Restore expanded arguments
5047 candidate_args = args;
5049 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5052 // We've found exact match
5054 if (best_candidate_rate == 0)
5058 // Try extension methods lookup when no ordinary method match was found and provider enables it
5061 var emg = base_provider.LookupExtensionMethod (rc);
5063 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5065 best_candidate_extension_group = emg;
5066 return (T) (MemberSpec) emg.BestCandidate;
5071 // Don't run expensive error reporting mode for probing
5078 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5081 lambda_conv_msgs = null;
5086 // No best member match found, report an error
5088 if (best_candidate_rate != 0 || error_mode) {
5089 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5093 if (best_candidate_dynamic) {
5094 if (args[0].ArgType == Argument.AType.ExtensionType) {
5095 rc.Report.Error (1973, loc,
5096 "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",
5097 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5101 // Check type constraints only when explicit type arguments are used
5103 if (best_candidate.IsGeneric && type_arguments != null) {
5104 MethodSpec bc = best_candidate as MethodSpec;
5105 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5106 ConstraintChecker cc = new ConstraintChecker (rc);
5107 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5111 BestCandidateIsDynamic = true;
5116 // These flags indicates we are running delegate probing conversion. No need to
5117 // do more expensive checks
5119 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5120 return (T) best_candidate;
5122 if (ambiguous_candidates != null) {
5124 // Now check that there are no ambiguities i.e the selected method
5125 // should be better than all the others
5127 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5128 var candidate = ambiguous_candidates [ix];
5130 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5131 var ambiguous = candidate.Member;
5132 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5133 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5134 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5135 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5136 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5139 return (T) best_candidate;
5144 if (invocable_member != null && !IsProbingOnly) {
5145 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5146 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5147 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5148 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5152 // And now check if the arguments are all
5153 // compatible, perform conversions if
5154 // necessary etc. and return if everything is
5157 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5160 if (best_candidate == null)
5164 // Don't run possibly expensive checks in probing mode
5166 if (!IsProbingOnly && !rc.IsInProbingMode) {
5168 // Check ObsoleteAttribute on the best method
5170 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5171 if (oa != null && !rc.IsObsolete)
5172 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5174 best_candidate.MemberDefinition.SetIsUsed ();
5177 args = best_candidate_args;
5178 return (T) best_candidate;
5181 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5183 return ResolveMember<MethodSpec> (rc, ref args);
5186 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5187 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5189 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5192 if (a.Type == InternalType.ErrorType)
5195 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5196 ec.Report.SymbolRelatedToPreviousError (method);
5197 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5198 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5199 TypeManager.CSharpSignature (method));
5202 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5203 TypeManager.CSharpSignature (method));
5204 } else if (IsDelegateInvoke) {
5205 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5206 DelegateType.GetSignatureForError ());
5208 ec.Report.SymbolRelatedToPreviousError (method);
5209 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5210 method.GetSignatureForError ());
5213 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5215 string index = (idx + 1).ToString ();
5216 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5217 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5218 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5219 index, Parameter.GetModifierSignature (a.Modifier));
5221 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5222 index, Parameter.GetModifierSignature (mod));
5224 string p1 = a.GetSignatureForError ();
5225 string p2 = paramType.GetSignatureForError ();
5228 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5229 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5232 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5233 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5234 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5237 ec.Report.Error (1503, a.Expr.Location,
5238 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5243 // We have failed to find exact match so we return error info about the closest match
5245 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5247 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5248 int arg_count = args == null ? 0 : args.Count;
5250 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5251 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5252 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5256 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5261 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5262 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5263 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5267 // For candidates which match on parameters count report more details about incorrect arguments
5270 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5271 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5272 // Reject any inaccessible member
5273 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5274 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5275 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5279 var ms = best_candidate as MethodSpec;
5280 if (ms != null && ms.IsGeneric) {
5281 bool constr_ok = true;
5282 if (ms.TypeArguments != null)
5283 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5285 if (ta_count == 0 && ms.TypeArguments == null) {
5286 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5290 rc.Report.Error (411, loc,
5291 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5292 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5299 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5305 // We failed to find any method with correct argument count, report best candidate
5307 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5310 if (best_candidate.Kind == MemberKind.Constructor) {
5311 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5312 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5313 } else if (IsDelegateInvoke) {
5314 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5315 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5316 DelegateType.GetSignatureForError (), arg_count.ToString ());
5318 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5319 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5320 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5321 name, arg_count.ToString ());
5325 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5327 var pd = pm.Parameters;
5328 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5330 Parameter.Modifier p_mod = 0;
5332 int a_idx = 0, a_pos = 0;
5334 ArrayInitializer params_initializers = null;
5335 bool has_unsafe_arg = pm.MemberType.IsPointer;
5336 int arg_count = args == null ? 0 : args.Count;
5338 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5343 if (p_mod != Parameter.Modifier.PARAMS) {
5344 p_mod = pd.FixedParameters[a_idx].ModFlags;
5346 has_unsafe_arg |= pt.IsPointer;
5348 if (p_mod == Parameter.Modifier.PARAMS) {
5349 if (chose_params_expanded) {
5350 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5351 pt = TypeManager.GetElementType (pt);
5357 // Types have to be identical when ref or out modifer is used
5359 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5360 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5363 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5369 NamedArgument na = a as NamedArgument;
5371 int name_index = pd.GetParameterIndexByName (na.Name);
5372 if (name_index < 0 || name_index >= pd.Count) {
5373 if (IsDelegateInvoke) {
5374 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5375 ec.Report.Error (1746, na.Location,
5376 "The delegate `{0}' does not contain a parameter named `{1}'",
5377 DelegateType.GetSignatureForError (), na.Name);
5379 ec.Report.SymbolRelatedToPreviousError (member);
5380 ec.Report.Error (1739, na.Location,
5381 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5382 TypeManager.CSharpSignature (member), na.Name);
5384 } else if (args[name_index] != a && args[name_index] != null) {
5385 if (IsDelegateInvoke)
5386 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5388 ec.Report.SymbolRelatedToPreviousError (member);
5390 ec.Report.Error (1744, na.Location,
5391 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5396 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5399 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5400 custom_errors.NoArgumentMatch (ec, member);
5405 if (a.ArgType == Argument.AType.ExtensionType) {
5406 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5409 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5411 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5414 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5421 // Convert params arguments to an array initializer
5423 if (params_initializers != null) {
5424 // we choose to use 'a.Expr' rather than 'conv' so that
5425 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5426 params_initializers.Add (a.Expr);
5427 args.RemoveAt (a_idx--);
5433 // Update the argument with the implicit conversion
5437 if (a_idx != arg_count) {
5438 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5443 // Fill not provided arguments required by params modifier
5445 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5447 args = new Arguments (1);
5449 pt = ptypes[pd.Count - 1];
5450 pt = TypeManager.GetElementType (pt);
5451 has_unsafe_arg |= pt.IsPointer;
5452 params_initializers = new ArrayInitializer (0, loc);
5456 // Append an array argument with all params arguments
5458 if (params_initializers != null) {
5459 args.Add (new Argument (
5460 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5464 if (has_unsafe_arg && !ec.IsUnsafe) {
5465 Expression.UnsafeError (ec, loc);
5469 // We could infer inaccesible type arguments
5471 if (type_arguments == null && member.IsGeneric) {
5472 var ms = (MethodSpec) member;
5473 foreach (var ta in ms.TypeArguments) {
5474 if (!ta.IsAccessible (ec)) {
5475 ec.Report.SymbolRelatedToPreviousError (ta);
5476 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5486 public class ConstantExpr : MemberExpr
5488 readonly ConstSpec constant;
5490 public ConstantExpr (ConstSpec constant, Location loc)
5492 this.constant = constant;
5496 public override string Name {
5497 get { throw new NotImplementedException (); }
5500 public override string KindName {
5501 get { return "constant"; }
5504 public override bool IsInstance {
5505 get { return !IsStatic; }
5508 public override bool IsStatic {
5509 get { return true; }
5512 protected override TypeSpec DeclaringType {
5513 get { return constant.DeclaringType; }
5516 public override Expression CreateExpressionTree (ResolveContext ec)
5518 throw new NotSupportedException ("ET");
5521 protected override Expression DoResolve (ResolveContext rc)
5523 ResolveInstanceExpression (rc, null);
5524 DoBestMemberChecks (rc, constant);
5526 var c = constant.GetConstant (rc);
5528 // Creates reference expression to the constant value
5529 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5532 public override void Emit (EmitContext ec)
5534 throw new NotSupportedException ();
5537 public override string GetSignatureForError ()
5539 return constant.GetSignatureForError ();
5542 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5544 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5549 // Fully resolved expression that references a Field
5551 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5553 protected FieldSpec spec;
5554 VariableInfo variable_info;
5556 LocalTemporary temp;
5559 protected FieldExpr (Location l)
5564 public FieldExpr (FieldSpec spec, Location loc)
5569 type = spec.MemberType;
5572 public FieldExpr (FieldBase fi, Location l)
5579 public override string Name {
5585 public bool IsHoisted {
5587 IVariableReference hv = InstanceExpression as IVariableReference;
5588 return hv != null && hv.IsHoisted;
5592 public override bool IsInstance {
5594 return !spec.IsStatic;
5598 public override bool IsStatic {
5600 return spec.IsStatic;
5604 public override string KindName {
5605 get { return "field"; }
5608 public FieldSpec Spec {
5614 protected override TypeSpec DeclaringType {
5616 return spec.DeclaringType;
5620 public VariableInfo VariableInfo {
5622 return variable_info;
5628 public override string GetSignatureForError ()
5630 return spec.GetSignatureForError ();
5633 public bool IsMarshalByRefAccess (ResolveContext rc)
5635 // Checks possible ldflda of field access expression
5636 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5637 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5638 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5641 public void SetHasAddressTaken ()
5643 IVariableReference vr = InstanceExpression as IVariableReference;
5645 vr.SetHasAddressTaken ();
5649 public override Expression CreateExpressionTree (ResolveContext ec)
5651 return CreateExpressionTree (ec, true);
5654 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5657 Expression instance;
5659 if (InstanceExpression == null) {
5660 instance = new NullLiteral (loc);
5661 } else if (convertInstance) {
5662 instance = InstanceExpression.CreateExpressionTree (ec);
5664 args = new Arguments (1);
5665 args.Add (new Argument (InstanceExpression));
5666 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5669 args = Arguments.CreateForExpressionTree (ec, null,
5671 CreateTypeOfExpression ());
5673 return CreateExpressionFactoryCall (ec, "Field", args);
5676 public Expression CreateTypeOfExpression ()
5678 return new TypeOfField (spec, loc);
5681 protected override Expression DoResolve (ResolveContext ec)
5683 spec.MemberDefinition.SetIsUsed ();
5685 return DoResolve (ec, null);
5688 Expression DoResolve (ResolveContext ec, Expression rhs)
5690 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5693 if (ResolveInstanceExpression (ec, rhs)) {
5694 // Resolve the field's instance expression while flow analysis is turned
5695 // off: when accessing a field "a.b", we must check whether the field
5696 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5698 if (lvalue_instance) {
5699 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5700 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5702 Expression right_side =
5703 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5705 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5708 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5709 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5713 if (InstanceExpression == null)
5717 DoBestMemberChecks (ec, spec);
5720 var fb = spec as FixedFieldSpec;
5721 IVariableReference var = InstanceExpression as IVariableReference;
5723 if (lvalue_instance && var != null && var.VariableInfo != null) {
5724 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5728 IFixedExpression fe = InstanceExpression as IFixedExpression;
5729 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5730 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5733 if (InstanceExpression.eclass != ExprClass.Variable) {
5734 ec.Report.SymbolRelatedToPreviousError (spec);
5735 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5736 TypeManager.GetFullNameSignature (spec));
5737 } else if (var != null && var.IsHoisted) {
5738 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5741 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5745 // Set flow-analysis variable info for struct member access. It will be check later
5746 // for precise error reporting
5748 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5749 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5750 if (rhs != null && variable_info != null)
5751 variable_info.SetStructFieldAssigned (ec, Name);
5754 eclass = ExprClass.Variable;
5758 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5763 var var = fe.InstanceExpression as IVariableReference;
5765 var vi = var.VariableInfo;
5767 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5769 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5771 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5778 fe = fe.InstanceExpression as FieldExpr;
5780 } while (fe != null);
5783 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5785 // The return value is always null. Returning a value simplifies calling code.
5787 if (right_side == EmptyExpression.OutAccess) {
5789 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5790 GetSignatureForError ());
5792 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5793 GetSignatureForError ());
5799 if (right_side == EmptyExpression.LValueMemberAccess) {
5800 // Already reported as CS1648/CS1650
5804 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5806 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5807 GetSignatureForError ());
5809 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5810 GetSignatureForError ());
5817 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5818 GetSignatureForError ());
5820 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5821 GetSignatureForError ());
5827 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5829 if (spec is FixedFieldSpec) {
5830 // It could be much better error message but we want to be error compatible
5831 Error_ValueAssignment (ec, right_side);
5834 Expression e = DoResolve (ec, right_side);
5839 spec.MemberDefinition.SetIsAssigned ();
5841 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5842 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5843 ec.Report.Warning (420, 1, loc,
5844 "`{0}': A volatile field references will not be treated as volatile",
5845 spec.GetSignatureForError ());
5848 if (spec.IsReadOnly) {
5849 // InitOnly fields can only be assigned in constructors or initializers
5850 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5851 return Error_AssignToReadonly (ec, right_side);
5853 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5855 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5856 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5857 return Error_AssignToReadonly (ec, right_side);
5858 // static InitOnly fields cannot be assigned-to in an instance constructor
5859 if (IsStatic && !ec.IsStatic)
5860 return Error_AssignToReadonly (ec, right_side);
5861 // instance constructors can't modify InitOnly fields of other instances of the same type
5862 if (!IsStatic && !(InstanceExpression is This))
5863 return Error_AssignToReadonly (ec, right_side);
5867 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5868 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5869 ec.Report.Warning (197, 1, loc,
5870 "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",
5871 GetSignatureForError ());
5874 eclass = ExprClass.Variable;
5878 public override int GetHashCode ()
5880 return spec.GetHashCode ();
5883 public bool IsFixed {
5886 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5888 IVariableReference variable = InstanceExpression as IVariableReference;
5889 if (variable != null)
5890 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5892 IFixedExpression fe = InstanceExpression as IFixedExpression;
5893 return fe != null && fe.IsFixed;
5897 public override bool Equals (object obj)
5899 FieldExpr fe = obj as FieldExpr;
5903 if (spec != fe.spec)
5906 if (InstanceExpression == null || fe.InstanceExpression == null)
5909 return InstanceExpression.Equals (fe.InstanceExpression);
5912 public void Emit (EmitContext ec, bool leave_copy)
5914 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5918 ec.Emit (OpCodes.Volatile);
5920 ec.Emit (OpCodes.Ldsfld, spec);
5923 EmitInstance (ec, false);
5925 // Optimization for build-in types
5926 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5927 ec.EmitLoadFromPtr (type);
5929 var ff = spec as FixedFieldSpec;
5931 ec.Emit (OpCodes.Ldflda, spec);
5932 ec.Emit (OpCodes.Ldflda, ff.Element);
5935 ec.Emit (OpCodes.Volatile);
5937 ec.Emit (OpCodes.Ldfld, spec);
5943 ec.Emit (OpCodes.Dup);
5945 temp = new LocalTemporary (this.Type);
5951 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5953 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5954 if (isCompound && !(source is DynamicExpressionStatement)) {
5955 if (has_await_source) {
5957 InstanceExpression = InstanceExpression.EmitToField (ec);
5964 if (has_await_source)
5965 source = source.EmitToField (ec);
5967 EmitInstance (ec, prepared);
5973 ec.Emit (OpCodes.Dup);
5975 temp = new LocalTemporary (this.Type);
5980 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5981 ec.Emit (OpCodes.Volatile);
5983 spec.MemberDefinition.SetIsAssigned ();
5986 ec.Emit (OpCodes.Stsfld, spec);
5988 ec.Emit (OpCodes.Stfld, spec);
5998 // Emits store to field with prepared values on stack
6000 public void EmitAssignFromStack (EmitContext ec)
6003 ec.Emit (OpCodes.Stsfld, spec);
6005 ec.Emit (OpCodes.Stfld, spec);
6009 public override void Emit (EmitContext ec)
6014 public override void EmitSideEffect (EmitContext ec)
6016 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6018 if (is_volatile) // || is_marshal_by_ref ())
6019 base.EmitSideEffect (ec);
6022 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6024 if ((mode & AddressOp.Store) != 0)
6025 spec.MemberDefinition.SetIsAssigned ();
6026 if ((mode & AddressOp.Load) != 0)
6027 spec.MemberDefinition.SetIsUsed ();
6030 // Handle initonly fields specially: make a copy and then
6031 // get the address of the copy.
6034 if (spec.IsReadOnly){
6036 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6048 var temp = ec.GetTemporaryLocal (type);
6049 ec.Emit (OpCodes.Stloc, temp);
6050 ec.Emit (OpCodes.Ldloca, temp);
6051 ec.FreeTemporaryLocal (temp, type);
6057 ec.Emit (OpCodes.Ldsflda, spec);
6060 EmitInstance (ec, false);
6061 ec.Emit (OpCodes.Ldflda, spec);
6065 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6067 return MakeExpression (ctx);
6070 public override SLE.Expression MakeExpression (BuilderContext ctx)
6073 return base.MakeExpression (ctx);
6075 return SLE.Expression.Field (
6076 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6077 spec.GetMetaInfo ());
6081 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6083 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6089 // Expression that evaluates to a Property.
6091 // This is not an LValue because we need to re-write the expression. We
6092 // can not take data from the stack and store it.
6094 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6096 Arguments arguments;
6098 public PropertyExpr (PropertySpec spec, Location l)
6101 best_candidate = spec;
6102 type = spec.MemberType;
6107 protected override Arguments Arguments {
6116 protected override TypeSpec DeclaringType {
6118 return best_candidate.DeclaringType;
6122 public override string Name {
6124 return best_candidate.Name;
6128 public override bool IsInstance {
6134 public override bool IsStatic {
6136 return best_candidate.IsStatic;
6140 public override string KindName {
6141 get { return "property"; }
6144 public PropertySpec PropertyInfo {
6146 return best_candidate;
6152 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6154 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6157 var args_count = arguments == null ? 0 : arguments.Count;
6158 if (args_count != body.Parameters.Count && args_count == 0)
6161 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6162 mg.InstanceExpression = InstanceExpression;
6167 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6169 return new PropertyExpr (spec, loc) {
6175 public override Expression CreateExpressionTree (ResolveContext ec)
6178 if (IsSingleDimensionalArrayLength ()) {
6179 args = new Arguments (1);
6180 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6181 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6184 args = new Arguments (2);
6185 if (InstanceExpression == null)
6186 args.Add (new Argument (new NullLiteral (loc)));
6188 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6189 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6190 return CreateExpressionFactoryCall (ec, "Property", args);
6193 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6195 DoResolveLValue (rc, null);
6196 return new TypeOfMethod (Setter, loc);
6199 public override string GetSignatureForError ()
6201 return best_candidate.GetSignatureForError ();
6204 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6207 return base.MakeExpression (ctx);
6209 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6213 public override SLE.Expression MakeExpression (BuilderContext ctx)
6216 return base.MakeExpression (ctx);
6218 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6222 void Error_PropertyNotValid (ResolveContext ec)
6224 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6225 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6226 GetSignatureForError ());
6229 bool IsSingleDimensionalArrayLength ()
6231 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6234 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6235 return ac != null && ac.Rank == 1;
6238 public override void Emit (EmitContext ec, bool leave_copy)
6241 // Special case: length of single dimension array property is turned into ldlen
6243 if (IsSingleDimensionalArrayLength ()) {
6244 EmitInstance (ec, false);
6245 ec.Emit (OpCodes.Ldlen);
6246 ec.Emit (OpCodes.Conv_I4);
6250 base.Emit (ec, leave_copy);
6253 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6256 LocalTemporary await_source_arg = null;
6258 if (isCompound && !(source is DynamicExpressionStatement)) {
6259 emitting_compound_assignment = true;
6262 if (has_await_arguments) {
6263 await_source_arg = new LocalTemporary (Type);
6264 await_source_arg.Store (ec);
6266 args = new Arguments (1);
6267 args.Add (new Argument (await_source_arg));
6270 temp = await_source_arg;
6273 has_await_arguments = false;
6278 ec.Emit (OpCodes.Dup);
6279 temp = new LocalTemporary (this.Type);
6284 args = arguments ?? new Arguments (1);
6288 temp = new LocalTemporary (this.Type);
6290 args.Add (new Argument (temp));
6292 args.Add (new Argument (source));
6296 emitting_compound_assignment = false;
6298 var call = new CallEmitter ();
6299 call.InstanceExpression = InstanceExpression;
6301 call.InstanceExpressionOnStack = true;
6303 call.Emit (ec, Setter, args, loc);
6310 if (await_source_arg != null) {
6311 await_source_arg.Release (ec);
6315 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6317 eclass = ExprClass.PropertyAccess;
6319 if (best_candidate.IsNotCSharpCompatible) {
6320 Error_PropertyNotValid (rc);
6323 ResolveInstanceExpression (rc, right_side);
6325 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6326 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6327 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6329 type = p.MemberType;
6333 DoBestMemberChecks (rc, best_candidate);
6335 // Handling of com-imported properties with any number of default property parameters
6336 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6337 var p = best_candidate.Get.Parameters;
6338 arguments = new Arguments (p.Count);
6339 for (int i = 0; i < p.Count; ++i) {
6340 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6342 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6343 var p = best_candidate.Set.Parameters;
6344 arguments = new Arguments (p.Count - 1);
6345 for (int i = 0; i < p.Count - 1; ++i) {
6346 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6353 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6355 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6359 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6361 // getter and setter can be different for base calls
6362 MethodSpec getter, setter;
6363 protected T best_candidate;
6365 protected LocalTemporary temp;
6366 protected bool emitting_compound_assignment;
6367 protected bool has_await_arguments;
6369 protected PropertyOrIndexerExpr (Location l)
6376 protected abstract Arguments Arguments { get; set; }
6378 public MethodSpec Getter {
6387 public MethodSpec Setter {
6398 protected override Expression DoResolve (ResolveContext ec)
6400 if (eclass == ExprClass.Unresolved) {
6401 var expr = OverloadResolve (ec, null);
6406 return expr.Resolve (ec);
6409 if (!ResolveGetter (ec))
6415 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6417 if (right_side == EmptyExpression.OutAccess) {
6418 // TODO: best_candidate can be null at this point
6419 INamedBlockVariable variable = null;
6420 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6421 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6422 best_candidate.Name);
6424 right_side.DoResolveLValue (ec, this);
6429 if (eclass == ExprClass.Unresolved) {
6430 var expr = OverloadResolve (ec, right_side);
6435 return expr.ResolveLValue (ec, right_side);
6438 if (!ResolveSetter (ec))
6445 // Implements the IAssignMethod interface for assignments
6447 public virtual void Emit (EmitContext ec, bool leave_copy)
6449 var call = new CallEmitter ();
6450 call.InstanceExpression = InstanceExpression;
6451 if (has_await_arguments)
6452 call.HasAwaitArguments = true;
6454 call.DuplicateArguments = emitting_compound_assignment;
6456 call.Emit (ec, Getter, Arguments, loc);
6458 if (call.HasAwaitArguments) {
6459 InstanceExpression = call.InstanceExpression;
6460 Arguments = call.EmittedArguments;
6461 has_await_arguments = true;
6465 ec.Emit (OpCodes.Dup);
6466 temp = new LocalTemporary (Type);
6471 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6473 public override void Emit (EmitContext ec)
6478 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6480 has_await_arguments = true;
6485 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6487 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6489 bool ResolveGetter (ResolveContext rc)
6491 if (!best_candidate.HasGet) {
6492 if (InstanceExpression != EmptyExpression.Null) {
6493 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6494 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6495 best_candidate.GetSignatureForError ());
6498 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6499 if (best_candidate.HasDifferentAccessibility) {
6500 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6501 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6502 TypeManager.CSharpSignature (best_candidate));
6504 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6505 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6509 if (best_candidate.HasDifferentAccessibility) {
6510 CheckProtectedMemberAccess (rc, best_candidate.Get);
6513 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6517 bool ResolveSetter (ResolveContext rc)
6519 if (!best_candidate.HasSet) {
6520 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6521 GetSignatureForError ());
6525 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6526 if (best_candidate.HasDifferentAccessibility) {
6527 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6528 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6529 GetSignatureForError ());
6531 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6532 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6536 if (best_candidate.HasDifferentAccessibility)
6537 CheckProtectedMemberAccess (rc, best_candidate.Set);
6539 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6545 /// Fully resolved expression that evaluates to an Event
6547 public class EventExpr : MemberExpr, IAssignMethod
6549 readonly EventSpec spec;
6552 public EventExpr (EventSpec spec, Location loc)
6560 protected override TypeSpec DeclaringType {
6562 return spec.DeclaringType;
6566 public override string Name {
6572 public override bool IsInstance {
6574 return !spec.IsStatic;
6578 public override bool IsStatic {
6580 return spec.IsStatic;
6584 public override string KindName {
6585 get { return "event"; }
6588 public MethodSpec Operator {
6596 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6599 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6601 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6602 if (spec.BackingField != null &&
6603 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6605 spec.MemberDefinition.SetIsUsed ();
6607 if (!ec.IsObsolete) {
6608 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6610 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6613 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6614 Error_AssignmentEventOnly (ec);
6616 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6618 InstanceExpression = null;
6620 return ml.ResolveMemberAccess (ec, left, original);
6624 return base.ResolveMemberAccess (ec, left, original);
6627 public override Expression CreateExpressionTree (ResolveContext ec)
6629 throw new NotSupportedException ("ET");
6632 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6634 if (right_side == EmptyExpression.EventAddition) {
6635 op = spec.AccessorAdd;
6636 } else if (right_side == EmptyExpression.EventSubtraction) {
6637 op = spec.AccessorRemove;
6641 Error_AssignmentEventOnly (ec);
6645 op = CandidateToBaseOverride (ec, op);
6649 protected override Expression DoResolve (ResolveContext ec)
6651 eclass = ExprClass.EventAccess;
6652 type = spec.MemberType;
6654 ResolveInstanceExpression (ec, null);
6656 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6657 Error_AssignmentEventOnly (ec);
6660 DoBestMemberChecks (ec, spec);
6664 public override void Emit (EmitContext ec)
6666 throw new NotSupportedException ();
6667 //Error_CannotAssign ();
6670 #region IAssignMethod Members
6672 public void Emit (EmitContext ec, bool leave_copy)
6674 throw new NotImplementedException ();
6677 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6679 if (leave_copy || !isCompound)
6680 throw new NotImplementedException ("EventExpr::EmitAssign");
6682 Arguments args = new Arguments (1);
6683 args.Add (new Argument (source));
6685 var call = new CallEmitter ();
6686 call.InstanceExpression = InstanceExpression;
6687 call.Emit (ec, op, args, loc);
6692 void Error_AssignmentEventOnly (ResolveContext ec)
6694 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6695 ec.Report.Error (79, loc,
6696 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6697 GetSignatureForError ());
6699 ec.Report.Error (70, loc,
6700 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6701 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6705 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6707 name = name.Substring (0, name.LastIndexOf ('.'));
6708 base.Error_CannotCallAbstractBase (rc, name);
6711 public override string GetSignatureForError ()
6713 return TypeManager.CSharpSignature (spec);
6716 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6718 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6722 public class TemporaryVariableReference : VariableReference
6724 public class Declarator : Statement
6726 TemporaryVariableReference variable;
6728 public Declarator (TemporaryVariableReference variable)
6730 this.variable = variable;
6734 protected override void DoEmit (EmitContext ec)
6736 variable.li.CreateBuilder (ec);
6739 public override void Emit (EmitContext ec)
6741 // Don't create sequence point
6745 protected override void CloneTo (CloneContext clonectx, Statement target)
6753 public TemporaryVariableReference (LocalVariable li, Location loc)
6756 this.type = li.Type;
6760 public override bool IsLockedByStatement {
6768 public LocalVariable LocalInfo {
6774 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6776 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6777 return new TemporaryVariableReference (li, loc);
6780 protected override Expression DoResolve (ResolveContext ec)
6782 eclass = ExprClass.Variable;
6785 // Don't capture temporary variables except when using
6786 // state machine redirection and block yields
6788 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6789 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6790 ec.IsVariableCapturingRequired) {
6791 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6792 storey.CaptureLocalVariable (ec, li);
6798 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6800 return Resolve (ec);
6803 public override void Emit (EmitContext ec)
6805 li.CreateBuilder (ec);
6810 public void EmitAssign (EmitContext ec, Expression source)
6812 li.CreateBuilder (ec);
6814 EmitAssign (ec, source, false, false);
6817 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6819 return li.HoistedVariant;
6822 public override bool IsFixed {
6823 get { return true; }
6826 public override bool IsRef {
6827 get { return false; }
6830 public override string Name {
6831 get { throw new NotImplementedException (); }
6834 public override void SetHasAddressTaken ()
6836 throw new NotImplementedException ();
6839 protected override ILocalVariable Variable {
6843 public override VariableInfo VariableInfo {
6844 get { return null; }
6847 public override void VerifyDefiniteAssignment (ResolveContext rc)
6853 /// Handles `var' contextual keyword; var becomes a keyword only
6854 /// if no type called var exists in a variable scope
6856 class VarExpr : SimpleName
6858 public VarExpr (Location loc)
6863 public bool InferType (ResolveContext ec, Expression right_side)
6866 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6868 type = right_side.Type;
6869 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6870 ec.Report.Error (815, loc,
6871 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6872 type.GetSignatureForError ());
6876 eclass = ExprClass.Variable;
6880 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6882 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6883 base.Error_TypeOrNamespaceNotFound (ec);
6885 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");