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");
926 public virtual void FlowAnalysis (FlowAnalysisContext fc)
931 /// Returns an expression that can be used to invoke operator true
932 /// on the expression if it exists.
934 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
936 return GetOperatorTrueOrFalse (ec, e, true, loc);
940 /// Returns an expression that can be used to invoke operator false
941 /// on the expression if it exists.
943 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
945 return GetOperatorTrueOrFalse (ec, e, false, loc);
948 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
950 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
951 var methods = MemberCache.GetUserOperator (e.type, op, false);
955 Arguments arguments = new Arguments (1);
956 arguments.Add (new Argument (e));
958 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
959 var oper = res.ResolveOperator (ec, ref arguments);
964 return new UserOperatorCall (oper, arguments, null, loc);
967 public virtual string ExprClassName
971 case ExprClass.Unresolved:
973 case ExprClass.Value:
975 case ExprClass.Variable:
977 case ExprClass.Namespace:
981 case ExprClass.MethodGroup:
982 return "method group";
983 case ExprClass.PropertyAccess:
984 return "property access";
985 case ExprClass.EventAccess:
986 return "event access";
987 case ExprClass.IndexerAccess:
988 return "indexer access";
989 case ExprClass.Nothing:
991 case ExprClass.TypeParameter:
992 return "type parameter";
994 throw new Exception ("Should not happen");
999 /// Reports that we were expecting `expr' to be of class `expected'
1001 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1003 var name = memberExpr.GetSignatureForError ();
1005 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1008 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1010 string [] valid = new string [4];
1013 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1014 valid [count++] = "variable";
1015 valid [count++] = "value";
1018 if ((flags & ResolveFlags.Type) != 0)
1019 valid [count++] = "type";
1021 if ((flags & ResolveFlags.MethodGroup) != 0)
1022 valid [count++] = "method group";
1025 valid [count++] = "unknown";
1027 StringBuilder sb = new StringBuilder (valid [0]);
1028 for (int i = 1; i < count - 1; i++) {
1030 sb.Append (valid [i]);
1033 sb.Append ("' or `");
1034 sb.Append (valid [count - 1]);
1037 ec.Report.Error (119, loc,
1038 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1041 public static void UnsafeError (ResolveContext ec, Location loc)
1043 UnsafeError (ec.Report, loc);
1046 public static void UnsafeError (Report Report, Location loc)
1048 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1052 // Converts `source' to an int, uint, long or ulong.
1054 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1056 var btypes = ec.BuiltinTypes;
1058 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1059 Arguments args = new Arguments (1);
1060 args.Add (new Argument (source));
1061 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1064 Expression converted;
1066 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1067 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1068 if (converted == null)
1069 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1070 if (converted == null)
1071 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1072 if (converted == null)
1073 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1075 if (converted == null) {
1076 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1082 // Only positive constants are allowed at compile time
1084 Constant c = converted as Constant;
1085 if (c != null && c.IsNegative)
1086 Error_NegativeArrayIndex (ec, source.loc);
1088 // No conversion needed to array index
1089 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1092 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1096 // Derived classes implement this method by cloning the fields that
1097 // could become altered during the Resolve stage
1099 // Only expressions that are created for the parser need to implement
1102 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1104 throw new NotImplementedException (
1106 "CloneTo not implemented for expression {0}", this.GetType ()));
1110 // Clones an expression created by the parser.
1112 // We only support expressions created by the parser so far, not
1113 // expressions that have been resolved (many more classes would need
1114 // to implement CloneTo).
1116 // This infrastructure is here merely for Lambda expressions which
1117 // compile the same code using different type values for the same
1118 // arguments to find the correct overload
1120 public virtual Expression Clone (CloneContext clonectx)
1122 Expression cloned = (Expression) MemberwiseClone ();
1123 CloneTo (clonectx, cloned);
1129 // Implementation of expression to expression tree conversion
1131 public abstract Expression CreateExpressionTree (ResolveContext ec);
1133 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1135 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1138 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1140 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1143 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1145 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1148 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1150 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1154 return new TypeExpression (t, loc);
1158 // Implemented by all expressions which support conversion from
1159 // compiler expression to invokable runtime expression. Used by
1160 // dynamic C# binder.
1162 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1164 throw new NotImplementedException ("MakeExpression for " + GetType ());
1167 public virtual object Accept (StructuralVisitor visitor)
1169 return visitor.Visit (this);
1174 /// This is just a base class for expressions that can
1175 /// appear on statements (invocations, object creation,
1176 /// assignments, post/pre increment and decrement). The idea
1177 /// being that they would support an extra Emition interface that
1178 /// does not leave a result on the stack.
1180 public abstract class ExpressionStatement : Expression
1182 public virtual void MarkReachable (Reachability rc)
1186 public ExpressionStatement ResolveStatement (BlockContext ec)
1188 Expression e = Resolve (ec);
1192 ExpressionStatement es = e as ExpressionStatement;
1194 Error_InvalidExpressionStatement (ec);
1197 // This is quite expensive warning, try to limit the damage
1199 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1200 WarningAsyncWithoutWait (ec, e);
1206 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1208 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1209 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1214 // Need to do full resolve because GetAwaiter can be extension method
1215 // available only in this context
1217 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1221 var arguments = new Arguments (0);
1222 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1227 // Use same check rules as for real await
1229 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1230 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
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");
1238 var inv = e as Invocation;
1239 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1240 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1241 bc.Report.Warning (4014, 1, e.Location,
1242 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1248 /// Requests the expression to be emitted in a `statement'
1249 /// context. This means that no new value is left on the
1250 /// stack after invoking this method (constrasted with
1251 /// Emit that will always leave a value on the stack).
1253 public abstract void EmitStatement (EmitContext ec);
1255 public override void EmitSideEffect (EmitContext ec)
1262 /// This kind of cast is used to encapsulate the child
1263 /// whose type is child.Type into an expression that is
1264 /// reported to return "return_type". This is used to encapsulate
1265 /// expressions which have compatible types, but need to be dealt
1266 /// at higher levels with.
1268 /// For example, a "byte" expression could be encapsulated in one
1269 /// of these as an "unsigned int". The type for the expression
1270 /// would be "unsigned int".
1273 public abstract class TypeCast : Expression
1275 protected readonly Expression child;
1277 protected TypeCast (Expression child, TypeSpec return_type)
1279 eclass = child.eclass;
1280 loc = child.Location;
1285 public Expression Child {
1291 public override bool ContainsEmitWithAwait ()
1293 return child.ContainsEmitWithAwait ();
1296 public override Expression CreateExpressionTree (ResolveContext ec)
1298 Arguments args = new Arguments (2);
1299 args.Add (new Argument (child.CreateExpressionTree (ec)));
1300 args.Add (new Argument (new TypeOf (type, loc)));
1302 if (type.IsPointer || child.Type.IsPointer)
1303 Error_PointerInsideExpressionTree (ec);
1305 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1308 protected override Expression DoResolve (ResolveContext ec)
1310 // This should never be invoked, we are born in fully
1311 // initialized state.
1316 public override void Emit (EmitContext ec)
1321 public override void FlowAnalysis (FlowAnalysisContext fc)
1323 child.FlowAnalysis (fc);
1326 public override SLE.Expression MakeExpression (BuilderContext ctx)
1329 return base.MakeExpression (ctx);
1331 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1332 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1333 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1337 protected override void CloneTo (CloneContext clonectx, Expression t)
1342 public override bool IsNull {
1343 get { return child.IsNull; }
1347 public class EmptyCast : TypeCast {
1348 EmptyCast (Expression child, TypeSpec target_type)
1349 : base (child, target_type)
1353 public static Expression Create (Expression child, TypeSpec type)
1355 Constant c = child as Constant;
1357 var enum_constant = c as EnumConstant;
1358 if (enum_constant != null)
1359 c = enum_constant.Child;
1361 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1365 var res = c.ConvertImplicitly (type);
1371 EmptyCast e = child as EmptyCast;
1373 return new EmptyCast (e.child, type);
1375 return new EmptyCast (child, type);
1378 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1380 child.EmitBranchable (ec, label, on_true);
1383 public override void EmitSideEffect (EmitContext ec)
1385 child.EmitSideEffect (ec);
1390 // Used for predefined type user operator (no obsolete check, etc.)
1392 public class OperatorCast : TypeCast
1394 readonly MethodSpec conversion_operator;
1396 public OperatorCast (Expression expr, TypeSpec target_type)
1397 : this (expr, target_type, target_type, false)
1401 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1402 : this (expr, target_type, target_type, find_explicit)
1406 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1407 : base (expr, returnType)
1409 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1410 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1413 foreach (MethodSpec oper in mi) {
1414 if (oper.ReturnType != returnType)
1417 if (oper.Parameters.Types[0] == expr.Type) {
1418 conversion_operator = oper;
1424 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1425 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1428 public override void Emit (EmitContext ec)
1431 ec.Emit (OpCodes.Call, conversion_operator);
1436 // Constant specialization of EmptyCast.
1437 // We need to special case this since an empty cast of
1438 // a constant is still a constant.
1440 public class EmptyConstantCast : Constant
1442 public readonly Constant child;
1444 public EmptyConstantCast (Constant child, TypeSpec type)
1445 : base (child.Location)
1448 throw new ArgumentNullException ("child");
1451 this.eclass = child.eclass;
1455 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1457 if (child.Type == target_type)
1460 // FIXME: check that 'type' can be converted to 'target_type' first
1461 return child.ConvertExplicitly (in_checked_context, target_type);
1464 public override Expression CreateExpressionTree (ResolveContext ec)
1466 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1467 child.CreateExpressionTree (ec),
1468 new TypeOf (type, loc));
1471 Error_PointerInsideExpressionTree (ec);
1473 return CreateExpressionFactoryCall (ec, "Convert", args);
1476 public override bool IsDefaultValue {
1477 get { return child.IsDefaultValue; }
1480 public override bool IsNegative {
1481 get { return child.IsNegative; }
1484 public override bool IsNull {
1485 get { return child.IsNull; }
1488 public override bool IsOneInteger {
1489 get { return child.IsOneInteger; }
1492 public override bool IsSideEffectFree {
1494 return child.IsSideEffectFree;
1498 public override bool IsZeroInteger {
1499 get { return child.IsZeroInteger; }
1502 public override void Emit (EmitContext ec)
1507 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1509 child.EmitBranchable (ec, label, on_true);
1511 // Only to make verifier happy
1512 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1513 ec.Emit (OpCodes.Unbox_Any, type);
1516 public override void EmitSideEffect (EmitContext ec)
1518 child.EmitSideEffect (ec);
1521 public override object GetValue ()
1523 return child.GetValue ();
1526 public override string GetValueAsLiteral ()
1528 return child.GetValueAsLiteral ();
1531 public override long GetValueAsLong ()
1533 return child.GetValueAsLong ();
1536 public override Constant ConvertImplicitly (TypeSpec target_type)
1538 if (type == target_type)
1541 // FIXME: Do we need to check user conversions?
1542 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1545 return child.ConvertImplicitly (target_type);
1550 /// This class is used to wrap literals which belong inside Enums
1552 public class EnumConstant : Constant
1554 public Constant Child;
1556 public EnumConstant (Constant child, TypeSpec enum_type)
1557 : base (child.Location)
1561 this.eclass = ExprClass.Value;
1562 this.type = enum_type;
1565 protected EnumConstant (Location loc)
1570 public override void Emit (EmitContext ec)
1575 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1577 Child.EncodeAttributeValue (rc, enc, Child.Type);
1580 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1582 Child.EmitBranchable (ec, label, on_true);
1585 public override void EmitSideEffect (EmitContext ec)
1587 Child.EmitSideEffect (ec);
1590 public override string GetSignatureForError()
1592 return Type.GetSignatureForError ();
1595 public override object GetValue ()
1597 return Child.GetValue ();
1601 public override object GetTypedValue ()
1604 // The method can be used in dynamic context only (on closed types)
1606 // System.Enum.ToObject cannot be called on dynamic types
1607 // EnumBuilder has to be used, but we cannot use EnumBuilder
1608 // because it does not properly support generics
1610 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1614 public override string GetValueAsLiteral ()
1616 return Child.GetValueAsLiteral ();
1619 public override long GetValueAsLong ()
1621 return Child.GetValueAsLong ();
1624 public EnumConstant Increment()
1626 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1629 public override bool IsDefaultValue {
1631 return Child.IsDefaultValue;
1635 public override bool IsSideEffectFree {
1637 return Child.IsSideEffectFree;
1641 public override bool IsZeroInteger {
1642 get { return Child.IsZeroInteger; }
1645 public override bool IsNegative {
1647 return Child.IsNegative;
1651 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1653 if (Child.Type == target_type)
1656 return Child.ConvertExplicitly (in_checked_context, target_type);
1659 public override Constant ConvertImplicitly (TypeSpec type)
1661 if (this.type == type) {
1665 if (!Convert.ImplicitStandardConversionExists (this, type)){
1669 return Child.ConvertImplicitly (type);
1674 /// This kind of cast is used to encapsulate Value Types in objects.
1676 /// The effect of it is to box the value type emitted by the previous
1679 public class BoxedCast : TypeCast {
1681 public BoxedCast (Expression expr, TypeSpec target_type)
1682 : base (expr, target_type)
1684 eclass = ExprClass.Value;
1687 protected override Expression DoResolve (ResolveContext ec)
1689 // This should never be invoked, we are born in fully
1690 // initialized state.
1695 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1697 // Only boxing to object type is supported
1698 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1699 base.EncodeAttributeValue (rc, enc, targetType);
1703 enc.Encode (child.Type);
1704 child.EncodeAttributeValue (rc, enc, child.Type);
1707 public override void Emit (EmitContext ec)
1711 ec.Emit (OpCodes.Box, child.Type);
1714 public override void EmitSideEffect (EmitContext ec)
1716 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1717 // so, we need to emit the box+pop instructions in most cases
1718 if (child.Type.IsStruct &&
1719 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1720 child.EmitSideEffect (ec);
1722 base.EmitSideEffect (ec);
1726 public class UnboxCast : TypeCast {
1727 public UnboxCast (Expression expr, TypeSpec return_type)
1728 : base (expr, return_type)
1732 protected override Expression DoResolve (ResolveContext ec)
1734 // This should never be invoked, we are born in fully
1735 // initialized state.
1740 public override void Emit (EmitContext ec)
1744 ec.Emit (OpCodes.Unbox_Any, type);
1749 /// This is used to perform explicit numeric conversions.
1751 /// Explicit numeric conversions might trigger exceptions in a checked
1752 /// context, so they should generate the conv.ovf opcodes instead of
1755 public class ConvCast : TypeCast {
1756 public enum Mode : byte {
1757 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1759 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1760 U2_I1, U2_U1, U2_I2, U2_CH,
1761 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1762 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1763 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1764 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1765 CH_I1, CH_U1, CH_I2,
1766 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1767 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1773 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1774 : base (child, return_type)
1779 protected override Expression DoResolve (ResolveContext ec)
1781 // This should never be invoked, we are born in fully
1782 // initialized state.
1787 public override string ToString ()
1789 return String.Format ("ConvCast ({0}, {1})", mode, child);
1792 public override void Emit (EmitContext ec)
1798 public static void Emit (EmitContext ec, Mode mode)
1800 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1802 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1803 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1804 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1805 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1806 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1808 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1809 case Mode.U1_CH: /* nothing */ break;
1811 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1812 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1813 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1814 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1815 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1820 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1821 case Mode.U2_CH: /* nothing */ break;
1823 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1824 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1825 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1826 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1827 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1829 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1831 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1832 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1833 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1834 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1835 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1836 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1838 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1839 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1840 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1841 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1842 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1843 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1844 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1845 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1846 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1848 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1849 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1850 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1851 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1852 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1853 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1854 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1855 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1856 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1858 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1859 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1860 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1862 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1863 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1864 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1865 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1866 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1867 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1868 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1869 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1870 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1872 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1873 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1874 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1875 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1876 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1877 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1878 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1879 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1880 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1881 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1883 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1887 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1888 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1889 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1890 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1891 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1893 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1894 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1896 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1897 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1898 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1899 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1900 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1901 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1905 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1906 case Mode.U2_CH: /* nothing */ break;
1908 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1909 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1910 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1911 case Mode.I4_U4: /* nothing */ break;
1912 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1913 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1914 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1916 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1917 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1918 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1919 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1920 case Mode.U4_I4: /* nothing */ break;
1921 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1924 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1925 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1926 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1927 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1928 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1929 case Mode.I8_U8: /* nothing */ break;
1930 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1931 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1933 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1934 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1935 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1936 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1937 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1938 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1939 case Mode.U8_I8: /* nothing */ break;
1940 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1941 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1943 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1944 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1945 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1947 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1948 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1949 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1950 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1951 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1952 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1953 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1954 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1955 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1957 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1958 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1959 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1960 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1961 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1962 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1963 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1964 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1965 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1966 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1968 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1974 class OpcodeCast : TypeCast
1978 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1979 : base (child, return_type)
1984 protected override Expression DoResolve (ResolveContext ec)
1986 // This should never be invoked, we are born in fully
1987 // initialized state.
1992 public override void Emit (EmitContext ec)
1998 public TypeSpec UnderlyingType {
1999 get { return child.Type; }
2004 // Opcode casts expression with 2 opcodes but only
2005 // single expression tree node
2007 class OpcodeCastDuplex : OpcodeCast
2009 readonly OpCode second;
2011 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2012 : base (child, returnType, first)
2014 this.second = second;
2017 public override void Emit (EmitContext ec)
2025 /// This kind of cast is used to encapsulate a child and cast it
2026 /// to the class requested
2028 public sealed class ClassCast : TypeCast {
2029 readonly bool forced;
2031 public ClassCast (Expression child, TypeSpec return_type)
2032 : base (child, return_type)
2036 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2037 : base (child, return_type)
2039 this.forced = forced;
2042 public override void Emit (EmitContext ec)
2046 bool gen = TypeManager.IsGenericParameter (child.Type);
2048 ec.Emit (OpCodes.Box, child.Type);
2050 if (type.IsGenericParameter) {
2051 ec.Emit (OpCodes.Unbox_Any, type);
2058 ec.Emit (OpCodes.Castclass, type);
2063 // Created during resolving pahse when an expression is wrapped or constantified
2064 // and original expression can be used later (e.g. for expression trees)
2066 public class ReducedExpression : Expression
2068 public sealed class ReducedConstantExpression : EmptyConstantCast
2070 readonly Expression orig_expr;
2072 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2073 : base (expr, expr.Type)
2075 this.orig_expr = orig_expr;
2078 public Expression OriginalExpression {
2084 public override Constant ConvertImplicitly (TypeSpec target_type)
2086 Constant c = base.ConvertImplicitly (target_type);
2088 c = new ReducedConstantExpression (c, orig_expr);
2093 public override Expression CreateExpressionTree (ResolveContext ec)
2095 return orig_expr.CreateExpressionTree (ec);
2098 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2100 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2102 c = new ReducedConstantExpression (c, orig_expr);
2106 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2109 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2111 if (orig_expr is Conditional)
2112 child.EncodeAttributeValue (rc, enc, targetType);
2114 base.EncodeAttributeValue (rc, enc, targetType);
2118 sealed class ReducedExpressionStatement : ExpressionStatement
2120 readonly Expression orig_expr;
2121 readonly ExpressionStatement stm;
2123 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2125 this.orig_expr = orig;
2127 this.eclass = stm.eclass;
2128 this.type = stm.Type;
2130 this.loc = orig.Location;
2133 public override bool ContainsEmitWithAwait ()
2135 return stm.ContainsEmitWithAwait ();
2138 public override Expression CreateExpressionTree (ResolveContext ec)
2140 return orig_expr.CreateExpressionTree (ec);
2143 protected override Expression DoResolve (ResolveContext ec)
2148 public override void Emit (EmitContext ec)
2153 public override void EmitStatement (EmitContext ec)
2155 stm.EmitStatement (ec);
2158 public override void FlowAnalysis (FlowAnalysisContext fc)
2160 stm.FlowAnalysis (fc);
2164 readonly Expression expr, orig_expr;
2166 private ReducedExpression (Expression expr, Expression orig_expr)
2169 this.eclass = expr.eclass;
2170 this.type = expr.Type;
2171 this.orig_expr = orig_expr;
2172 this.loc = orig_expr.Location;
2177 public override bool IsSideEffectFree {
2179 return expr.IsSideEffectFree;
2183 public Expression OriginalExpression {
2191 public override bool ContainsEmitWithAwait ()
2193 return expr.ContainsEmitWithAwait ();
2197 // Creates fully resolved expression switcher
2199 public static Constant Create (Constant expr, Expression original_expr)
2201 if (expr.eclass == ExprClass.Unresolved)
2202 throw new ArgumentException ("Unresolved expression");
2204 return new ReducedConstantExpression (expr, original_expr);
2207 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2209 return new ReducedExpressionStatement (s, orig);
2212 public static Expression Create (Expression expr, Expression original_expr)
2214 return Create (expr, original_expr, true);
2218 // Creates unresolved reduce expression. The original expression has to be
2219 // already resolved. Created expression is constant based based on `expr'
2220 // value unless canBeConstant is used
2222 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2224 if (canBeConstant) {
2225 Constant c = expr as Constant;
2227 return Create (c, original_expr);
2230 ExpressionStatement s = expr as ExpressionStatement;
2232 return Create (s, original_expr);
2234 if (expr.eclass == ExprClass.Unresolved)
2235 throw new ArgumentException ("Unresolved expression");
2237 return new ReducedExpression (expr, original_expr);
2240 public override Expression CreateExpressionTree (ResolveContext ec)
2242 return orig_expr.CreateExpressionTree (ec);
2245 protected override Expression DoResolve (ResolveContext ec)
2250 public override void Emit (EmitContext ec)
2255 public override Expression EmitToField (EmitContext ec)
2257 return expr.EmitToField(ec);
2260 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2262 expr.EmitBranchable (ec, target, on_true);
2265 public override void FlowAnalysis (FlowAnalysisContext fc)
2267 expr.FlowAnalysis (fc);
2270 public override SLE.Expression MakeExpression (BuilderContext ctx)
2272 return orig_expr.MakeExpression (ctx);
2277 // Standard composite pattern
2279 public abstract class CompositeExpression : Expression
2281 protected Expression expr;
2283 protected CompositeExpression (Expression expr)
2286 this.loc = expr.Location;
2289 public override bool ContainsEmitWithAwait ()
2291 return expr.ContainsEmitWithAwait ();
2294 public override Expression CreateExpressionTree (ResolveContext rc)
2296 return expr.CreateExpressionTree (rc);
2299 public Expression Child {
2300 get { return expr; }
2303 protected override Expression DoResolve (ResolveContext rc)
2305 expr = expr.Resolve (rc);
2308 eclass = expr.eclass;
2314 public override void Emit (EmitContext ec)
2319 public override bool IsNull {
2320 get { return expr.IsNull; }
2325 // Base of expressions used only to narrow resolve flow
2327 public abstract class ShimExpression : Expression
2329 protected Expression expr;
2331 protected ShimExpression (Expression expr)
2336 public Expression Expr {
2342 protected override void CloneTo (CloneContext clonectx, Expression t)
2347 ShimExpression target = (ShimExpression) t;
2348 target.expr = expr.Clone (clonectx);
2351 public override bool ContainsEmitWithAwait ()
2353 return expr.ContainsEmitWithAwait ();
2356 public override Expression CreateExpressionTree (ResolveContext ec)
2358 throw new NotSupportedException ("ET");
2361 public override void Emit (EmitContext ec)
2363 throw new InternalErrorException ("Missing Resolve call");
2367 public class UnreachableExpression : Expression
2369 public UnreachableExpression (Expression expr)
2371 this.loc = expr.Location;
2374 public override Expression CreateExpressionTree (ResolveContext ec)
2377 throw new NotImplementedException ();
2380 protected override Expression DoResolve (ResolveContext rc)
2382 throw new NotSupportedException ();
2385 public override void FlowAnalysis (FlowAnalysisContext fc)
2387 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2390 public override void Emit (EmitContext ec)
2394 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2400 // Unresolved type name expressions
2402 public abstract class ATypeNameExpression : FullNamedExpression
2405 protected TypeArguments targs;
2407 protected ATypeNameExpression (string name, Location l)
2413 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2420 protected ATypeNameExpression (string name, int arity, Location l)
2421 : this (name, new UnboundTypeArguments (arity), l)
2427 protected int Arity {
2429 return targs == null ? 0 : targs.Count;
2433 public bool HasTypeArguments {
2435 return targs != null && !targs.IsEmpty;
2439 public string Name {
2448 public TypeArguments TypeArguments {
2456 public override bool Equals (object obj)
2458 ATypeNameExpression atne = obj as ATypeNameExpression;
2459 return atne != null && atne.Name == Name &&
2460 (targs == null || targs.Equals (atne.targs));
2463 public override int GetHashCode ()
2465 return Name.GetHashCode ();
2468 // TODO: Move it to MemberCore
2469 public static string GetMemberType (MemberCore mc)
2475 if (mc is FieldBase)
2477 if (mc is MethodCore)
2479 if (mc is EnumMember)
2487 public override string GetSignatureForError ()
2489 if (targs != null) {
2490 return Name + "<" + targs.GetSignatureForError () + ">";
2496 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2500 /// SimpleName expressions are formed of a single word and only happen at the beginning
2501 /// of a dotted-name.
2503 public class SimpleName : ATypeNameExpression
2505 public SimpleName (string name, Location l)
2510 public SimpleName (string name, TypeArguments args, Location l)
2511 : base (name, args, l)
2515 public SimpleName (string name, int arity, Location l)
2516 : base (name, arity, l)
2520 public SimpleName GetMethodGroup ()
2522 return new SimpleName (Name, targs, loc);
2525 protected override Expression DoResolve (ResolveContext rc)
2527 return SimpleNameResolve (rc, null);
2530 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2532 return SimpleNameResolve (ec, right_side);
2535 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2537 if (ctx.CurrentType != null) {
2538 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2539 if (member != null) {
2540 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2545 var report = ctx.Module.Compiler.Report;
2547 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2548 if (retval != null) {
2549 report.SymbolRelatedToPreviousError (retval.Type);
2550 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2554 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2555 if (retval != null) {
2556 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2560 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2561 if (ns_candidates != null) {
2562 if (ctx is UsingAliasNamespace.AliasContext) {
2563 report.Error (246, loc,
2564 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2565 ns_candidates[0], Name);
2567 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2568 report.Error (246, loc,
2569 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2573 report.Error (246, loc,
2574 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2579 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2581 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2584 if (fne.Type != null && Arity > 0) {
2585 if (HasTypeArguments) {
2586 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2587 if (ct.ResolveAsType (mc) == null)
2593 return new GenericOpenTypeExpr (fne.Type, loc);
2597 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2599 if (!(fne is Namespace))
2603 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2604 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2605 mc.Module.Compiler.Report.Error (1980, Location,
2606 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2607 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2610 fne = new DynamicTypeExpr (loc);
2611 fne.ResolveAsType (mc);
2617 Error_TypeOrNamespaceNotFound (mc);
2621 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2623 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2626 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2628 int lookup_arity = Arity;
2629 bool errorMode = false;
2631 Block current_block = rc.CurrentBlock;
2632 INamedBlockVariable variable = null;
2633 bool variable_found = false;
2637 // Stage 1: binding to local variables or parameters
2639 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2641 if (current_block != null && lookup_arity == 0) {
2642 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2643 if (!variable.IsDeclared) {
2644 // We found local name in accessible block but it's not
2645 // initialized yet, maybe the user wanted to bind to something else
2647 variable_found = true;
2649 e = variable.CreateReferenceExpression (rc, loc);
2652 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2661 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2663 TypeSpec member_type = rc.CurrentType;
2664 for (; member_type != null; member_type = member_type.DeclaringType) {
2665 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2669 var me = e as MemberExpr;
2671 // The name matches a type, defer to ResolveAsTypeStep
2679 if (variable != null) {
2680 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2681 rc.Report.Error (844, loc,
2682 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2683 Name, me.GetSignatureForError ());
2687 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2688 // Leave it to overload resolution to report correct error
2690 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2691 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2694 // LAMESPEC: again, ignores InvocableOnly
2695 if (variable != null) {
2696 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2697 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2701 // MemberLookup does not check accessors availability, this is actually needed for properties only
2703 var pe = me as PropertyExpr;
2706 // Break as there is no other overload available anyway
2707 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2708 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2711 pe.Getter = pe.PropertyInfo.Get;
2713 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2716 pe.Setter = pe.PropertyInfo.Set;
2721 // TODO: It's used by EventExpr -> FieldExpr transformation only
2722 // TODO: Should go to MemberAccess
2723 me = me.ResolveMemberAccess (rc, null, null);
2727 me.SetTypeArguments (rc, targs);
2734 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2736 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2737 if (IsPossibleTypeOrNamespace (rc)) {
2738 if (variable != null) {
2739 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2740 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2743 return ResolveAsTypeOrNamespace (rc);
2748 if (variable_found) {
2749 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2752 var tparams = rc.CurrentTypeParameters;
2753 if (tparams != null) {
2754 if (tparams.Find (Name) != null) {
2755 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2760 var ct = rc.CurrentType;
2762 if (ct.MemberDefinition.TypeParametersCount > 0) {
2763 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2764 if (ctp.Name == Name) {
2765 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2771 ct = ct.DeclaringType;
2772 } while (ct != null);
2775 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2776 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2778 rc.Report.SymbolRelatedToPreviousError (e.Type);
2779 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2783 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2785 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2786 return ErrorExpression.Instance;
2790 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2792 if (e.Type.Arity != Arity) {
2793 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2797 if (e is TypeExpr) {
2798 // TypeExpression does not have correct location
2799 if (e is TypeExpression)
2800 e = new TypeExpression (e.Type, loc);
2806 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2809 return ErrorExpression.Instance;
2812 if (rc.Module.Evaluator != null) {
2813 var fi = rc.Module.Evaluator.LookupField (Name);
2815 return new FieldExpr (fi.Item1, loc);
2823 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2825 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2830 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2831 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2835 if (right_side != null) {
2836 e = e.ResolveLValue (ec, right_side);
2844 public override object Accept (StructuralVisitor visitor)
2846 return visitor.Visit (this);
2851 /// Represents a namespace or a type. The name of the class was inspired by
2852 /// section 10.8.1 (Fully Qualified Names).
2854 public abstract class FullNamedExpression : Expression
2856 protected override void CloneTo (CloneContext clonectx, Expression target)
2858 // Do nothing, most unresolved type expressions cannot be
2859 // resolved to different type
2862 public override bool ContainsEmitWithAwait ()
2867 public override Expression CreateExpressionTree (ResolveContext ec)
2869 throw new NotSupportedException ("ET");
2872 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2875 // This is used to resolve the expression as a type, a null
2876 // value will be returned if the expression is not a type
2879 public override TypeSpec ResolveAsType (IMemberContext mc)
2881 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2886 TypeExpr te = fne as TypeExpr;
2888 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2896 var dep = type.GetMissingDependencies ();
2898 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2901 if (type.Kind == MemberKind.Void) {
2902 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2906 // Obsolete checks cannot be done when resolving base context as they
2907 // require type dependencies to be set but we are in process of resolving them
2909 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2910 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2911 if (obsolete_attr != null && !mc.IsObsolete) {
2912 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2920 public override void Emit (EmitContext ec)
2922 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2923 GetSignatureForError ());
2928 /// Expression that evaluates to a type
2930 public abstract class TypeExpr : FullNamedExpression
2932 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2938 protected sealed override Expression DoResolve (ResolveContext ec)
2944 public override bool Equals (object obj)
2946 TypeExpr tobj = obj as TypeExpr;
2950 return Type == tobj.Type;
2953 public override int GetHashCode ()
2955 return Type.GetHashCode ();
2960 /// Fully resolved Expression that already evaluated to a type
2962 public class TypeExpression : TypeExpr
2964 public TypeExpression (TypeSpec t, Location l)
2967 eclass = ExprClass.Type;
2971 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2978 /// This class denotes an expression which evaluates to a member
2979 /// of a struct or a class.
2981 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2984 // An instance expression associated with this member, if it's a
2985 // non-static member
2987 public Expression InstanceExpression;
2990 /// The name of this member.
2992 public abstract string Name {
2997 // When base.member is used
2999 public bool IsBase {
3000 get { return InstanceExpression is BaseThis; }
3004 /// Whether this is an instance member.
3006 public abstract bool IsInstance {
3011 /// Whether this is a static member.
3013 public abstract bool IsStatic {
3017 public abstract string KindName {
3021 protected abstract TypeSpec DeclaringType {
3025 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3027 return InstanceExpression.Type;
3032 // Converts best base candidate for virtual method starting from QueriedBaseType
3034 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3037 // Only when base.member is used and method is virtual
3043 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3044 // means for base.member access we have to find the closest match after we found best candidate
3046 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3048 // The method could already be what we are looking for
3050 TypeSpec[] targs = null;
3051 if (method.DeclaringType != InstanceExpression.Type) {
3053 // Candidate can have inflated MVAR parameters and we need to find
3054 // base match for original definition not inflated parameter types
3056 var parameters = method.Parameters;
3057 if (method.Arity > 0) {
3058 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3059 var inflated = method.DeclaringType as InflatedTypeSpec;
3060 if (inflated != null) {
3061 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3065 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3066 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3067 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3068 if (base_override.IsGeneric)
3069 targs = method.TypeArguments;
3071 method = base_override;
3076 // When base access is used inside anonymous method/iterator/etc we need to
3077 // get back to the context of original type. We do it by emiting proxy
3078 // method in original class and rewriting base call to this compiler
3079 // generated method call which does the actual base invocation. This may
3080 // introduce redundant storey but with `this' only but it's tricky to avoid
3081 // at this stage as we don't know what expressions follow base
3083 if (rc.CurrentAnonymousMethod != null) {
3084 if (targs == null && method.IsGeneric) {
3085 targs = method.TypeArguments;
3086 method = method.GetGenericMethodDefinition ();
3089 if (method.Parameters.HasArglist)
3090 throw new NotImplementedException ("__arglist base call proxy");
3092 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3094 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3095 // get/set member expressions second call would fail to proxy because left expression
3096 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3097 // FIXME: The async check is another hack but will probably fail with mutators
3098 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3099 InstanceExpression = new This (loc).Resolve (rc);
3103 method = method.MakeGenericMethod (rc, targs);
3107 // Only base will allow this invocation to happen.
3109 if (method.IsAbstract) {
3110 rc.Report.SymbolRelatedToPreviousError (method);
3111 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3117 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3119 if (InstanceExpression == null)
3122 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3123 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3124 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3129 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3131 if (InstanceExpression == null)
3134 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3137 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3139 var ct = rc.CurrentType;
3140 if (ct == qualifier)
3143 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3146 qualifier = qualifier.GetDefinition ();
3147 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3154 public override bool ContainsEmitWithAwait ()
3156 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3159 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3162 type = type.GetDefinition ();
3164 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3167 type = type.DeclaringType;
3168 } while (type != null);
3173 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3175 if (InstanceExpression != null) {
3176 InstanceExpression = InstanceExpression.Resolve (rc);
3177 CheckProtectedMemberAccess (rc, member);
3180 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3181 UnsafeError (rc, loc);
3184 var dep = member.GetMissingDependencies ();
3186 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3189 if (!rc.IsObsolete) {
3190 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3192 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3195 if (!(member is FieldSpec))
3196 member.MemberDefinition.SetIsUsed ();
3199 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3201 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3204 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3206 rc.Report.SymbolRelatedToPreviousError (member);
3207 rc.Report.Error (1540, loc,
3208 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3209 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3212 public override void FlowAnalysis (FlowAnalysisContext fc)
3214 if (InstanceExpression != null)
3215 InstanceExpression.FlowAnalysis (fc);
3218 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3220 if (!ResolveInstanceExpressionCore (rc, rhs))
3224 // Check intermediate value modification which won't have any effect
3226 if (rhs != null && InstanceExpression.Type.IsStruct) {
3227 var fexpr = InstanceExpression as FieldExpr;
3228 if (fexpr != null) {
3229 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3232 if (fexpr.IsStatic) {
3233 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3234 fexpr.GetSignatureForError ());
3236 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3237 fexpr.GetSignatureForError ());
3243 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3244 if (rc.CurrentInitializerVariable != null) {
3245 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3246 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3248 rc.Report.Error (1612, loc,
3249 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3250 InstanceExpression.GetSignatureForError ());
3256 var lvr = InstanceExpression as LocalVariableReference;
3259 if (!lvr.local_info.IsReadonly)
3262 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3263 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3270 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3273 if (InstanceExpression != null) {
3274 if (InstanceExpression is TypeExpr) {
3275 var t = InstanceExpression.Type;
3277 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3278 if (oa != null && !rc.IsObsolete) {
3279 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3282 t = t.DeclaringType;
3283 } while (t != null);
3285 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3286 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3287 rc.Report.Error (176, loc,
3288 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3289 GetSignatureForError ());
3293 InstanceExpression = null;
3299 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3300 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3301 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3302 rc.Report.Error (236, loc,
3303 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3304 GetSignatureForError ());
3306 rc.Report.Error (120, loc,
3307 "An object reference is required to access non-static member `{0}'",
3308 GetSignatureForError ());
3310 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3314 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3315 rc.Report.Error (38, loc,
3316 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3317 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3320 InstanceExpression = new This (loc).Resolve (rc);
3324 var me = InstanceExpression as MemberExpr;
3326 me.ResolveInstanceExpressionCore (rc, rhs);
3328 var fe = me as FieldExpr;
3329 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3330 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3331 rc.Report.Warning (1690, 1, loc,
3332 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3333 me.GetSignatureForError ());
3340 // Additional checks for l-value member access
3343 if (InstanceExpression is UnboxCast) {
3344 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3351 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3353 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3354 ec.Report.Warning (1720, 1, left.Location,
3355 "Expression will always cause a `{0}'", "System.NullReferenceException");
3358 InstanceExpression = left;
3362 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3364 TypeSpec instance_type = InstanceExpression.Type;
3365 if (TypeSpec.IsValueType (instance_type)) {
3366 if (InstanceExpression is IMemoryLocation) {
3367 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3369 // Cannot release the temporary variable when its address
3370 // is required to be on stack for any parent
3371 LocalTemporary t = new LocalTemporary (instance_type);
3372 InstanceExpression.Emit (ec);
3374 t.AddressOf (ec, AddressOp.Store);
3377 InstanceExpression.Emit (ec);
3379 // Only to make verifier happy
3380 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3381 ec.Emit (OpCodes.Box, instance_type);
3384 if (prepare_for_load)
3385 ec.Emit (OpCodes.Dup);
3388 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3391 public class ExtensionMethodCandidates
3393 readonly NamespaceContainer container;
3394 readonly IList<MethodSpec> methods;
3396 readonly IMemberContext context;
3398 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3400 this.context = context;
3401 this.methods = methods;
3402 this.container = nsContainer;
3403 this.index = lookupIndex;
3406 public NamespaceContainer Container {
3412 public IMemberContext Context {
3418 public int LookupIndex {
3424 public IList<MethodSpec> Methods {
3432 // Represents a group of extension method candidates for whole namespace
3434 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3436 ExtensionMethodCandidates candidates;
3437 public Expression ExtensionExpression;
3439 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3440 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3442 this.candidates = candidates;
3443 this.ExtensionExpression = extensionExpr;
3446 public override bool IsStatic {
3447 get { return true; }
3451 // For extension methodgroup we are not looking for base members but parent
3452 // namespace extension methods
3454 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3456 // TODO: candidates are null only when doing error reporting, that's
3457 // incorrect. We have to discover same extension methods in error mode
3458 if (candidates == null)
3461 int arity = type_arguments == null ? 0 : type_arguments.Count;
3463 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3464 if (candidates == null)
3467 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3470 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3472 // We are already here
3476 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3478 if (arguments == null)
3479 arguments = new Arguments (1);
3481 ExtensionExpression = ExtensionExpression.Resolve (ec);
3482 if (ExtensionExpression == null)
3485 var cand = candidates;
3486 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3487 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3489 // Restore candidates in case we are running in probing mode
3492 // Store resolved argument and restore original arguments
3494 // Clean-up modified arguments for error reporting
3495 arguments.RemoveAt (0);
3499 var me = ExtensionExpression as MemberExpr;
3501 me.ResolveInstanceExpression (ec, null);
3502 var fe = me as FieldExpr;
3504 fe.Spec.MemberDefinition.SetIsUsed ();
3507 InstanceExpression = null;
3511 #region IErrorHandler Members
3513 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3518 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3520 rc.Report.SymbolRelatedToPreviousError (best);
3521 rc.Report.Error (1928, loc,
3522 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3523 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3526 rc.Report.Error (1929, loc,
3527 "Extension method instance type `{0}' cannot be converted to `{1}'",
3528 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3534 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3539 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3548 /// MethodGroupExpr represents a group of method candidates which
3549 /// can be resolved to the best method overload
3551 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3553 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3555 protected IList<MemberSpec> Methods;
3556 MethodSpec best_candidate;
3557 TypeSpec best_candidate_return;
3558 protected TypeArguments type_arguments;
3560 SimpleName simple_name;
3561 protected TypeSpec queried_type;
3563 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3567 this.type = InternalType.MethodGroup;
3569 eclass = ExprClass.MethodGroup;
3570 queried_type = type;
3573 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3574 : this (new MemberSpec[] { m }, type, loc)
3580 public MethodSpec BestCandidate {
3582 return best_candidate;
3586 public TypeSpec BestCandidateReturnType {
3588 return best_candidate_return;
3592 public IList<MemberSpec> Candidates {
3598 protected override TypeSpec DeclaringType {
3600 return queried_type;
3604 public bool IsConditionallyExcluded {
3606 return Methods == Excluded;
3610 public override bool IsInstance {
3612 if (best_candidate != null)
3613 return !best_candidate.IsStatic;
3619 public override bool IsSideEffectFree {
3621 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3625 public override bool IsStatic {
3627 if (best_candidate != null)
3628 return best_candidate.IsStatic;
3634 public override string KindName {
3635 get { return "method"; }
3638 public override string Name {
3640 if (best_candidate != null)
3641 return best_candidate.Name;
3644 return Methods.First ().Name;
3651 // When best candidate is already know this factory can be used
3652 // to avoid expensive overload resolution to be called
3654 // NOTE: InstanceExpression has to be set manually
3656 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3658 return new MethodGroupExpr (best, queriedType, loc) {
3659 best_candidate = best,
3660 best_candidate_return = best.ReturnType
3664 public override string GetSignatureForError ()
3666 if (best_candidate != null)
3667 return best_candidate.GetSignatureForError ();
3669 return Methods.First ().GetSignatureForError ();
3672 public override Expression CreateExpressionTree (ResolveContext ec)
3674 if (best_candidate == null) {
3675 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3679 if (IsConditionallyExcluded)
3680 ec.Report.Error (765, loc,
3681 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3683 return new TypeOfMethod (best_candidate, loc);
3686 protected override Expression DoResolve (ResolveContext ec)
3688 this.eclass = ExprClass.MethodGroup;
3690 if (InstanceExpression != null) {
3691 InstanceExpression = InstanceExpression.Resolve (ec);
3692 if (InstanceExpression == null)
3699 public override void Emit (EmitContext ec)
3701 throw new NotSupportedException ();
3704 public void EmitCall (EmitContext ec, Arguments arguments)
3706 var call = new CallEmitter ();
3707 call.InstanceExpression = InstanceExpression;
3708 call.Emit (ec, best_candidate, arguments, loc);
3711 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3713 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3714 Name, target.GetSignatureForError ());
3717 public static bool IsExtensionMethodArgument (Expression expr)
3720 // LAMESPEC: No details about which expressions are not allowed
3722 return !(expr is TypeExpr) && !(expr is BaseThis);
3726 /// Find the Applicable Function Members (7.4.2.1)
3728 /// me: Method Group expression with the members to select.
3729 /// it might contain constructors or methods (or anything
3730 /// that maps to a method).
3732 /// Arguments: ArrayList containing resolved Argument objects.
3734 /// loc: The location if we want an error to be reported, or a Null
3735 /// location for "probing" purposes.
3737 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3738 /// that is the best match of me on Arguments.
3741 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3743 // TODO: causes issues with probing mode, remove explicit Kind check
3744 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3747 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3748 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3749 r.BaseMembersProvider = this;
3750 r.InstanceQualifier = this;
3753 if (cerrors != null)
3754 r.CustomErrors = cerrors;
3756 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3757 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3758 if (best_candidate == null)
3759 return r.BestCandidateIsDynamic ? this : null;
3761 // Overload resolver had to create a new method group, all checks bellow have already been executed
3762 if (r.BestCandidateNewMethodGroup != null)
3763 return r.BestCandidateNewMethodGroup;
3765 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3766 if (InstanceExpression != null) {
3767 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3768 InstanceExpression = null;
3770 if (best_candidate.IsStatic && simple_name != null) {
3771 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3774 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3778 ResolveInstanceExpression (ec, null);
3781 var base_override = CandidateToBaseOverride (ec, best_candidate);
3782 if (base_override == best_candidate) {
3783 best_candidate_return = r.BestCandidateReturnType;
3785 best_candidate = base_override;
3786 best_candidate_return = best_candidate.ReturnType;
3789 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3790 ConstraintChecker cc = new ConstraintChecker (ec);
3791 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3795 // Additional check for possible imported base override method which
3796 // could not be done during IsOverrideMethodBaseTypeAccessible
3798 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3799 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3800 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3801 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3804 // Speed up the check by not doing it on disallowed targets
3805 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3811 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3813 var fe = left as FieldExpr;
3816 // Using method-group on struct fields makes the struct assigned. I am not sure
3817 // why but that's what .net does
3819 fe.Spec.MemberDefinition.SetIsAssigned ();
3822 simple_name = original;
3823 return base.ResolveMemberAccess (ec, left, original);
3826 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3828 type_arguments = ta;
3831 #region IBaseMembersProvider Members
3833 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3835 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3838 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3840 if (queried_type == member.DeclaringType)
3843 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3844 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3848 // Extension methods lookup after ordinary methods candidates failed to apply
3850 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3852 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3855 if (!IsExtensionMethodArgument (InstanceExpression))
3858 int arity = type_arguments == null ? 0 : type_arguments.Count;
3859 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3860 if (methods == null)
3863 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3864 emg.SetTypeArguments (rc, type_arguments);
3871 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3873 public ConstructorInstanceQualifier (TypeSpec type)
3876 InstanceType = type;
3879 public TypeSpec InstanceType { get; private set; }
3881 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3883 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3887 public struct OverloadResolver
3890 public enum Restrictions
3894 ProbingOnly = 1 << 1,
3895 CovariantDelegate = 1 << 2,
3896 NoBaseMembers = 1 << 3,
3897 BaseMembersIncluded = 1 << 4
3900 public interface IBaseMembersProvider
3902 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3903 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3904 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3907 public interface IErrorHandler
3909 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3910 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3911 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3912 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3915 public interface IInstanceQualifier
3917 TypeSpec InstanceType { get; }
3918 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3921 sealed class NoBaseMembers : IBaseMembersProvider
3923 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3925 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3930 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3935 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3941 struct AmbiguousCandidate
3943 public readonly MemberSpec Member;
3944 public readonly bool Expanded;
3945 public readonly AParametersCollection Parameters;
3947 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3950 Parameters = parameters;
3951 Expanded = expanded;
3956 IList<MemberSpec> members;
3957 TypeArguments type_arguments;
3958 IBaseMembersProvider base_provider;
3959 IErrorHandler custom_errors;
3960 IInstanceQualifier instance_qualifier;
3961 Restrictions restrictions;
3962 MethodGroupExpr best_candidate_extension_group;
3963 TypeSpec best_candidate_return_type;
3965 SessionReportPrinter lambda_conv_msgs;
3967 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3968 : this (members, null, restrictions, loc)
3972 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3975 if (members == null || members.Count == 0)
3976 throw new ArgumentException ("empty members set");
3978 this.members = members;
3980 type_arguments = targs;
3981 this.restrictions = restrictions;
3982 if (IsDelegateInvoke)
3983 this.restrictions |= Restrictions.NoBaseMembers;
3985 base_provider = NoBaseMembers.Instance;
3990 public IBaseMembersProvider BaseMembersProvider {
3992 return base_provider;
3995 base_provider = value;
3999 public bool BestCandidateIsDynamic { get; set; }
4002 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4004 public MethodGroupExpr BestCandidateNewMethodGroup {
4006 return best_candidate_extension_group;
4011 // Return type can be different between best candidate and closest override
4013 public TypeSpec BestCandidateReturnType {
4015 return best_candidate_return_type;
4019 public IErrorHandler CustomErrors {
4021 return custom_errors;
4024 custom_errors = value;
4028 TypeSpec DelegateType {
4030 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4031 throw new InternalErrorException ("Not running in delegate mode", loc);
4033 return members [0].DeclaringType;
4037 public IInstanceQualifier InstanceQualifier {
4039 return instance_qualifier;
4042 instance_qualifier = value;
4046 bool IsProbingOnly {
4048 return (restrictions & Restrictions.ProbingOnly) != 0;
4052 bool IsDelegateInvoke {
4054 return (restrictions & Restrictions.DelegateInvoke) != 0;
4061 // 7.4.3.3 Better conversion from expression
4062 // Returns : 1 if a->p is better,
4063 // 2 if a->q is better,
4064 // 0 if neither is better
4066 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4068 TypeSpec argument_type = a.Type;
4071 // If argument is an anonymous function
4073 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4075 // p and q are delegate types or expression tree types
4077 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4078 if (q.MemberDefinition != p.MemberDefinition) {
4083 // Uwrap delegate from Expression<T>
4085 q = TypeManager.GetTypeArguments (q)[0];
4086 p = TypeManager.GetTypeArguments (p)[0];
4089 var p_m = Delegate.GetInvokeMethod (p);
4090 var q_m = Delegate.GetInvokeMethod (q);
4093 // With identical parameter lists
4095 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4104 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4106 if (p.Kind == MemberKind.Void) {
4107 return q.Kind != MemberKind.Void ? 2 : 0;
4111 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4113 if (q.Kind == MemberKind.Void) {
4114 return p.Kind != MemberKind.Void ? 1: 0;
4117 var am = (AnonymousMethodExpression) a.Expr;
4120 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4121 // better conversion is performed between underlying types Y1 and Y2
4123 if (p.IsGenericTask || q.IsGenericTask) {
4124 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4125 q = q.TypeArguments[0];
4126 p = p.TypeArguments[0];
4128 } else if (q != p) {
4130 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4132 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4133 var am_rt = am.InferReturnType (ec, null, orig_q);
4134 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4136 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4137 var am_rt = am.InferReturnType (ec, null, orig_p);
4138 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4144 // The parameters are identicial and return type is not void, use better type conversion
4145 // on return type to determine better one
4148 if (argument_type == p)
4151 if (argument_type == q)
4155 return BetterTypeConversion (ec, p, q);
4159 // 7.4.3.4 Better conversion from type
4161 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4163 if (p == null || q == null)
4164 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4166 switch (p.BuiltinType) {
4167 case BuiltinTypeSpec.Type.Int:
4168 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4171 case BuiltinTypeSpec.Type.Long:
4172 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4175 case BuiltinTypeSpec.Type.SByte:
4176 switch (q.BuiltinType) {
4177 case BuiltinTypeSpec.Type.Byte:
4178 case BuiltinTypeSpec.Type.UShort:
4179 case BuiltinTypeSpec.Type.UInt:
4180 case BuiltinTypeSpec.Type.ULong:
4184 case BuiltinTypeSpec.Type.Short:
4185 switch (q.BuiltinType) {
4186 case BuiltinTypeSpec.Type.UShort:
4187 case BuiltinTypeSpec.Type.UInt:
4188 case BuiltinTypeSpec.Type.ULong:
4192 case BuiltinTypeSpec.Type.Dynamic:
4193 // Dynamic is never better
4197 switch (q.BuiltinType) {
4198 case BuiltinTypeSpec.Type.Int:
4199 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4202 case BuiltinTypeSpec.Type.Long:
4203 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4206 case BuiltinTypeSpec.Type.SByte:
4207 switch (p.BuiltinType) {
4208 case BuiltinTypeSpec.Type.Byte:
4209 case BuiltinTypeSpec.Type.UShort:
4210 case BuiltinTypeSpec.Type.UInt:
4211 case BuiltinTypeSpec.Type.ULong:
4215 case BuiltinTypeSpec.Type.Short:
4216 switch (p.BuiltinType) {
4217 case BuiltinTypeSpec.Type.UShort:
4218 case BuiltinTypeSpec.Type.UInt:
4219 case BuiltinTypeSpec.Type.ULong:
4223 case BuiltinTypeSpec.Type.Dynamic:
4224 // Dynamic is never better
4228 // FIXME: handle lifted operators
4230 // TODO: this is expensive
4231 Expression p_tmp = new EmptyExpression (p);
4232 Expression q_tmp = new EmptyExpression (q);
4234 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4235 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4237 if (p_to_q && !q_to_p)
4240 if (q_to_p && !p_to_q)
4247 /// Determines "Better function" between candidate
4248 /// and the current best match
4251 /// Returns a boolean indicating :
4252 /// false if candidate ain't better
4253 /// true if candidate is better than the current best match
4255 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4256 MemberSpec best, AParametersCollection bparam, bool best_params)
4258 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4259 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4261 bool better_at_least_one = false;
4263 int args_count = args == null ? 0 : args.Count;
4267 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4270 // Default arguments are ignored for better decision
4271 if (a.IsDefaultArgument)
4275 // When comparing named argument the parameter type index has to be looked up
4276 // in original parameter set (override version for virtual members)
4278 NamedArgument na = a as NamedArgument;
4280 int idx = cparam.GetParameterIndexByName (na.Name);
4281 ct = candidate_pd.Types[idx];
4282 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4283 ct = TypeManager.GetElementType (ct);
4285 idx = bparam.GetParameterIndexByName (na.Name);
4286 bt = best_pd.Types[idx];
4287 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4288 bt = TypeManager.GetElementType (bt);
4290 ct = candidate_pd.Types[c_idx];
4291 bt = best_pd.Types[b_idx];
4293 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4294 ct = TypeManager.GetElementType (ct);
4298 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4299 bt = TypeManager.GetElementType (bt);
4304 if (TypeSpecComparer.IsEqual (ct, bt))
4308 int result = BetterExpressionConversion (ec, a, ct, bt);
4310 // for each argument, the conversion to 'ct' should be no worse than
4311 // the conversion to 'bt'.
4315 // for at least one argument, the conversion to 'ct' should be better than
4316 // the conversion to 'bt'.
4318 better_at_least_one = true;
4321 if (better_at_least_one)
4325 // This handles the case
4327 // Add (float f1, float f2, float f3);
4328 // Add (params decimal [] foo);
4330 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4331 // first candidate would've chosen as better.
4333 if (!same && !a.IsDefaultArgument)
4337 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4341 // This handles the following cases:
4343 // Foo (int i) is better than Foo (int i, long l = 0)
4344 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4345 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4347 // Prefer non-optional version
4349 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4351 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4352 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4355 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4358 return candidate_pd.Count >= best_pd.Count;
4362 // One is a non-generic method and second is a generic method, then non-generic is better
4364 if (best.IsGeneric != candidate.IsGeneric)
4365 return best.IsGeneric;
4368 // This handles the following cases:
4370 // Trim () is better than Trim (params char[] chars)
4371 // Concat (string s1, string s2, string s3) is better than
4372 // Concat (string s1, params string [] srest)
4373 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4375 // Prefer non-expanded version
4377 if (candidate_params != best_params)
4380 int candidate_param_count = candidate_pd.Count;
4381 int best_param_count = best_pd.Count;
4383 if (candidate_param_count != best_param_count)
4384 // can only happen if (candidate_params && best_params)
4385 return candidate_param_count > best_param_count && best_pd.HasParams;
4388 // Both methods have the same number of parameters, and the parameters have equal types
4389 // Pick the "more specific" signature using rules over original (non-inflated) types
4391 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4392 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4394 bool specific_at_least_once = false;
4395 for (j = 0; j < args_count; ++j) {
4396 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4398 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4399 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4401 ct = candidate_def_pd.Types[j];
4402 bt = best_def_pd.Types[j];
4407 TypeSpec specific = MoreSpecific (ct, bt);
4411 specific_at_least_once = true;
4414 if (specific_at_least_once)
4420 static bool CheckInflatedArguments (MethodSpec ms)
4422 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4425 // Setup constraint checker for probing only
4426 ConstraintChecker cc = new ConstraintChecker (null);
4428 var mp = ms.Parameters.Types;
4429 for (int i = 0; i < mp.Length; ++i) {
4430 var type = mp[i] as InflatedTypeSpec;
4434 var targs = type.TypeArguments;
4435 if (targs.Length == 0)
4438 // TODO: Checking inflated MVAR arguments should be enough
4439 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4446 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4448 rc.Report.Error (1729, loc,
4449 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4450 type.GetSignatureForError (), argCount.ToString ());
4454 // Determines if the candidate method is applicable to the given set of arguments
4455 // There could be two different set of parameters for same candidate where one
4456 // is the closest override for default values and named arguments checks and second
4457 // one being the virtual base for the parameter types and modifiers.
4459 // A return value rates candidate method compatibility,
4460 // 0 = the best, int.MaxValue = the worst
4463 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)
4465 // Parameters of most-derived type used mainly for named and optional parameters
4466 var pd = pm.Parameters;
4468 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4469 // params modifier instead of most-derived type
4470 var cpd = ((IParametersMember) candidate).Parameters;
4471 int param_count = pd.Count;
4472 int optional_count = 0;
4474 Arguments orig_args = arguments;
4476 if (arg_count != param_count) {
4478 // No arguments expansion when doing exact match for delegates
4480 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4481 for (int i = 0; i < pd.Count; ++i) {
4482 if (pd.FixedParameters[i].HasDefaultValue) {
4483 optional_count = pd.Count - i;
4489 if (optional_count != 0) {
4490 // Readjust expected number when params used
4491 if (cpd.HasParams) {
4493 if (arg_count < param_count)
4495 } else if (arg_count > param_count) {
4496 int args_gap = System.Math.Abs (arg_count - param_count);
4497 return int.MaxValue - 10000 + args_gap;
4498 } else if (arg_count < param_count - optional_count) {
4499 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4500 return int.MaxValue - 10000 + args_gap;
4502 } else if (arg_count != param_count) {
4503 int args_gap = System.Math.Abs (arg_count - param_count);
4505 return int.MaxValue - 10000 + args_gap;
4506 if (arg_count < param_count - 1)
4507 return int.MaxValue - 10000 + args_gap;
4510 // Resize to fit optional arguments
4511 if (optional_count != 0) {
4512 if (arguments == null) {
4513 arguments = new Arguments (optional_count);
4515 // Have to create a new container, so the next run can do same
4516 var resized = new Arguments (param_count);
4517 resized.AddRange (arguments);
4518 arguments = resized;
4521 for (int i = arg_count; i < param_count; ++i)
4522 arguments.Add (null);
4526 if (arg_count > 0) {
4528 // Shuffle named arguments to the right positions if there are any
4530 if (arguments[arg_count - 1] is NamedArgument) {
4531 arg_count = arguments.Count;
4533 for (int i = 0; i < arg_count; ++i) {
4534 bool arg_moved = false;
4536 NamedArgument na = arguments[i] as NamedArgument;
4540 int index = pd.GetParameterIndexByName (na.Name);
4542 // Named parameter not found
4546 // already reordered
4551 if (index >= param_count) {
4552 // When using parameters which should not be available to the user
4553 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4556 arguments.Add (null);
4560 temp = arguments[index];
4562 // The slot has been taken by positional argument
4563 if (temp != null && !(temp is NamedArgument))
4568 arguments = arguments.MarkOrderedArgument (na);
4572 if (arguments == orig_args) {
4573 arguments = new Arguments (orig_args.Count);
4574 arguments.AddRange (orig_args);
4577 arguments[index] = arguments[i];
4578 arguments[i] = temp;
4585 arg_count = arguments.Count;
4587 } else if (arguments != null) {
4588 arg_count = arguments.Count;
4592 // Don't do any expensive checks when the candidate cannot succeed
4594 if (arg_count != param_count && !cpd.HasParams)
4595 return (param_count - arg_count) * 2 + 1;
4597 var dep = candidate.GetMissingDependencies ();
4599 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4604 // 1. Handle generic method using type arguments when specified or type inference
4607 var ms = candidate as MethodSpec;
4608 if (ms != null && ms.IsGeneric) {
4609 if (type_arguments != null) {
4610 var g_args_count = ms.Arity;
4611 if (g_args_count != type_arguments.Count)
4612 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4614 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4617 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4618 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4619 // candidate was found use the set to report more details about what was wrong with lambda body.
4620 // The general idea is to distinguish between code errors and errors caused by
4621 // trial-and-error type inference
4623 if (lambda_conv_msgs == null) {
4624 for (int i = 0; i < arg_count; i++) {
4625 Argument a = arguments[i];
4629 var am = a.Expr as AnonymousMethodExpression;
4631 if (lambda_conv_msgs == null)
4632 lambda_conv_msgs = new SessionReportPrinter ();
4634 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4639 var ti = new TypeInference (arguments);
4640 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4643 return ti.InferenceScore - 20000;
4646 // Clear any error messages when the result was success
4648 if (lambda_conv_msgs != null)
4649 lambda_conv_msgs.ClearSession ();
4651 if (i_args.Length != 0) {
4652 ms = ms.MakeGenericMethod (ec, i_args);
4657 // Type arguments constraints have to match for the method to be applicable
4659 if (!CheckInflatedArguments (ms)) {
4661 return int.MaxValue - 25000;
4665 // We have a generic return type and at same time the method is override which
4666 // means we have to also inflate override return type in case the candidate is
4667 // best candidate and override return type is different to base return type.
4669 // virtual Foo<T, object> with override Foo<T, dynamic>
4671 if (candidate != pm) {
4672 MethodSpec override_ms = (MethodSpec) pm;
4673 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4674 returnType = inflator.Inflate (returnType);
4676 returnType = ms.ReturnType;
4683 if (type_arguments != null)
4684 return int.MaxValue - 15000;
4690 // 2. Each argument has to be implicitly convertible to method parameter
4692 Parameter.Modifier p_mod = 0;
4695 for (int i = 0; i < arg_count; i++) {
4696 Argument a = arguments[i];
4698 var fp = pd.FixedParameters[i];
4699 if (!fp.HasDefaultValue) {
4700 arguments = orig_args;
4701 return arg_count * 2 + 2;
4705 // Get the default value expression, we can use the same expression
4706 // if the type matches
4708 Expression e = fp.DefaultValue;
4710 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4712 // Restore for possible error reporting
4713 for (int ii = i; ii < arg_count; ++ii)
4714 arguments.RemoveAt (i);
4716 return (arg_count - i) * 2 + 1;
4720 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4722 // LAMESPEC: Attributes can be mixed together with build-in priority
4724 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4725 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4726 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4727 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4728 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4729 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4733 arguments[i] = new Argument (e, Argument.AType.Default);
4737 if (p_mod != Parameter.Modifier.PARAMS) {
4738 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4740 } else if (!params_expanded_form) {
4741 params_expanded_form = true;
4742 pt = ((ElementTypeSpec) pt).Element;
4748 if (!params_expanded_form) {
4749 if (a.ArgType == Argument.AType.ExtensionType) {
4751 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4753 // LAMESPEC: or implicit type parameter conversion
4756 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4757 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4758 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4763 score = IsArgumentCompatible (ec, a, p_mod, pt);
4766 dynamicArgument = true;
4771 // It can be applicable in expanded form (when not doing exact match like for delegates)
4773 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4774 if (!params_expanded_form) {
4775 pt = ((ElementTypeSpec) pt).Element;
4779 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4782 params_expanded_form = true;
4783 dynamicArgument = true;
4784 } else if (score == 0 || arg_count > pd.Count) {
4785 params_expanded_form = true;
4790 if (params_expanded_form)
4792 return (arg_count - i) * 2 + score;
4797 // When params parameter has no argument it will be provided later if the method is the best candidate
4799 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4800 params_expanded_form = true;
4803 // Restore original arguments for dynamic binder to keep the intention of original source code
4805 if (dynamicArgument)
4806 arguments = orig_args;
4811 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4813 if (e is Constant && e.Type == ptype)
4817 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4819 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4820 e = new MemberAccess (new MemberAccess (new MemberAccess (
4821 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4822 } else if (e is Constant) {
4824 // Handles int to int? conversions, DefaultParameterValue check
4826 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4830 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4833 return e.Resolve (ec);
4837 // Tests argument compatibility with the parameter
4838 // The possible return values are
4840 // 1 - modifier mismatch
4841 // 2 - type mismatch
4842 // -1 - dynamic binding required
4844 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4847 // Types have to be identical when ref or out modifer
4848 // is used and argument is not of dynamic type
4850 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4851 if (argument.Type != parameter) {
4853 // Do full equality check after quick path
4855 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4857 // Using dynamic for ref/out parameter can still succeed at runtime
4859 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4866 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4868 // Using dynamic for ref/out parameter can still succeed at runtime
4870 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4877 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4881 // Use implicit conversion in all modes to return same candidates when the expression
4882 // is used as argument or delegate conversion
4884 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4885 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4892 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4894 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4896 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4899 var ac_p = p as ArrayContainer;
4901 var ac_q = q as ArrayContainer;
4905 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4906 if (specific == ac_p.Element)
4908 if (specific == ac_q.Element)
4910 } else if (p.IsGeneric && q.IsGeneric) {
4911 var pargs = TypeManager.GetTypeArguments (p);
4912 var qargs = TypeManager.GetTypeArguments (q);
4914 bool p_specific_at_least_once = false;
4915 bool q_specific_at_least_once = false;
4917 for (int i = 0; i < pargs.Length; i++) {
4918 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4919 if (specific == pargs[i])
4920 p_specific_at_least_once = true;
4921 if (specific == qargs[i])
4922 q_specific_at_least_once = true;
4925 if (p_specific_at_least_once && !q_specific_at_least_once)
4927 if (!p_specific_at_least_once && q_specific_at_least_once)
4935 // Find the best method from candidate list
4937 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4939 List<AmbiguousCandidate> ambiguous_candidates = null;
4941 MemberSpec best_candidate;
4942 Arguments best_candidate_args = null;
4943 bool best_candidate_params = false;
4944 bool best_candidate_dynamic = false;
4945 int best_candidate_rate;
4946 IParametersMember best_parameter_member = null;
4948 int args_count = args != null ? args.Count : 0;
4950 Arguments candidate_args = args;
4951 bool error_mode = false;
4952 MemberSpec invocable_member = null;
4955 best_candidate = null;
4956 best_candidate_rate = int.MaxValue;
4958 var type_members = members;
4960 for (int i = 0; i < type_members.Count; ++i) {
4961 var member = type_members[i];
4964 // Methods in a base class are not candidates if any method in a derived
4965 // class is applicable
4967 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4971 if (!member.IsAccessible (rc))
4974 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4977 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4978 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4983 IParametersMember pm = member as IParametersMember;
4986 // Will use it later to report ambiguity between best method and invocable member
4988 if (Invocation.IsMemberInvocable (member))
4989 invocable_member = member;
4995 // Overload resolution is looking for base member but using parameter names
4996 // and default values from the closest member. That means to do expensive lookup
4997 // for the closest override for virtual or abstract members
4999 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5000 var override_params = base_provider.GetOverrideMemberParameters (member);
5001 if (override_params != null)
5002 pm = override_params;
5006 // Check if the member candidate is applicable
5008 bool params_expanded_form = false;
5009 bool dynamic_argument = false;
5010 TypeSpec rt = pm.MemberType;
5011 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5013 if (lambda_conv_msgs != null)
5014 lambda_conv_msgs.EndSession ();
5017 // How does it score compare to others
5019 if (candidate_rate < best_candidate_rate) {
5021 // Fatal error (missing dependency), cannot continue
5022 if (candidate_rate < 0)
5025 best_candidate_rate = candidate_rate;
5026 best_candidate = member;
5027 best_candidate_args = candidate_args;
5028 best_candidate_params = params_expanded_form;
5029 best_candidate_dynamic = dynamic_argument;
5030 best_parameter_member = pm;
5031 best_candidate_return_type = rt;
5032 } else if (candidate_rate == 0) {
5034 // The member look is done per type for most operations but sometimes
5035 // it's not possible like for binary operators overload because they
5036 // are unioned between 2 sides
5038 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5039 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5044 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5046 // We pack all interface members into top level type which makes the overload resolution
5047 // more complicated for interfaces. We compensate it by removing methods with same
5048 // signature when building the cache hence this path should not really be hit often
5051 // interface IA { void Foo (int arg); }
5052 // interface IB : IA { void Foo (params int[] args); }
5054 // IB::Foo is the best overload when calling IB.Foo (1)
5057 if (ambiguous_candidates != null) {
5058 foreach (var amb_cand in ambiguous_candidates) {
5059 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5068 ambiguous_candidates = null;
5071 // Is the new candidate better
5072 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5076 best_candidate = member;
5077 best_candidate_args = candidate_args;
5078 best_candidate_params = params_expanded_form;
5079 best_candidate_dynamic = dynamic_argument;
5080 best_parameter_member = pm;
5081 best_candidate_return_type = rt;
5083 // It's not better but any other found later could be but we are not sure yet
5084 if (ambiguous_candidates == null)
5085 ambiguous_candidates = new List<AmbiguousCandidate> ();
5087 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5091 // Restore expanded arguments
5092 candidate_args = args;
5094 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5097 // We've found exact match
5099 if (best_candidate_rate == 0)
5103 // Try extension methods lookup when no ordinary method match was found and provider enables it
5106 var emg = base_provider.LookupExtensionMethod (rc);
5108 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5110 best_candidate_extension_group = emg;
5111 return (T) (MemberSpec) emg.BestCandidate;
5116 // Don't run expensive error reporting mode for probing
5123 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5126 lambda_conv_msgs = null;
5131 // No best member match found, report an error
5133 if (best_candidate_rate != 0 || error_mode) {
5134 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5138 if (best_candidate_dynamic) {
5139 if (args[0].ArgType == Argument.AType.ExtensionType) {
5140 rc.Report.Error (1973, loc,
5141 "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",
5142 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5146 // Check type constraints only when explicit type arguments are used
5148 if (best_candidate.IsGeneric && type_arguments != null) {
5149 MethodSpec bc = best_candidate as MethodSpec;
5150 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5151 ConstraintChecker cc = new ConstraintChecker (rc);
5152 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5156 BestCandidateIsDynamic = true;
5161 // These flags indicates we are running delegate probing conversion. No need to
5162 // do more expensive checks
5164 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5165 return (T) best_candidate;
5167 if (ambiguous_candidates != null) {
5169 // Now check that there are no ambiguities i.e the selected method
5170 // should be better than all the others
5172 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5173 var candidate = ambiguous_candidates [ix];
5175 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5176 var ambiguous = candidate.Member;
5177 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5178 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5179 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5180 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5181 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5184 return (T) best_candidate;
5189 if (invocable_member != null && !IsProbingOnly) {
5190 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5191 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5192 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5193 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5197 // And now check if the arguments are all
5198 // compatible, perform conversions if
5199 // necessary etc. and return if everything is
5202 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5205 if (best_candidate == null)
5209 // Don't run possibly expensive checks in probing mode
5211 if (!IsProbingOnly && !rc.IsInProbingMode) {
5213 // Check ObsoleteAttribute on the best method
5215 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5216 if (oa != null && !rc.IsObsolete)
5217 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5219 best_candidate.MemberDefinition.SetIsUsed ();
5222 args = best_candidate_args;
5223 return (T) best_candidate;
5226 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5228 return ResolveMember<MethodSpec> (rc, ref args);
5231 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5232 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5234 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5237 if (a.Type == InternalType.ErrorType)
5240 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5241 ec.Report.SymbolRelatedToPreviousError (method);
5242 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5243 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5244 TypeManager.CSharpSignature (method));
5247 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5248 TypeManager.CSharpSignature (method));
5249 } else if (IsDelegateInvoke) {
5250 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5251 DelegateType.GetSignatureForError ());
5253 ec.Report.SymbolRelatedToPreviousError (method);
5254 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5255 method.GetSignatureForError ());
5258 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5260 string index = (idx + 1).ToString ();
5261 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5262 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5263 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5264 index, Parameter.GetModifierSignature (a.Modifier));
5266 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5267 index, Parameter.GetModifierSignature (mod));
5269 string p1 = a.GetSignatureForError ();
5270 string p2 = paramType.GetSignatureForError ();
5273 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5274 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5277 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5278 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5279 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5282 ec.Report.Error (1503, a.Expr.Location,
5283 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5288 // We have failed to find exact match so we return error info about the closest match
5290 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5292 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5293 int arg_count = args == null ? 0 : args.Count;
5295 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5296 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5297 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5301 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5306 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5307 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5308 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5312 // For candidates which match on parameters count report more details about incorrect arguments
5315 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5316 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5317 // Reject any inaccessible member
5318 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5319 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5320 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5324 var ms = best_candidate as MethodSpec;
5325 if (ms != null && ms.IsGeneric) {
5326 bool constr_ok = true;
5327 if (ms.TypeArguments != null)
5328 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5330 if (ta_count == 0 && ms.TypeArguments == null) {
5331 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5335 rc.Report.Error (411, loc,
5336 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5337 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5344 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5350 // We failed to find any method with correct argument count, report best candidate
5352 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5355 if (best_candidate.Kind == MemberKind.Constructor) {
5356 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5357 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5358 } else if (IsDelegateInvoke) {
5359 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5360 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5361 DelegateType.GetSignatureForError (), arg_count.ToString ());
5363 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5364 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5365 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5366 name, arg_count.ToString ());
5370 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5372 var pd = pm.Parameters;
5373 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5375 Parameter.Modifier p_mod = 0;
5377 int a_idx = 0, a_pos = 0;
5379 ArrayInitializer params_initializers = null;
5380 bool has_unsafe_arg = pm.MemberType.IsPointer;
5381 int arg_count = args == null ? 0 : args.Count;
5383 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5388 if (p_mod != Parameter.Modifier.PARAMS) {
5389 p_mod = pd.FixedParameters[a_idx].ModFlags;
5391 has_unsafe_arg |= pt.IsPointer;
5393 if (p_mod == Parameter.Modifier.PARAMS) {
5394 if (chose_params_expanded) {
5395 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5396 pt = TypeManager.GetElementType (pt);
5402 // Types have to be identical when ref or out modifer is used
5404 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5405 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5408 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5414 NamedArgument na = a as NamedArgument;
5416 int name_index = pd.GetParameterIndexByName (na.Name);
5417 if (name_index < 0 || name_index >= pd.Count) {
5418 if (IsDelegateInvoke) {
5419 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5420 ec.Report.Error (1746, na.Location,
5421 "The delegate `{0}' does not contain a parameter named `{1}'",
5422 DelegateType.GetSignatureForError (), na.Name);
5424 ec.Report.SymbolRelatedToPreviousError (member);
5425 ec.Report.Error (1739, na.Location,
5426 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5427 TypeManager.CSharpSignature (member), na.Name);
5429 } else if (args[name_index] != a && args[name_index] != null) {
5430 if (IsDelegateInvoke)
5431 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5433 ec.Report.SymbolRelatedToPreviousError (member);
5435 ec.Report.Error (1744, na.Location,
5436 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5441 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5444 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5445 custom_errors.NoArgumentMatch (ec, member);
5450 if (a.ArgType == Argument.AType.ExtensionType) {
5451 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5454 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5456 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5459 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5466 // Convert params arguments to an array initializer
5468 if (params_initializers != null) {
5469 // we choose to use 'a.Expr' rather than 'conv' so that
5470 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5471 params_initializers.Add (a.Expr);
5472 args.RemoveAt (a_idx--);
5478 // Update the argument with the implicit conversion
5482 if (a_idx != arg_count) {
5483 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5488 // Fill not provided arguments required by params modifier
5490 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5492 args = new Arguments (1);
5494 pt = ptypes[pd.Count - 1];
5495 pt = TypeManager.GetElementType (pt);
5496 has_unsafe_arg |= pt.IsPointer;
5497 params_initializers = new ArrayInitializer (0, loc);
5501 // Append an array argument with all params arguments
5503 if (params_initializers != null) {
5504 args.Add (new Argument (
5505 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5509 if (has_unsafe_arg && !ec.IsUnsafe) {
5510 Expression.UnsafeError (ec, loc);
5514 // We could infer inaccesible type arguments
5516 if (type_arguments == null && member.IsGeneric) {
5517 var ms = (MethodSpec) member;
5518 foreach (var ta in ms.TypeArguments) {
5519 if (!ta.IsAccessible (ec)) {
5520 ec.Report.SymbolRelatedToPreviousError (ta);
5521 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5531 public class ConstantExpr : MemberExpr
5533 readonly ConstSpec constant;
5535 public ConstantExpr (ConstSpec constant, Location loc)
5537 this.constant = constant;
5541 public override string Name {
5542 get { throw new NotImplementedException (); }
5545 public override string KindName {
5546 get { return "constant"; }
5549 public override bool IsInstance {
5550 get { return !IsStatic; }
5553 public override bool IsStatic {
5554 get { return true; }
5557 protected override TypeSpec DeclaringType {
5558 get { return constant.DeclaringType; }
5561 public override Expression CreateExpressionTree (ResolveContext ec)
5563 throw new NotSupportedException ("ET");
5566 protected override Expression DoResolve (ResolveContext rc)
5568 ResolveInstanceExpression (rc, null);
5569 DoBestMemberChecks (rc, constant);
5571 var c = constant.GetConstant (rc);
5573 // Creates reference expression to the constant value
5574 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5577 public override void Emit (EmitContext ec)
5579 throw new NotSupportedException ();
5582 public override string GetSignatureForError ()
5584 return constant.GetSignatureForError ();
5587 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5589 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5594 // Fully resolved expression that references a Field
5596 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5598 protected FieldSpec spec;
5599 VariableInfo variable_info;
5601 LocalTemporary temp;
5604 protected FieldExpr (Location l)
5609 public FieldExpr (FieldSpec spec, Location loc)
5614 type = spec.MemberType;
5617 public FieldExpr (FieldBase fi, Location l)
5624 public override string Name {
5630 public bool IsHoisted {
5632 IVariableReference hv = InstanceExpression as IVariableReference;
5633 return hv != null && hv.IsHoisted;
5637 public override bool IsInstance {
5639 return !spec.IsStatic;
5643 public override bool IsStatic {
5645 return spec.IsStatic;
5649 public override string KindName {
5650 get { return "field"; }
5653 public FieldSpec Spec {
5659 protected override TypeSpec DeclaringType {
5661 return spec.DeclaringType;
5665 public VariableInfo VariableInfo {
5667 return variable_info;
5673 public override string GetSignatureForError ()
5675 return spec.GetSignatureForError ();
5678 public bool IsMarshalByRefAccess (ResolveContext rc)
5680 // Checks possible ldflda of field access expression
5681 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5682 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5683 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5686 public void SetHasAddressTaken ()
5688 IVariableReference vr = InstanceExpression as IVariableReference;
5690 vr.SetHasAddressTaken ();
5694 public override Expression CreateExpressionTree (ResolveContext ec)
5696 return CreateExpressionTree (ec, true);
5699 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5702 Expression instance;
5704 if (InstanceExpression == null) {
5705 instance = new NullLiteral (loc);
5706 } else if (convertInstance) {
5707 instance = InstanceExpression.CreateExpressionTree (ec);
5709 args = new Arguments (1);
5710 args.Add (new Argument (InstanceExpression));
5711 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5714 args = Arguments.CreateForExpressionTree (ec, null,
5716 CreateTypeOfExpression ());
5718 return CreateExpressionFactoryCall (ec, "Field", args);
5721 public Expression CreateTypeOfExpression ()
5723 return new TypeOfField (spec, loc);
5726 protected override Expression DoResolve (ResolveContext ec)
5728 spec.MemberDefinition.SetIsUsed ();
5730 return DoResolve (ec, null);
5733 Expression DoResolve (ResolveContext ec, Expression rhs)
5735 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5738 if (ResolveInstanceExpression (ec, rhs)) {
5739 // Resolve the field's instance expression while flow analysis is turned
5740 // off: when accessing a field "a.b", we must check whether the field
5741 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5743 if (lvalue_instance) {
5744 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5746 Expression right_side =
5747 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5749 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5751 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5754 if (InstanceExpression == null)
5758 DoBestMemberChecks (ec, spec);
5761 var fb = spec as FixedFieldSpec;
5762 IVariableReference var = InstanceExpression as IVariableReference;
5765 IFixedExpression fe = InstanceExpression as IFixedExpression;
5766 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5767 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5770 if (InstanceExpression.eclass != ExprClass.Variable) {
5771 ec.Report.SymbolRelatedToPreviousError (spec);
5772 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5773 TypeManager.GetFullNameSignature (spec));
5774 } else if (var != null && var.IsHoisted) {
5775 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5778 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5782 // Set flow-analysis variable info for struct member access. It will be check later
5783 // for precise error reporting
5785 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5786 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5789 eclass = ExprClass.Variable;
5793 public void SetFieldAssigned (FlowAnalysisContext fc)
5798 bool lvalue_instance = spec.DeclaringType.IsStruct;
5799 if (lvalue_instance) {
5800 var var = InstanceExpression as IVariableReference;
5801 if (var != null && var.VariableInfo != null) {
5802 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5806 var fe = InstanceExpression as FieldExpr;
5807 if (fe != null || lvalue_instance) {
5812 while (fe.InstanceExpression is FieldExpr) {
5813 fe = (FieldExpr) fe.InstanceExpression;
5814 if (!fe.Spec.DeclaringType.IsStruct)
5817 if (fe.VariableInfo != null && fc.IsStructFieldDefinitelyAssigned (fe.VariableInfo, fe.Name)) {
5818 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5822 fe.InstanceExpression.FlowAnalysis (fc);
5825 InstanceExpression.FlowAnalysis (fc);
5830 public void VerifyAssignedStructField (FlowAnalysisContext fc)
5835 var var = fe.InstanceExpression as IVariableReference;
5837 var vi = var.VariableInfo;
5839 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, fe.Name) && !fe.type.IsStruct) {
5840 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5844 fe = fe.InstanceExpression as FieldExpr;
5846 } while (fe != null);
5849 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5851 // The return value is always null. Returning a value simplifies calling code.
5853 if (right_side == EmptyExpression.OutAccess) {
5855 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5856 GetSignatureForError ());
5858 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5859 GetSignatureForError ());
5865 if (right_side == EmptyExpression.LValueMemberAccess) {
5866 // Already reported as CS1648/CS1650
5870 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5872 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5873 GetSignatureForError ());
5875 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5876 GetSignatureForError ());
5882 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5883 GetSignatureForError ());
5885 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5886 GetSignatureForError ());
5892 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5894 if (spec is FixedFieldSpec) {
5895 // It could be much better error message but we want to be error compatible
5896 Error_ValueAssignment (ec, right_side);
5899 Expression e = DoResolve (ec, right_side);
5904 spec.MemberDefinition.SetIsAssigned ();
5906 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5907 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5908 ec.Report.Warning (420, 1, loc,
5909 "`{0}': A volatile field references will not be treated as volatile",
5910 spec.GetSignatureForError ());
5913 if (spec.IsReadOnly) {
5914 // InitOnly fields can only be assigned in constructors or initializers
5915 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5916 return Error_AssignToReadonly (ec, right_side);
5918 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5920 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5921 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5922 return Error_AssignToReadonly (ec, right_side);
5923 // static InitOnly fields cannot be assigned-to in an instance constructor
5924 if (IsStatic && !ec.IsStatic)
5925 return Error_AssignToReadonly (ec, right_side);
5926 // instance constructors can't modify InitOnly fields of other instances of the same type
5927 if (!IsStatic && !(InstanceExpression is This))
5928 return Error_AssignToReadonly (ec, right_side);
5932 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5933 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5934 ec.Report.Warning (197, 1, loc,
5935 "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",
5936 GetSignatureForError ());
5939 eclass = ExprClass.Variable;
5943 public override void FlowAnalysis (FlowAnalysisContext fc)
5945 var var = InstanceExpression as IVariableReference;
5947 var vi = var.VariableInfo;
5948 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
5949 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
5953 if (TypeSpec.IsValueType (InstanceExpression.Type))
5957 base.FlowAnalysis (fc);
5960 public override int GetHashCode ()
5962 return spec.GetHashCode ();
5965 public bool IsFixed {
5968 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5970 IVariableReference variable = InstanceExpression as IVariableReference;
5971 if (variable != null)
5972 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5974 IFixedExpression fe = InstanceExpression as IFixedExpression;
5975 return fe != null && fe.IsFixed;
5979 public override bool Equals (object obj)
5981 FieldExpr fe = obj as FieldExpr;
5985 if (spec != fe.spec)
5988 if (InstanceExpression == null || fe.InstanceExpression == null)
5991 return InstanceExpression.Equals (fe.InstanceExpression);
5994 public void Emit (EmitContext ec, bool leave_copy)
5996 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6000 ec.Emit (OpCodes.Volatile);
6002 ec.Emit (OpCodes.Ldsfld, spec);
6005 EmitInstance (ec, false);
6007 // Optimization for build-in types
6008 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6009 ec.EmitLoadFromPtr (type);
6011 var ff = spec as FixedFieldSpec;
6013 ec.Emit (OpCodes.Ldflda, spec);
6014 ec.Emit (OpCodes.Ldflda, ff.Element);
6017 ec.Emit (OpCodes.Volatile);
6019 ec.Emit (OpCodes.Ldfld, spec);
6025 ec.Emit (OpCodes.Dup);
6027 temp = new LocalTemporary (this.Type);
6033 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6035 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6036 if (isCompound && !(source is DynamicExpressionStatement)) {
6037 if (has_await_source) {
6039 InstanceExpression = InstanceExpression.EmitToField (ec);
6046 if (has_await_source)
6047 source = source.EmitToField (ec);
6049 EmitInstance (ec, prepared);
6055 ec.Emit (OpCodes.Dup);
6057 temp = new LocalTemporary (this.Type);
6062 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6063 ec.Emit (OpCodes.Volatile);
6065 spec.MemberDefinition.SetIsAssigned ();
6068 ec.Emit (OpCodes.Stsfld, spec);
6070 ec.Emit (OpCodes.Stfld, spec);
6080 // Emits store to field with prepared values on stack
6082 public void EmitAssignFromStack (EmitContext ec)
6085 ec.Emit (OpCodes.Stsfld, spec);
6087 ec.Emit (OpCodes.Stfld, spec);
6091 public override void Emit (EmitContext ec)
6096 public override void EmitSideEffect (EmitContext ec)
6098 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6100 if (is_volatile) // || is_marshal_by_ref ())
6101 base.EmitSideEffect (ec);
6104 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6106 if ((mode & AddressOp.Store) != 0)
6107 spec.MemberDefinition.SetIsAssigned ();
6108 if ((mode & AddressOp.Load) != 0)
6109 spec.MemberDefinition.SetIsUsed ();
6112 // Handle initonly fields specially: make a copy and then
6113 // get the address of the copy.
6116 if (spec.IsReadOnly){
6118 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6130 var temp = ec.GetTemporaryLocal (type);
6131 ec.Emit (OpCodes.Stloc, temp);
6132 ec.Emit (OpCodes.Ldloca, temp);
6133 ec.FreeTemporaryLocal (temp, type);
6139 ec.Emit (OpCodes.Ldsflda, spec);
6142 EmitInstance (ec, false);
6143 ec.Emit (OpCodes.Ldflda, spec);
6147 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6149 return MakeExpression (ctx);
6152 public override SLE.Expression MakeExpression (BuilderContext ctx)
6155 return base.MakeExpression (ctx);
6157 return SLE.Expression.Field (
6158 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6159 spec.GetMetaInfo ());
6163 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6165 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6171 // Expression that evaluates to a Property.
6173 // This is not an LValue because we need to re-write the expression. We
6174 // can not take data from the stack and store it.
6176 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6178 Arguments arguments;
6180 public PropertyExpr (PropertySpec spec, Location l)
6183 best_candidate = spec;
6184 type = spec.MemberType;
6189 protected override Arguments Arguments {
6198 protected override TypeSpec DeclaringType {
6200 return best_candidate.DeclaringType;
6204 public override string Name {
6206 return best_candidate.Name;
6210 public override bool IsInstance {
6216 public override bool IsStatic {
6218 return best_candidate.IsStatic;
6222 public override string KindName {
6223 get { return "property"; }
6226 public PropertySpec PropertyInfo {
6228 return best_candidate;
6234 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6236 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6239 var args_count = arguments == null ? 0 : arguments.Count;
6240 if (args_count != body.Parameters.Count && args_count == 0)
6243 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6244 mg.InstanceExpression = InstanceExpression;
6249 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6251 return new PropertyExpr (spec, loc) {
6257 public override Expression CreateExpressionTree (ResolveContext ec)
6260 if (IsSingleDimensionalArrayLength ()) {
6261 args = new Arguments (1);
6262 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6263 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6266 args = new Arguments (2);
6267 if (InstanceExpression == null)
6268 args.Add (new Argument (new NullLiteral (loc)));
6270 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6271 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6272 return CreateExpressionFactoryCall (ec, "Property", args);
6275 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6277 DoResolveLValue (rc, null);
6278 return new TypeOfMethod (Setter, loc);
6281 public override string GetSignatureForError ()
6283 return best_candidate.GetSignatureForError ();
6286 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6289 return base.MakeExpression (ctx);
6291 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6295 public override SLE.Expression MakeExpression (BuilderContext ctx)
6298 return base.MakeExpression (ctx);
6300 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6304 void Error_PropertyNotValid (ResolveContext ec)
6306 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6307 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6308 GetSignatureForError ());
6311 bool IsSingleDimensionalArrayLength ()
6313 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6316 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6317 return ac != null && ac.Rank == 1;
6320 public override void Emit (EmitContext ec, bool leave_copy)
6323 // Special case: length of single dimension array property is turned into ldlen
6325 if (IsSingleDimensionalArrayLength ()) {
6326 EmitInstance (ec, false);
6327 ec.Emit (OpCodes.Ldlen);
6328 ec.Emit (OpCodes.Conv_I4);
6332 base.Emit (ec, leave_copy);
6335 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6338 LocalTemporary await_source_arg = null;
6340 if (isCompound && !(source is DynamicExpressionStatement)) {
6341 emitting_compound_assignment = true;
6344 if (has_await_arguments) {
6345 await_source_arg = new LocalTemporary (Type);
6346 await_source_arg.Store (ec);
6348 args = new Arguments (1);
6349 args.Add (new Argument (await_source_arg));
6352 temp = await_source_arg;
6355 has_await_arguments = false;
6360 ec.Emit (OpCodes.Dup);
6361 temp = new LocalTemporary (this.Type);
6366 args = arguments ?? new Arguments (1);
6370 temp = new LocalTemporary (this.Type);
6372 args.Add (new Argument (temp));
6374 args.Add (new Argument (source));
6378 emitting_compound_assignment = false;
6380 var call = new CallEmitter ();
6381 call.InstanceExpression = InstanceExpression;
6383 call.InstanceExpressionOnStack = true;
6385 call.Emit (ec, Setter, args, loc);
6392 if (await_source_arg != null) {
6393 await_source_arg.Release (ec);
6397 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6399 eclass = ExprClass.PropertyAccess;
6401 if (best_candidate.IsNotCSharpCompatible) {
6402 Error_PropertyNotValid (rc);
6405 ResolveInstanceExpression (rc, right_side);
6407 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6408 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6409 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6411 type = p.MemberType;
6415 DoBestMemberChecks (rc, best_candidate);
6417 // Handling of com-imported properties with any number of default property parameters
6418 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6419 var p = best_candidate.Get.Parameters;
6420 arguments = new Arguments (p.Count);
6421 for (int i = 0; i < p.Count; ++i) {
6422 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6424 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6425 var p = best_candidate.Set.Parameters;
6426 arguments = new Arguments (p.Count - 1);
6427 for (int i = 0; i < p.Count - 1; ++i) {
6428 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6435 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6437 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6441 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6443 // getter and setter can be different for base calls
6444 MethodSpec getter, setter;
6445 protected T best_candidate;
6447 protected LocalTemporary temp;
6448 protected bool emitting_compound_assignment;
6449 protected bool has_await_arguments;
6451 protected PropertyOrIndexerExpr (Location l)
6458 protected abstract Arguments Arguments { get; set; }
6460 public MethodSpec Getter {
6469 public MethodSpec Setter {
6480 protected override Expression DoResolve (ResolveContext ec)
6482 if (eclass == ExprClass.Unresolved) {
6483 var expr = OverloadResolve (ec, null);
6488 return expr.Resolve (ec);
6491 if (!ResolveGetter (ec))
6497 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6499 if (right_side == EmptyExpression.OutAccess) {
6500 // TODO: best_candidate can be null at this point
6501 INamedBlockVariable variable = null;
6502 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6503 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6504 best_candidate.Name);
6506 right_side.DoResolveLValue (ec, this);
6511 if (eclass == ExprClass.Unresolved) {
6512 var expr = OverloadResolve (ec, right_side);
6517 return expr.ResolveLValue (ec, right_side);
6520 if (!ResolveSetter (ec))
6527 // Implements the IAssignMethod interface for assignments
6529 public virtual void Emit (EmitContext ec, bool leave_copy)
6531 var call = new CallEmitter ();
6532 call.InstanceExpression = InstanceExpression;
6533 if (has_await_arguments)
6534 call.HasAwaitArguments = true;
6536 call.DuplicateArguments = emitting_compound_assignment;
6538 call.Emit (ec, Getter, Arguments, loc);
6540 if (call.HasAwaitArguments) {
6541 InstanceExpression = call.InstanceExpression;
6542 Arguments = call.EmittedArguments;
6543 has_await_arguments = true;
6547 ec.Emit (OpCodes.Dup);
6548 temp = new LocalTemporary (Type);
6553 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6555 public override void Emit (EmitContext ec)
6560 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6562 has_await_arguments = true;
6567 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6569 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6571 bool ResolveGetter (ResolveContext rc)
6573 if (!best_candidate.HasGet) {
6574 if (InstanceExpression != EmptyExpression.Null) {
6575 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6576 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6577 best_candidate.GetSignatureForError ());
6580 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6581 if (best_candidate.HasDifferentAccessibility) {
6582 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6583 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6584 TypeManager.CSharpSignature (best_candidate));
6586 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6587 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6591 if (best_candidate.HasDifferentAccessibility) {
6592 CheckProtectedMemberAccess (rc, best_candidate.Get);
6595 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6599 bool ResolveSetter (ResolveContext rc)
6601 if (!best_candidate.HasSet) {
6602 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6603 GetSignatureForError ());
6607 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6608 if (best_candidate.HasDifferentAccessibility) {
6609 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6610 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6611 GetSignatureForError ());
6613 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6614 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6618 if (best_candidate.HasDifferentAccessibility)
6619 CheckProtectedMemberAccess (rc, best_candidate.Set);
6621 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6627 /// Fully resolved expression that evaluates to an Event
6629 public class EventExpr : MemberExpr, IAssignMethod
6631 readonly EventSpec spec;
6634 public EventExpr (EventSpec spec, Location loc)
6642 protected override TypeSpec DeclaringType {
6644 return spec.DeclaringType;
6648 public override string Name {
6654 public override bool IsInstance {
6656 return !spec.IsStatic;
6660 public override bool IsStatic {
6662 return spec.IsStatic;
6666 public override string KindName {
6667 get { return "event"; }
6670 public MethodSpec Operator {
6678 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6681 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6683 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6684 if (spec.BackingField != null &&
6685 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6687 spec.MemberDefinition.SetIsUsed ();
6689 if (!ec.IsObsolete) {
6690 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6692 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6695 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6696 Error_AssignmentEventOnly (ec);
6698 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6700 InstanceExpression = null;
6702 return ml.ResolveMemberAccess (ec, left, original);
6706 return base.ResolveMemberAccess (ec, left, original);
6709 public override Expression CreateExpressionTree (ResolveContext ec)
6711 throw new NotSupportedException ("ET");
6714 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6716 if (right_side == EmptyExpression.EventAddition) {
6717 op = spec.AccessorAdd;
6718 } else if (right_side == EmptyExpression.EventSubtraction) {
6719 op = spec.AccessorRemove;
6723 Error_AssignmentEventOnly (ec);
6727 op = CandidateToBaseOverride (ec, op);
6731 protected override Expression DoResolve (ResolveContext ec)
6733 eclass = ExprClass.EventAccess;
6734 type = spec.MemberType;
6736 ResolveInstanceExpression (ec, null);
6738 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6739 Error_AssignmentEventOnly (ec);
6742 DoBestMemberChecks (ec, spec);
6746 public override void Emit (EmitContext ec)
6748 throw new NotSupportedException ();
6749 //Error_CannotAssign ();
6752 #region IAssignMethod Members
6754 public void Emit (EmitContext ec, bool leave_copy)
6756 throw new NotImplementedException ();
6759 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6761 if (leave_copy || !isCompound)
6762 throw new NotImplementedException ("EventExpr::EmitAssign");
6764 Arguments args = new Arguments (1);
6765 args.Add (new Argument (source));
6767 var call = new CallEmitter ();
6768 call.InstanceExpression = InstanceExpression;
6769 call.Emit (ec, op, args, loc);
6774 void Error_AssignmentEventOnly (ResolveContext ec)
6776 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6777 ec.Report.Error (79, loc,
6778 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6779 GetSignatureForError ());
6781 ec.Report.Error (70, loc,
6782 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6783 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6787 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6789 name = name.Substring (0, name.LastIndexOf ('.'));
6790 base.Error_CannotCallAbstractBase (rc, name);
6793 public override string GetSignatureForError ()
6795 return TypeManager.CSharpSignature (spec);
6798 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6800 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6804 public class TemporaryVariableReference : VariableReference
6806 public class Declarator : Statement
6808 TemporaryVariableReference variable;
6810 public Declarator (TemporaryVariableReference variable)
6812 this.variable = variable;
6816 protected override void DoEmit (EmitContext ec)
6818 variable.li.CreateBuilder (ec);
6821 public override void Emit (EmitContext ec)
6823 // Don't create sequence point
6827 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6832 protected override void CloneTo (CloneContext clonectx, Statement target)
6840 public TemporaryVariableReference (LocalVariable li, Location loc)
6843 this.type = li.Type;
6847 public override bool IsLockedByStatement {
6855 public LocalVariable LocalInfo {
6861 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6863 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6864 return new TemporaryVariableReference (li, loc);
6867 protected override Expression DoResolve (ResolveContext ec)
6869 eclass = ExprClass.Variable;
6872 // Don't capture temporary variables except when using
6873 // state machine redirection and block yields
6875 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6876 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6877 ec.IsVariableCapturingRequired) {
6878 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6879 storey.CaptureLocalVariable (ec, li);
6885 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6887 return Resolve (ec);
6890 public override void Emit (EmitContext ec)
6892 li.CreateBuilder (ec);
6897 public void EmitAssign (EmitContext ec, Expression source)
6899 li.CreateBuilder (ec);
6901 EmitAssign (ec, source, false, false);
6904 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6906 return li.HoistedVariant;
6909 public override bool IsFixed {
6910 get { return true; }
6913 public override bool IsRef {
6914 get { return false; }
6917 public override string Name {
6918 get { throw new NotImplementedException (); }
6921 public override void SetHasAddressTaken ()
6923 throw new NotImplementedException ();
6926 protected override ILocalVariable Variable {
6930 public override VariableInfo VariableInfo {
6931 get { return null; }
6936 /// Handles `var' contextual keyword; var becomes a keyword only
6937 /// if no type called var exists in a variable scope
6939 class VarExpr : SimpleName
6941 public VarExpr (Location loc)
6946 public bool InferType (ResolveContext ec, Expression right_side)
6949 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6951 type = right_side.Type;
6952 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6953 ec.Report.Error (815, loc,
6954 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6955 type.GetSignatureForError ());
6959 eclass = ExprClass.Variable;
6963 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6965 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6966 base.Error_TypeOrNamespaceNotFound (ec);
6968 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");