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 void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public ResolveFlags ExprClassToResolveFlags {
380 case ExprClass.Namespace:
381 return ResolveFlags.Type;
383 case ExprClass.MethodGroup:
384 return ResolveFlags.MethodGroup;
386 case ExprClass.TypeParameter:
387 return ResolveFlags.TypeParameter;
389 case ExprClass.Value:
390 case ExprClass.Variable:
391 case ExprClass.PropertyAccess:
392 case ExprClass.EventAccess:
393 case ExprClass.IndexerAccess:
394 return ResolveFlags.VariableOrValue;
397 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
403 // Implements identical simple name and type-name resolution
405 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
408 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
411 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
412 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
414 if (left is MemberExpr || left is VariableReference) {
415 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
416 if (identical_type != null && identical_type.Type == left.Type)
417 return identical_type;
423 public virtual string GetSignatureForError ()
425 return type.GetDefinition ().GetSignatureForError ();
429 /// Resolves an expression and performs semantic analysis on it.
433 /// Currently Resolve wraps DoResolve to perform sanity
434 /// checking and assertion checking on what we expect from Resolve.
436 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
438 if (eclass != ExprClass.Unresolved) {
439 if ((flags & ExprClassToResolveFlags) == 0) {
440 Error_UnexpectedKind (ec, flags, loc);
454 if ((flags & e.ExprClassToResolveFlags) == 0) {
455 e.Error_UnexpectedKind (ec, flags, loc);
460 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
463 } catch (Exception ex) {
464 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
465 ec.Report.Printer is NullReportPrinter)
468 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
469 return ErrorExpression.Instance; // TODO: Add location
474 /// Resolves an expression and performs semantic analysis on it.
476 public Expression Resolve (ResolveContext rc)
478 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
482 /// Resolves an expression for LValue assignment
486 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
487 /// checking and assertion checking on what we expect from Resolve
489 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
491 int errors = ec.Report.Errors;
492 bool out_access = right_side == EmptyExpression.OutAccess;
494 Expression e = DoResolveLValue (ec, right_side);
496 if (e != null && out_access && !(e is IMemoryLocation)) {
497 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
498 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
500 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
501 // e.GetType () + " " + e.GetSignatureForError ());
506 if (errors == ec.Report.Errors) {
507 Error_ValueAssignment (ec, right_side);
512 if (e.eclass == ExprClass.Unresolved)
513 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
515 if ((e.type == null) && !(e is GenericTypeExpr))
516 throw new Exception ("Expression " + e + " did not set its type after Resolve");
521 public Constant ResolveLabelConstant (ResolveContext rc)
523 var expr = Resolve (rc);
527 Constant c = expr as Constant;
529 if (expr.type != InternalType.ErrorType)
530 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
538 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
540 rc.Module.Compiler.Report.Error (182, loc,
541 "An attribute argument must be a constant expression, typeof expression or array creation expression");
545 /// Emits the code for the expression
549 /// The Emit method is invoked to generate the code
550 /// for the expression.
552 public abstract void Emit (EmitContext ec);
555 // Emit code to branch to @target if this expression is equivalent to @on_true.
556 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
557 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
558 // including the use of conditional branches. Note also that a branch MUST be emitted
559 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
562 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
565 // Emit this expression for its side effects, not for its value.
566 // The default implementation is to emit the value, and then throw it away.
567 // Subclasses can provide more efficient implementations, but those MUST be equivalent
568 public virtual void EmitSideEffect (EmitContext ec)
571 ec.Emit (OpCodes.Pop);
575 // Emits the expression into temporary field variable. The method
576 // should be used for await expressions only
578 public virtual Expression EmitToField (EmitContext ec)
581 // This is the await prepare Emit method. When emitting code like
582 // a + b we emit code like
588 // For await a + await b we have to interfere the flow to keep the
589 // stack clean because await yields from the expression. The emit
592 // a = a.EmitToField () // a is changed to temporary field access
593 // b = b.EmitToField ()
599 // The idea is to emit expression and leave the stack empty with
600 // result value still available.
602 // Expressions should override this default implementation when
603 // optimized version can be provided (e.g. FieldExpr)
606 // We can optimize for side-effect free expressions, they can be
607 // emitted out of order
609 if (IsSideEffectFree)
612 bool needs_temporary = ContainsEmitWithAwait ();
613 if (!needs_temporary)
616 // Emit original code
617 var field = EmitToFieldSource (ec);
620 // Store the result to temporary field when we
621 // cannot load `this' directly
623 field = ec.GetTemporaryField (type);
624 if (needs_temporary) {
626 // Create temporary local (we cannot load `this' before Emit)
628 var temp = ec.GetTemporaryLocal (type);
629 ec.Emit (OpCodes.Stloc, temp);
632 ec.Emit (OpCodes.Ldloc, temp);
633 field.EmitAssignFromStack (ec);
635 ec.FreeTemporaryLocal (temp, type);
637 field.EmitAssignFromStack (ec);
644 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
647 // Default implementation calls Emit method
653 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
655 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
656 bool contains_await = false;
658 for (int i = 1; i < expressions.Count; ++i) {
659 if (expressions[i].ContainsEmitWithAwait ()) {
660 contains_await = true;
665 if (contains_await) {
666 for (int i = 0; i < expressions.Count; ++i) {
667 expressions[i] = expressions[i].EmitToField (ec);
672 for (int i = 0; i < expressions.Count; ++i) {
673 expressions[i].Emit (ec);
678 /// Protected constructor. Only derivate types should
679 /// be able to be created
682 protected Expression ()
687 /// Returns a fully formed expression after a MemberLookup
690 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
692 if (spec is EventSpec)
693 return new EventExpr ((EventSpec) spec, loc);
694 if (spec is ConstSpec)
695 return new ConstantExpr ((ConstSpec) spec, loc);
696 if (spec is FieldSpec)
697 return new FieldExpr ((FieldSpec) spec, loc);
698 if (spec is PropertySpec)
699 return new PropertyExpr ((PropertySpec) spec, loc);
700 if (spec is TypeSpec)
701 return new TypeExpression (((TypeSpec) spec), loc);
706 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
708 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
710 rc.Report.SymbolRelatedToPreviousError (type);
712 // Report meaningful error for struct as they always have default ctor in C# context
713 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
715 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
716 type.GetSignatureForError ());
722 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
723 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
724 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
727 return r.ResolveMember<MethodSpec> (rc, ref args);
731 public enum MemberLookupRestrictions
740 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
741 // `qualifier_type' or null to lookup members in the current class.
743 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
745 var members = MemberCache.FindMembers (queried_type, name, false);
749 MemberSpec non_method = null;
750 MemberSpec ambig_non_method = null;
752 for (int i = 0; i < members.Count; ++i) {
753 var member = members[i];
755 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
756 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
759 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
762 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
766 if (!member.IsAccessible (rc))
770 // With runtime binder we can have a situation where queried type is inaccessible
771 // because it came via dynamic object, the check about inconsisted accessibility
772 // had no effect as the type was unknown during compilation
775 // private class N { }
777 // public dynamic Foo ()
783 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
787 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
788 if (member is MethodSpec) {
790 // Interface members that are hidden by class members are removed from the set. This
791 // step only has an effect if T is a type parameter and T has both an effective base
792 // class other than object and a non-empty effective interface set
794 var tps = queried_type as TypeParameterSpec;
795 if (tps != null && tps.HasTypeConstraint)
796 members = RemoveHiddenTypeParameterMethods (members);
798 return new MethodGroupExpr (members, queried_type, loc);
801 if (!Invocation.IsMemberInvocable (member))
805 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
807 } else if (!errorMode && !member.IsNotCSharpCompatible) {
809 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
810 // T has both an effective base class other than object and a non-empty effective interface set.
812 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
814 var tps = queried_type as TypeParameterSpec;
815 if (tps != null && tps.HasTypeConstraint) {
816 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
819 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
825 ambig_non_method = member;
829 if (non_method != null) {
830 if (ambig_non_method != null && rc != null) {
831 var report = rc.Module.Compiler.Report;
832 report.SymbolRelatedToPreviousError (non_method);
833 report.SymbolRelatedToPreviousError (ambig_non_method);
834 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
835 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
838 if (non_method is MethodSpec)
839 return new MethodGroupExpr (members, queried_type, loc);
841 return ExprClassFromMemberInfo (non_method, loc);
844 if (members[0].DeclaringType.BaseType == null)
847 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
849 } while (members != null);
854 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
856 if (members.Count < 2)
860 // If M is a method, then all non-method members declared in an interface declaration
861 // are removed from the set, and all methods with the same signature as M declared in
862 // an interface declaration are removed from the set
866 for (int i = 0; i < members.Count; ++i) {
867 var method = members[i] as MethodSpec;
868 if (method == null) {
871 members = new List<MemberSpec> (members);
874 members.RemoveAt (i--);
878 if (!method.DeclaringType.IsInterface)
881 for (int ii = 0; ii < members.Count; ++ii) {
882 var candidate = members[ii] as MethodSpec;
883 if (candidate == null || !candidate.DeclaringType.IsClass)
886 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
891 members = new List<MemberSpec> (members);
894 members.RemoveAt (i--);
902 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
904 throw new NotImplementedException ();
907 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
909 if (t == InternalType.ErrorType)
912 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
913 oper, t.GetSignatureForError ());
916 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
918 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
922 /// Returns an expression that can be used to invoke operator true
923 /// on the expression if it exists.
925 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
927 return GetOperatorTrueOrFalse (ec, e, true, loc);
931 /// Returns an expression that can be used to invoke operator false
932 /// on the expression if it exists.
934 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
936 return GetOperatorTrueOrFalse (ec, e, false, loc);
939 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
941 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
942 var methods = MemberCache.GetUserOperator (e.type, op, false);
946 Arguments arguments = new Arguments (1);
947 arguments.Add (new Argument (e));
949 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
950 var oper = res.ResolveOperator (ec, ref arguments);
955 return new UserOperatorCall (oper, arguments, null, loc);
958 public virtual string ExprClassName
962 case ExprClass.Unresolved:
964 case ExprClass.Value:
966 case ExprClass.Variable:
968 case ExprClass.Namespace:
972 case ExprClass.MethodGroup:
973 return "method group";
974 case ExprClass.PropertyAccess:
975 return "property access";
976 case ExprClass.EventAccess:
977 return "event access";
978 case ExprClass.IndexerAccess:
979 return "indexer access";
980 case ExprClass.Nothing:
982 case ExprClass.TypeParameter:
983 return "type parameter";
985 throw new Exception ("Should not happen");
990 /// Reports that we were expecting `expr' to be of class `expected'
992 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
994 var name = memberExpr.GetSignatureForError ();
996 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
999 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1001 string [] valid = new string [4];
1004 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1005 valid [count++] = "variable";
1006 valid [count++] = "value";
1009 if ((flags & ResolveFlags.Type) != 0)
1010 valid [count++] = "type";
1012 if ((flags & ResolveFlags.MethodGroup) != 0)
1013 valid [count++] = "method group";
1016 valid [count++] = "unknown";
1018 StringBuilder sb = new StringBuilder (valid [0]);
1019 for (int i = 1; i < count - 1; i++) {
1021 sb.Append (valid [i]);
1024 sb.Append ("' or `");
1025 sb.Append (valid [count - 1]);
1028 ec.Report.Error (119, loc,
1029 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1032 public static void UnsafeError (ResolveContext ec, Location loc)
1034 UnsafeError (ec.Report, loc);
1037 public static void UnsafeError (Report Report, Location loc)
1039 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1043 // Converts `source' to an int, uint, long or ulong.
1045 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1047 var btypes = ec.BuiltinTypes;
1049 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1050 Arguments args = new Arguments (1);
1051 args.Add (new Argument (source));
1052 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1055 Expression converted;
1057 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1058 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1059 if (converted == null)
1060 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1061 if (converted == null)
1062 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1063 if (converted == null)
1064 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1066 if (converted == null) {
1067 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1073 // Only positive constants are allowed at compile time
1075 Constant c = converted as Constant;
1076 if (c != null && c.IsNegative)
1077 Error_NegativeArrayIndex (ec, source.loc);
1079 // No conversion needed to array index
1080 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1083 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1087 // Derived classes implement this method by cloning the fields that
1088 // could become altered during the Resolve stage
1090 // Only expressions that are created for the parser need to implement
1093 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1095 throw new NotImplementedException (
1097 "CloneTo not implemented for expression {0}", this.GetType ()));
1101 // Clones an expression created by the parser.
1103 // We only support expressions created by the parser so far, not
1104 // expressions that have been resolved (many more classes would need
1105 // to implement CloneTo).
1107 // This infrastructure is here merely for Lambda expressions which
1108 // compile the same code using different type values for the same
1109 // arguments to find the correct overload
1111 public virtual Expression Clone (CloneContext clonectx)
1113 Expression cloned = (Expression) MemberwiseClone ();
1114 CloneTo (clonectx, cloned);
1120 // Implementation of expression to expression tree conversion
1122 public abstract Expression CreateExpressionTree (ResolveContext ec);
1124 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1126 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1129 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1131 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1134 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1136 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1139 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1141 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1145 return new TypeExpression (t, loc);
1149 // Implemented by all expressions which support conversion from
1150 // compiler expression to invokable runtime expression. Used by
1151 // dynamic C# binder.
1153 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1155 throw new NotImplementedException ("MakeExpression for " + GetType ());
1158 public virtual object Accept (StructuralVisitor visitor)
1160 return visitor.Visit (this);
1165 /// This is just a base class for expressions that can
1166 /// appear on statements (invocations, object creation,
1167 /// assignments, post/pre increment and decrement). The idea
1168 /// being that they would support an extra Emition interface that
1169 /// does not leave a result on the stack.
1171 public abstract class ExpressionStatement : Expression
1173 public ExpressionStatement ResolveStatement (BlockContext ec)
1175 Expression e = Resolve (ec);
1179 ExpressionStatement es = e as ExpressionStatement;
1181 Error_InvalidExpressionStatement (ec);
1184 // This is quite expensive warning, try to limit the damage
1186 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1187 WarningAsyncWithoutWait (ec, e);
1193 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1195 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1196 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1201 // Need to do full resolve because GetAwaiter can be extension method
1202 // available only in this context
1204 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1208 var arguments = new Arguments (0);
1209 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1214 // Use same check rules as for real await
1216 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1217 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1220 bc.Report.Warning (4014, 1, e.Location,
1221 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1225 var inv = e as Invocation;
1226 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1227 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1228 bc.Report.Warning (4014, 1, e.Location,
1229 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1235 /// Requests the expression to be emitted in a `statement'
1236 /// context. This means that no new value is left on the
1237 /// stack after invoking this method (constrasted with
1238 /// Emit that will always leave a value on the stack).
1240 public abstract void EmitStatement (EmitContext ec);
1242 public override void EmitSideEffect (EmitContext ec)
1249 /// This kind of cast is used to encapsulate the child
1250 /// whose type is child.Type into an expression that is
1251 /// reported to return "return_type". This is used to encapsulate
1252 /// expressions which have compatible types, but need to be dealt
1253 /// at higher levels with.
1255 /// For example, a "byte" expression could be encapsulated in one
1256 /// of these as an "unsigned int". The type for the expression
1257 /// would be "unsigned int".
1260 public abstract class TypeCast : Expression
1262 protected readonly Expression child;
1264 protected TypeCast (Expression child, TypeSpec return_type)
1266 eclass = child.eclass;
1267 loc = child.Location;
1272 public Expression Child {
1278 public override bool ContainsEmitWithAwait ()
1280 return child.ContainsEmitWithAwait ();
1283 public override Expression CreateExpressionTree (ResolveContext ec)
1285 Arguments args = new Arguments (2);
1286 args.Add (new Argument (child.CreateExpressionTree (ec)));
1287 args.Add (new Argument (new TypeOf (type, loc)));
1289 if (type.IsPointer || child.Type.IsPointer)
1290 Error_PointerInsideExpressionTree (ec);
1292 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1295 protected override Expression DoResolve (ResolveContext ec)
1297 // This should never be invoked, we are born in fully
1298 // initialized state.
1303 public override void Emit (EmitContext ec)
1308 public override SLE.Expression MakeExpression (BuilderContext ctx)
1311 return base.MakeExpression (ctx);
1313 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1314 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1315 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1319 protected override void CloneTo (CloneContext clonectx, Expression t)
1324 public override bool IsNull {
1325 get { return child.IsNull; }
1329 public class EmptyCast : TypeCast {
1330 EmptyCast (Expression child, TypeSpec target_type)
1331 : base (child, target_type)
1335 public static Expression Create (Expression child, TypeSpec type)
1337 Constant c = child as Constant;
1339 var enum_constant = c as EnumConstant;
1340 if (enum_constant != null)
1341 c = enum_constant.Child;
1343 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1347 var res = c.ConvertImplicitly (type);
1353 EmptyCast e = child as EmptyCast;
1355 return new EmptyCast (e.child, type);
1357 return new EmptyCast (child, type);
1360 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1362 child.EmitBranchable (ec, label, on_true);
1365 public override void EmitSideEffect (EmitContext ec)
1367 child.EmitSideEffect (ec);
1372 // Used for predefined type user operator (no obsolete check, etc.)
1374 public class OperatorCast : TypeCast
1376 readonly MethodSpec conversion_operator;
1378 public OperatorCast (Expression expr, TypeSpec target_type)
1379 : this (expr, target_type, target_type, false)
1383 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1384 : this (expr, target_type, target_type, find_explicit)
1388 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1389 : base (expr, returnType)
1391 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1392 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1395 foreach (MethodSpec oper in mi) {
1396 if (oper.ReturnType != returnType)
1399 if (oper.Parameters.Types[0] == expr.Type) {
1400 conversion_operator = oper;
1406 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1407 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1410 public override void Emit (EmitContext ec)
1413 ec.Emit (OpCodes.Call, conversion_operator);
1418 // Constant specialization of EmptyCast.
1419 // We need to special case this since an empty cast of
1420 // a constant is still a constant.
1422 public class EmptyConstantCast : Constant
1424 public readonly Constant child;
1426 public EmptyConstantCast (Constant child, TypeSpec type)
1427 : base (child.Location)
1430 throw new ArgumentNullException ("child");
1433 this.eclass = child.eclass;
1437 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1439 if (child.Type == target_type)
1442 // FIXME: check that 'type' can be converted to 'target_type' first
1443 return child.ConvertExplicitly (in_checked_context, target_type);
1446 public override Expression CreateExpressionTree (ResolveContext ec)
1448 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1449 child.CreateExpressionTree (ec),
1450 new TypeOf (type, loc));
1453 Error_PointerInsideExpressionTree (ec);
1455 return CreateExpressionFactoryCall (ec, "Convert", args);
1458 public override bool IsDefaultValue {
1459 get { return child.IsDefaultValue; }
1462 public override bool IsNegative {
1463 get { return child.IsNegative; }
1466 public override bool IsNull {
1467 get { return child.IsNull; }
1470 public override bool IsOneInteger {
1471 get { return child.IsOneInteger; }
1474 public override bool IsSideEffectFree {
1476 return child.IsSideEffectFree;
1480 public override bool IsZeroInteger {
1481 get { return child.IsZeroInteger; }
1484 public override void Emit (EmitContext ec)
1489 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1491 child.EmitBranchable (ec, label, on_true);
1493 // Only to make verifier happy
1494 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1495 ec.Emit (OpCodes.Unbox_Any, type);
1498 public override void EmitSideEffect (EmitContext ec)
1500 child.EmitSideEffect (ec);
1503 public override object GetValue ()
1505 return child.GetValue ();
1508 public override string GetValueAsLiteral ()
1510 return child.GetValueAsLiteral ();
1513 public override long GetValueAsLong ()
1515 return child.GetValueAsLong ();
1518 public override Constant ConvertImplicitly (TypeSpec target_type)
1520 if (type == target_type)
1523 // FIXME: Do we need to check user conversions?
1524 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1527 return child.ConvertImplicitly (target_type);
1532 /// This class is used to wrap literals which belong inside Enums
1534 public class EnumConstant : Constant
1536 public Constant Child;
1538 public EnumConstant (Constant child, TypeSpec enum_type)
1539 : base (child.Location)
1543 this.eclass = ExprClass.Value;
1544 this.type = enum_type;
1547 protected EnumConstant (Location loc)
1552 public override void Emit (EmitContext ec)
1557 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1559 Child.EncodeAttributeValue (rc, enc, Child.Type);
1562 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1564 Child.EmitBranchable (ec, label, on_true);
1567 public override void EmitSideEffect (EmitContext ec)
1569 Child.EmitSideEffect (ec);
1572 public override string GetSignatureForError()
1574 return Type.GetSignatureForError ();
1577 public override object GetValue ()
1579 return Child.GetValue ();
1583 public override object GetTypedValue ()
1586 // The method can be used in dynamic context only (on closed types)
1588 // System.Enum.ToObject cannot be called on dynamic types
1589 // EnumBuilder has to be used, but we cannot use EnumBuilder
1590 // because it does not properly support generics
1592 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1596 public override string GetValueAsLiteral ()
1598 return Child.GetValueAsLiteral ();
1601 public override long GetValueAsLong ()
1603 return Child.GetValueAsLong ();
1606 public EnumConstant Increment()
1608 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1611 public override bool IsDefaultValue {
1613 return Child.IsDefaultValue;
1617 public override bool IsSideEffectFree {
1619 return Child.IsSideEffectFree;
1623 public override bool IsZeroInteger {
1624 get { return Child.IsZeroInteger; }
1627 public override bool IsNegative {
1629 return Child.IsNegative;
1633 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1635 if (Child.Type == target_type)
1638 return Child.ConvertExplicitly (in_checked_context, target_type);
1641 public override Constant ConvertImplicitly (TypeSpec type)
1643 if (this.type == type) {
1647 if (!Convert.ImplicitStandardConversionExists (this, type)){
1651 return Child.ConvertImplicitly (type);
1656 /// This kind of cast is used to encapsulate Value Types in objects.
1658 /// The effect of it is to box the value type emitted by the previous
1661 public class BoxedCast : TypeCast {
1663 public BoxedCast (Expression expr, TypeSpec target_type)
1664 : base (expr, target_type)
1666 eclass = ExprClass.Value;
1669 protected override Expression DoResolve (ResolveContext ec)
1671 // This should never be invoked, we are born in fully
1672 // initialized state.
1677 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1679 // Only boxing to object type is supported
1680 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1681 base.EncodeAttributeValue (rc, enc, targetType);
1685 enc.Encode (child.Type);
1686 child.EncodeAttributeValue (rc, enc, child.Type);
1689 public override void Emit (EmitContext ec)
1693 ec.Emit (OpCodes.Box, child.Type);
1696 public override void EmitSideEffect (EmitContext ec)
1698 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1699 // so, we need to emit the box+pop instructions in most cases
1700 if (child.Type.IsStruct &&
1701 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1702 child.EmitSideEffect (ec);
1704 base.EmitSideEffect (ec);
1708 public class UnboxCast : TypeCast {
1709 public UnboxCast (Expression expr, TypeSpec return_type)
1710 : base (expr, return_type)
1714 protected override Expression DoResolve (ResolveContext ec)
1716 // This should never be invoked, we are born in fully
1717 // initialized state.
1722 public override void Emit (EmitContext ec)
1726 ec.Emit (OpCodes.Unbox_Any, type);
1731 /// This is used to perform explicit numeric conversions.
1733 /// Explicit numeric conversions might trigger exceptions in a checked
1734 /// context, so they should generate the conv.ovf opcodes instead of
1737 public class ConvCast : TypeCast {
1738 public enum Mode : byte {
1739 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1741 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1742 U2_I1, U2_U1, U2_I2, U2_CH,
1743 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1744 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1745 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1746 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1747 CH_I1, CH_U1, CH_I2,
1748 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1749 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1755 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1756 : base (child, return_type)
1761 protected override Expression DoResolve (ResolveContext ec)
1763 // This should never be invoked, we are born in fully
1764 // initialized state.
1769 public override string ToString ()
1771 return String.Format ("ConvCast ({0}, {1})", mode, child);
1774 public override void Emit (EmitContext ec)
1780 public static void Emit (EmitContext ec, Mode mode)
1782 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1784 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1785 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1786 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1787 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1788 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1790 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1791 case Mode.U1_CH: /* nothing */ break;
1793 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1794 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1795 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1796 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1797 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1798 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1800 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1801 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1802 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1803 case Mode.U2_CH: /* nothing */ break;
1805 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1806 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1807 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1808 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1809 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1810 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1811 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1813 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1814 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1815 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1816 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1817 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1818 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1820 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1821 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1822 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1823 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1825 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1826 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1827 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1830 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1831 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1832 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1833 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1834 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1835 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1836 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1837 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1838 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1840 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1841 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1842 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1844 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1845 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1846 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1847 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1848 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1849 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1850 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1851 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1852 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1854 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1855 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1856 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1857 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1858 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1859 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1860 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1861 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1862 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1863 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1865 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1869 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1870 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1871 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1872 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1873 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1875 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1876 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1878 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1879 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1880 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1881 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1882 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1883 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1885 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1886 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1887 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1888 case Mode.U2_CH: /* nothing */ break;
1890 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1891 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1892 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1893 case Mode.I4_U4: /* nothing */ break;
1894 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1895 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1896 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1898 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1899 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1900 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1901 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1902 case Mode.U4_I4: /* nothing */ break;
1903 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1905 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1906 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1907 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1908 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1909 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1910 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1911 case Mode.I8_U8: /* nothing */ break;
1912 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1913 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1915 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1916 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1917 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1918 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1919 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1920 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1921 case Mode.U8_I8: /* nothing */ break;
1922 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1925 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1926 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1927 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1929 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1930 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1931 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1932 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1933 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1934 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1935 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1936 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1937 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1939 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1940 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1941 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1942 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1943 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1944 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1945 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1946 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1947 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1950 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1956 class OpcodeCast : TypeCast
1960 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1961 : base (child, return_type)
1966 protected override Expression DoResolve (ResolveContext ec)
1968 // This should never be invoked, we are born in fully
1969 // initialized state.
1974 public override void Emit (EmitContext ec)
1980 public TypeSpec UnderlyingType {
1981 get { return child.Type; }
1986 // Opcode casts expression with 2 opcodes but only
1987 // single expression tree node
1989 class OpcodeCastDuplex : OpcodeCast
1991 readonly OpCode second;
1993 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1994 : base (child, returnType, first)
1996 this.second = second;
1999 public override void Emit (EmitContext ec)
2007 /// This kind of cast is used to encapsulate a child and cast it
2008 /// to the class requested
2010 public sealed class ClassCast : TypeCast {
2011 readonly bool forced;
2013 public ClassCast (Expression child, TypeSpec return_type)
2014 : base (child, return_type)
2018 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2019 : base (child, return_type)
2021 this.forced = forced;
2024 public override void Emit (EmitContext ec)
2028 bool gen = TypeManager.IsGenericParameter (child.Type);
2030 ec.Emit (OpCodes.Box, child.Type);
2032 if (type.IsGenericParameter) {
2033 ec.Emit (OpCodes.Unbox_Any, type);
2040 ec.Emit (OpCodes.Castclass, type);
2045 // Created during resolving pahse when an expression is wrapped or constantified
2046 // and original expression can be used later (e.g. for expression trees)
2048 public class ReducedExpression : Expression
2050 public sealed class ReducedConstantExpression : EmptyConstantCast
2052 readonly Expression orig_expr;
2054 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2055 : base (expr, expr.Type)
2057 this.orig_expr = orig_expr;
2060 public override Constant ConvertImplicitly (TypeSpec target_type)
2062 Constant c = base.ConvertImplicitly (target_type);
2064 c = new ReducedConstantExpression (c, orig_expr);
2069 public override Expression CreateExpressionTree (ResolveContext ec)
2071 return orig_expr.CreateExpressionTree (ec);
2074 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2076 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2078 c = new ReducedConstantExpression (c, orig_expr);
2082 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2085 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2087 if (orig_expr is Conditional)
2088 child.EncodeAttributeValue (rc, enc, targetType);
2090 base.EncodeAttributeValue (rc, enc, targetType);
2094 sealed class ReducedExpressionStatement : ExpressionStatement
2096 readonly Expression orig_expr;
2097 readonly ExpressionStatement stm;
2099 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2101 this.orig_expr = orig;
2103 this.eclass = stm.eclass;
2104 this.type = stm.Type;
2106 this.loc = orig.Location;
2109 public override bool ContainsEmitWithAwait ()
2111 return stm.ContainsEmitWithAwait ();
2114 public override Expression CreateExpressionTree (ResolveContext ec)
2116 return orig_expr.CreateExpressionTree (ec);
2119 protected override Expression DoResolve (ResolveContext ec)
2124 public override void Emit (EmitContext ec)
2129 public override void EmitStatement (EmitContext ec)
2131 stm.EmitStatement (ec);
2135 readonly Expression expr, orig_expr;
2137 private ReducedExpression (Expression expr, Expression orig_expr)
2140 this.eclass = expr.eclass;
2141 this.type = expr.Type;
2142 this.orig_expr = orig_expr;
2143 this.loc = orig_expr.Location;
2148 public override bool IsSideEffectFree {
2150 return expr.IsSideEffectFree;
2154 public Expression OriginalExpression {
2162 public override bool ContainsEmitWithAwait ()
2164 return expr.ContainsEmitWithAwait ();
2168 // Creates fully resolved expression switcher
2170 public static Constant Create (Constant expr, Expression original_expr)
2172 if (expr.eclass == ExprClass.Unresolved)
2173 throw new ArgumentException ("Unresolved expression");
2175 return new ReducedConstantExpression (expr, original_expr);
2178 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2180 return new ReducedExpressionStatement (s, orig);
2183 public static Expression Create (Expression expr, Expression original_expr)
2185 return Create (expr, original_expr, true);
2189 // Creates unresolved reduce expression. The original expression has to be
2190 // already resolved. Created expression is constant based based on `expr'
2191 // value unless canBeConstant is used
2193 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2195 if (canBeConstant) {
2196 Constant c = expr as Constant;
2198 return Create (c, original_expr);
2201 ExpressionStatement s = expr as ExpressionStatement;
2203 return Create (s, original_expr);
2205 if (expr.eclass == ExprClass.Unresolved)
2206 throw new ArgumentException ("Unresolved expression");
2208 return new ReducedExpression (expr, original_expr);
2211 public override Expression CreateExpressionTree (ResolveContext ec)
2213 return orig_expr.CreateExpressionTree (ec);
2216 protected override Expression DoResolve (ResolveContext ec)
2221 public override void Emit (EmitContext ec)
2226 public override Expression EmitToField (EmitContext ec)
2228 return expr.EmitToField(ec);
2231 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2233 expr.EmitBranchable (ec, target, on_true);
2236 public override SLE.Expression MakeExpression (BuilderContext ctx)
2238 return orig_expr.MakeExpression (ctx);
2243 // Standard composite pattern
2245 public abstract class CompositeExpression : Expression
2247 protected Expression expr;
2249 protected CompositeExpression (Expression expr)
2252 this.loc = expr.Location;
2255 public override bool ContainsEmitWithAwait ()
2257 return expr.ContainsEmitWithAwait ();
2260 public override Expression CreateExpressionTree (ResolveContext rc)
2262 return expr.CreateExpressionTree (rc);
2265 public Expression Child {
2266 get { return expr; }
2269 protected override Expression DoResolve (ResolveContext rc)
2271 expr = expr.Resolve (rc);
2274 eclass = expr.eclass;
2280 public override void Emit (EmitContext ec)
2285 public override bool IsNull {
2286 get { return expr.IsNull; }
2291 // Base of expressions used only to narrow resolve flow
2293 public abstract class ShimExpression : Expression
2295 protected Expression expr;
2297 protected ShimExpression (Expression expr)
2302 public Expression Expr {
2308 protected override void CloneTo (CloneContext clonectx, Expression t)
2313 ShimExpression target = (ShimExpression) t;
2314 target.expr = expr.Clone (clonectx);
2317 public override bool ContainsEmitWithAwait ()
2319 return expr.ContainsEmitWithAwait ();
2322 public override Expression CreateExpressionTree (ResolveContext ec)
2324 throw new NotSupportedException ("ET");
2327 public override void Emit (EmitContext ec)
2329 throw new InternalErrorException ("Missing Resolve call");
2335 // Unresolved type name expressions
2337 public abstract class ATypeNameExpression : FullNamedExpression
2340 protected TypeArguments targs;
2342 protected ATypeNameExpression (string name, Location l)
2348 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2355 protected ATypeNameExpression (string name, int arity, Location l)
2356 : this (name, new UnboundTypeArguments (arity), l)
2362 protected int Arity {
2364 return targs == null ? 0 : targs.Count;
2368 public bool HasTypeArguments {
2370 return targs != null && !targs.IsEmpty;
2374 public string Name {
2383 public TypeArguments TypeArguments {
2391 public override bool Equals (object obj)
2393 ATypeNameExpression atne = obj as ATypeNameExpression;
2394 return atne != null && atne.Name == Name &&
2395 (targs == null || targs.Equals (atne.targs));
2398 public override int GetHashCode ()
2400 return Name.GetHashCode ();
2403 // TODO: Move it to MemberCore
2404 public static string GetMemberType (MemberCore mc)
2410 if (mc is FieldBase)
2412 if (mc is MethodCore)
2414 if (mc is EnumMember)
2422 public override string GetSignatureForError ()
2424 if (targs != null) {
2425 return Name + "<" + targs.GetSignatureForError () + ">";
2431 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2435 /// SimpleName expressions are formed of a single word and only happen at the beginning
2436 /// of a dotted-name.
2438 public class SimpleName : ATypeNameExpression
2440 public SimpleName (string name, Location l)
2445 public SimpleName (string name, TypeArguments args, Location l)
2446 : base (name, args, l)
2450 public SimpleName (string name, int arity, Location l)
2451 : base (name, arity, l)
2455 public SimpleName GetMethodGroup ()
2457 return new SimpleName (Name, targs, loc);
2460 protected override Expression DoResolve (ResolveContext rc)
2462 var e = SimpleNameResolve (rc, null);
2464 var fe = e as FieldExpr;
2466 fe.VerifyAssignedStructField (rc, null);
2472 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2474 return SimpleNameResolve (ec, right_side);
2477 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2479 if (ctx.CurrentType != null) {
2480 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2481 if (member != null) {
2482 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2487 var report = ctx.Module.Compiler.Report;
2489 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2490 if (retval != null) {
2491 report.SymbolRelatedToPreviousError (retval.Type);
2492 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2496 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2497 if (retval != null) {
2498 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2502 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2503 if (ns_candidates != null) {
2504 if (ctx is UsingAliasNamespace.AliasContext) {
2505 report.Error (246, loc,
2506 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2507 ns_candidates[0], Name);
2509 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2510 report.Error (246, loc,
2511 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2515 report.Error (246, loc,
2516 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2521 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2523 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2526 if (fne.Type != null && Arity > 0) {
2527 if (HasTypeArguments) {
2528 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2529 if (ct.ResolveAsType (mc) == null)
2535 return new GenericOpenTypeExpr (fne.Type, loc);
2539 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2541 if (!(fne is Namespace))
2545 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2546 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2547 mc.Module.Compiler.Report.Error (1980, Location,
2548 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2549 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2552 fne = new DynamicTypeExpr (loc);
2553 fne.ResolveAsType (mc);
2559 Error_TypeOrNamespaceNotFound (mc);
2563 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2565 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2568 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2570 int lookup_arity = Arity;
2571 bool errorMode = false;
2573 Block current_block = rc.CurrentBlock;
2574 INamedBlockVariable variable = null;
2575 bool variable_found = false;
2579 // Stage 1: binding to local variables or parameters
2581 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2583 if (current_block != null && lookup_arity == 0) {
2584 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2585 if (!variable.IsDeclared) {
2586 // We found local name in accessible block but it's not
2587 // initialized yet, maybe the user wanted to bind to something else
2589 variable_found = true;
2591 e = variable.CreateReferenceExpression (rc, loc);
2594 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2603 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2605 TypeSpec member_type = rc.CurrentType;
2606 for (; member_type != null; member_type = member_type.DeclaringType) {
2607 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2611 var me = e as MemberExpr;
2613 // The name matches a type, defer to ResolveAsTypeStep
2621 if (variable != null) {
2622 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2623 rc.Report.Error (844, loc,
2624 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2625 Name, me.GetSignatureForError ());
2629 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2630 // Leave it to overload resolution to report correct error
2632 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2633 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2636 // LAMESPEC: again, ignores InvocableOnly
2637 if (variable != null) {
2638 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2639 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2643 // MemberLookup does not check accessors availability, this is actually needed for properties only
2645 var pe = me as PropertyExpr;
2648 // Break as there is no other overload available anyway
2649 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2650 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2653 pe.Getter = pe.PropertyInfo.Get;
2655 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2658 pe.Setter = pe.PropertyInfo.Set;
2663 // TODO: It's used by EventExpr -> FieldExpr transformation only
2664 // TODO: Should go to MemberAccess
2665 me = me.ResolveMemberAccess (rc, null, null);
2669 me.SetTypeArguments (rc, targs);
2676 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2678 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2679 if (IsPossibleTypeOrNamespace (rc)) {
2680 if (variable != null) {
2681 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2682 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2685 return ResolveAsTypeOrNamespace (rc);
2690 if (variable_found) {
2691 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2694 var tparams = rc.CurrentTypeParameters;
2695 if (tparams != null) {
2696 if (tparams.Find (Name) != null) {
2697 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2702 var ct = rc.CurrentType;
2704 if (ct.MemberDefinition.TypeParametersCount > 0) {
2705 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2706 if (ctp.Name == Name) {
2707 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2713 ct = ct.DeclaringType;
2714 } while (ct != null);
2717 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2718 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2720 rc.Report.SymbolRelatedToPreviousError (e.Type);
2721 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2725 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2727 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2728 return ErrorExpression.Instance;
2732 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2734 if (e.Type.Arity != Arity) {
2735 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2739 if (e is TypeExpr) {
2740 // TypeExpression does not have correct location
2741 if (e is TypeExpression)
2742 e = new TypeExpression (e.Type, loc);
2748 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2751 return ErrorExpression.Instance;
2754 if (rc.Module.Evaluator != null) {
2755 var fi = rc.Module.Evaluator.LookupField (Name);
2757 return new FieldExpr (fi.Item1, loc);
2765 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2767 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2772 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2773 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2777 if (right_side != null) {
2778 e = e.ResolveLValue (ec, right_side);
2786 public override object Accept (StructuralVisitor visitor)
2788 return visitor.Visit (this);
2793 /// Represents a namespace or a type. The name of the class was inspired by
2794 /// section 10.8.1 (Fully Qualified Names).
2796 public abstract class FullNamedExpression : Expression
2798 protected override void CloneTo (CloneContext clonectx, Expression target)
2800 // Do nothing, most unresolved type expressions cannot be
2801 // resolved to different type
2804 public override bool ContainsEmitWithAwait ()
2809 public override Expression CreateExpressionTree (ResolveContext ec)
2811 throw new NotSupportedException ("ET");
2814 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2817 // This is used to resolve the expression as a type, a null
2818 // value will be returned if the expression is not a type
2821 public override TypeSpec ResolveAsType (IMemberContext mc)
2823 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2828 TypeExpr te = fne as TypeExpr;
2830 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2838 var dep = type.GetMissingDependencies ();
2840 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2843 if (type.Kind == MemberKind.Void) {
2844 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2848 // Obsolete checks cannot be done when resolving base context as they
2849 // require type dependencies to be set but we are in process of resolving them
2851 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2852 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2853 if (obsolete_attr != null && !mc.IsObsolete) {
2854 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2862 public override void Emit (EmitContext ec)
2864 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2865 GetSignatureForError ());
2870 /// Expression that evaluates to a type
2872 public abstract class TypeExpr : FullNamedExpression
2874 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2880 protected sealed override Expression DoResolve (ResolveContext ec)
2886 public override bool Equals (object obj)
2888 TypeExpr tobj = obj as TypeExpr;
2892 return Type == tobj.Type;
2895 public override int GetHashCode ()
2897 return Type.GetHashCode ();
2902 /// Fully resolved Expression that already evaluated to a type
2904 public class TypeExpression : TypeExpr
2906 public TypeExpression (TypeSpec t, Location l)
2909 eclass = ExprClass.Type;
2913 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2920 /// This class denotes an expression which evaluates to a member
2921 /// of a struct or a class.
2923 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2926 // An instance expression associated with this member, if it's a
2927 // non-static member
2929 public Expression InstanceExpression;
2932 /// The name of this member.
2934 public abstract string Name {
2939 // When base.member is used
2941 public bool IsBase {
2942 get { return InstanceExpression is BaseThis; }
2946 /// Whether this is an instance member.
2948 public abstract bool IsInstance {
2953 /// Whether this is a static member.
2955 public abstract bool IsStatic {
2959 public abstract string KindName {
2963 protected abstract TypeSpec DeclaringType {
2967 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2969 return InstanceExpression.Type;
2974 // Converts best base candidate for virtual method starting from QueriedBaseType
2976 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2979 // Only when base.member is used and method is virtual
2985 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2986 // means for base.member access we have to find the closest match after we found best candidate
2988 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2990 // The method could already be what we are looking for
2992 TypeSpec[] targs = null;
2993 if (method.DeclaringType != InstanceExpression.Type) {
2994 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2995 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2996 if (base_override.IsGeneric)
2997 targs = method.TypeArguments;
2999 method = base_override;
3004 // When base access is used inside anonymous method/iterator/etc we need to
3005 // get back to the context of original type. We do it by emiting proxy
3006 // method in original class and rewriting base call to this compiler
3007 // generated method call which does the actual base invocation. This may
3008 // introduce redundant storey but with `this' only but it's tricky to avoid
3009 // at this stage as we don't know what expressions follow base
3011 if (rc.CurrentAnonymousMethod != null) {
3012 if (targs == null && method.IsGeneric) {
3013 targs = method.TypeArguments;
3014 method = method.GetGenericMethodDefinition ();
3017 if (method.Parameters.HasArglist)
3018 throw new NotImplementedException ("__arglist base call proxy");
3020 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3022 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3023 // get/set member expressions second call would fail to proxy because left expression
3024 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3025 // FIXME: The async check is another hack but will probably fail with mutators
3026 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3027 InstanceExpression = new This (loc).Resolve (rc);
3031 method = method.MakeGenericMethod (rc, targs);
3035 // Only base will allow this invocation to happen.
3037 if (method.IsAbstract) {
3038 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3044 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3046 if (InstanceExpression == null)
3049 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3050 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3051 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3056 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3058 if (InstanceExpression == null)
3061 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3064 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3066 var ct = rc.CurrentType;
3067 if (ct == qualifier)
3070 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3073 qualifier = qualifier.GetDefinition ();
3074 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3081 public override bool ContainsEmitWithAwait ()
3083 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3086 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3089 type = type.GetDefinition ();
3091 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3094 type = type.DeclaringType;
3095 } while (type != null);
3100 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3102 if (InstanceExpression != null) {
3103 InstanceExpression = InstanceExpression.Resolve (rc);
3104 CheckProtectedMemberAccess (rc, member);
3107 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3108 UnsafeError (rc, loc);
3111 var dep = member.GetMissingDependencies ();
3113 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3116 if (!rc.IsObsolete) {
3117 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3119 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3122 if (!(member is FieldSpec))
3123 member.MemberDefinition.SetIsUsed ();
3126 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3128 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3131 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3133 rc.Report.SymbolRelatedToPreviousError (member);
3134 rc.Report.Error (1540, loc,
3135 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3136 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3139 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3141 if (!ResolveInstanceExpressionCore (rc, rhs))
3145 // Check intermediate value modification which won't have any effect
3147 if (rhs != null && InstanceExpression.Type.IsStruct) {
3148 var fexpr = InstanceExpression as FieldExpr;
3149 if (fexpr != null) {
3150 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3153 if (fexpr.IsStatic) {
3154 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3155 fexpr.GetSignatureForError ());
3157 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3158 fexpr.GetSignatureForError ());
3160 } else if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3161 if (rc.CurrentInitializerVariable != null) {
3162 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3163 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3165 rc.Report.Error (1612, loc,
3166 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3167 InstanceExpression.GetSignatureForError ());
3175 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3178 if (InstanceExpression != null) {
3179 if (InstanceExpression is TypeExpr) {
3180 var t = InstanceExpression.Type;
3182 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3183 if (oa != null && !rc.IsObsolete) {
3184 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3187 t = t.DeclaringType;
3188 } while (t != null);
3190 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3191 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3192 rc.Report.Error (176, loc,
3193 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3194 GetSignatureForError ());
3198 InstanceExpression = null;
3204 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3205 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3206 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3207 rc.Report.Error (236, loc,
3208 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3209 GetSignatureForError ());
3211 rc.Report.Error (120, loc,
3212 "An object reference is required to access non-static member `{0}'",
3213 GetSignatureForError ());
3215 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3219 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3220 rc.Report.Error (38, loc,
3221 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3222 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3225 InstanceExpression = new This (loc);
3226 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3227 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3228 InstanceExpression = InstanceExpression.Resolve (rc);
3231 InstanceExpression = InstanceExpression.Resolve (rc);
3237 var me = InstanceExpression as MemberExpr;
3239 me.ResolveInstanceExpressionCore (rc, rhs);
3241 // Using this check to detect probing instance expression resolve
3242 if (!rc.OmitStructFlowAnalysis) {
3243 var fe = me as FieldExpr;
3244 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3245 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3246 rc.Report.Warning (1690, 1, loc,
3247 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3248 me.GetSignatureForError ());
3256 // Run member-access postponed check once we know that
3257 // the expression is not field expression which is the only
3258 // expression which can use uninitialized this
3260 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3261 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3265 // Additional checks for l-value member access
3268 if (InstanceExpression is UnboxCast) {
3269 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3276 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3278 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3279 ec.Report.Warning (1720, 1, left.Location,
3280 "Expression will always cause a `{0}'", "System.NullReferenceException");
3283 InstanceExpression = left;
3287 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3289 TypeSpec instance_type = InstanceExpression.Type;
3290 if (TypeSpec.IsValueType (instance_type)) {
3291 if (InstanceExpression is IMemoryLocation) {
3292 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3294 // Cannot release the temporary variable when its address
3295 // is required to be on stack for any parent
3296 LocalTemporary t = new LocalTemporary (instance_type);
3297 InstanceExpression.Emit (ec);
3299 t.AddressOf (ec, AddressOp.Store);
3302 InstanceExpression.Emit (ec);
3304 // Only to make verifier happy
3305 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3306 ec.Emit (OpCodes.Box, instance_type);
3309 if (prepare_for_load)
3310 ec.Emit (OpCodes.Dup);
3313 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3316 public class ExtensionMethodCandidates
3318 readonly NamespaceContainer container;
3319 readonly IList<MethodSpec> methods;
3321 readonly IMemberContext context;
3323 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3325 this.context = context;
3326 this.methods = methods;
3327 this.container = nsContainer;
3328 this.index = lookupIndex;
3331 public NamespaceContainer Container {
3337 public IMemberContext Context {
3343 public int LookupIndex {
3349 public IList<MethodSpec> Methods {
3357 // Represents a group of extension method candidates for whole namespace
3359 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3361 ExtensionMethodCandidates candidates;
3362 public Expression ExtensionExpression;
3364 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3365 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3367 this.candidates = candidates;
3368 this.ExtensionExpression = extensionExpr;
3371 public override bool IsStatic {
3372 get { return true; }
3376 // For extension methodgroup we are not looking for base members but parent
3377 // namespace extension methods
3379 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3381 // TODO: candidates are null only when doing error reporting, that's
3382 // incorrect. We have to discover same extension methods in error mode
3383 if (candidates == null)
3386 int arity = type_arguments == null ? 0 : type_arguments.Count;
3388 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3389 if (candidates == null)
3392 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3395 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3397 // We are already here
3401 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3403 if (arguments == null)
3404 arguments = new Arguments (1);
3406 ExtensionExpression = ExtensionExpression.Resolve (ec);
3407 if (ExtensionExpression == null)
3410 var cand = candidates;
3411 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3412 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3414 // Restore candidates in case we are running in probing mode
3417 // Store resolved argument and restore original arguments
3419 // Clean-up modified arguments for error reporting
3420 arguments.RemoveAt (0);
3424 var me = ExtensionExpression as MemberExpr;
3426 me.ResolveInstanceExpression (ec, null);
3427 var fe = me as FieldExpr;
3429 fe.Spec.MemberDefinition.SetIsUsed ();
3432 InstanceExpression = null;
3436 #region IErrorHandler Members
3438 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3443 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3445 rc.Report.SymbolRelatedToPreviousError (best);
3446 rc.Report.Error (1928, loc,
3447 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3448 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3451 rc.Report.Error (1929, loc,
3452 "Extension method instance type `{0}' cannot be converted to `{1}'",
3453 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3459 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3464 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3473 /// MethodGroupExpr represents a group of method candidates which
3474 /// can be resolved to the best method overload
3476 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3478 protected IList<MemberSpec> Methods;
3479 MethodSpec best_candidate;
3480 TypeSpec best_candidate_return;
3481 protected TypeArguments type_arguments;
3483 SimpleName simple_name;
3484 protected TypeSpec queried_type;
3486 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3490 this.type = InternalType.MethodGroup;
3492 eclass = ExprClass.MethodGroup;
3493 queried_type = type;
3496 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3497 : this (new MemberSpec[] { m }, type, loc)
3503 public MethodSpec BestCandidate {
3505 return best_candidate;
3509 public TypeSpec BestCandidateReturnType {
3511 return best_candidate_return;
3515 public IList<MemberSpec> Candidates {
3521 protected override TypeSpec DeclaringType {
3523 return queried_type;
3527 public override bool IsInstance {
3529 if (best_candidate != null)
3530 return !best_candidate.IsStatic;
3536 public override bool IsSideEffectFree {
3538 return InstanceExpression != null ?
3539 InstanceExpression.IsSideEffectFree : true;
3543 public override bool IsStatic {
3545 if (best_candidate != null)
3546 return best_candidate.IsStatic;
3552 public override string KindName {
3553 get { return "method"; }
3556 public override string Name {
3558 if (best_candidate != null)
3559 return best_candidate.Name;
3562 return Methods.First ().Name;
3569 // When best candidate is already know this factory can be used
3570 // to avoid expensive overload resolution to be called
3572 // NOTE: InstanceExpression has to be set manually
3574 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3576 return new MethodGroupExpr (best, queriedType, loc) {
3577 best_candidate = best,
3578 best_candidate_return = best.ReturnType
3582 public override string GetSignatureForError ()
3584 if (best_candidate != null)
3585 return best_candidate.GetSignatureForError ();
3587 return Methods.First ().GetSignatureForError ();
3590 public override Expression CreateExpressionTree (ResolveContext ec)
3592 if (best_candidate == null) {
3593 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3597 if (best_candidate.IsConditionallyExcluded (ec))
3598 ec.Report.Error (765, loc,
3599 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3601 return new TypeOfMethod (best_candidate, loc);
3604 protected override Expression DoResolve (ResolveContext ec)
3606 this.eclass = ExprClass.MethodGroup;
3608 if (InstanceExpression != null) {
3609 InstanceExpression = InstanceExpression.Resolve (ec);
3610 if (InstanceExpression == null)
3617 public override void Emit (EmitContext ec)
3619 throw new NotSupportedException ();
3622 public void EmitCall (EmitContext ec, Arguments arguments)
3624 var call = new CallEmitter ();
3625 call.InstanceExpression = InstanceExpression;
3626 call.Emit (ec, best_candidate, arguments, loc);
3629 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3631 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3632 Name, target.GetSignatureForError ());
3635 public static bool IsExtensionMethodArgument (Expression expr)
3638 // LAMESPEC: No details about which expressions are not allowed
3640 return !(expr is TypeExpr) && !(expr is BaseThis);
3644 /// Find the Applicable Function Members (7.4.2.1)
3646 /// me: Method Group expression with the members to select.
3647 /// it might contain constructors or methods (or anything
3648 /// that maps to a method).
3650 /// Arguments: ArrayList containing resolved Argument objects.
3652 /// loc: The location if we want an error to be reported, or a Null
3653 /// location for "probing" purposes.
3655 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3656 /// that is the best match of me on Arguments.
3659 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3661 // TODO: causes issues with probing mode, remove explicit Kind check
3662 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3665 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3666 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3667 r.BaseMembersProvider = this;
3668 r.InstanceQualifier = this;
3671 if (cerrors != null)
3672 r.CustomErrors = cerrors;
3674 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3675 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3676 if (best_candidate == null)
3677 return r.BestCandidateIsDynamic ? this : null;
3679 // Overload resolver had to create a new method group, all checks bellow have already been executed
3680 if (r.BestCandidateNewMethodGroup != null)
3681 return r.BestCandidateNewMethodGroup;
3683 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3684 if (InstanceExpression != null) {
3685 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3686 InstanceExpression = null;
3688 if (best_candidate.IsStatic && simple_name != null) {
3689 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3692 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3696 ResolveInstanceExpression (ec, null);
3699 var base_override = CandidateToBaseOverride (ec, best_candidate);
3700 if (base_override == best_candidate) {
3701 best_candidate_return = r.BestCandidateReturnType;
3703 best_candidate = base_override;
3704 best_candidate_return = best_candidate.ReturnType;
3707 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3708 ConstraintChecker cc = new ConstraintChecker (ec);
3709 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3713 // Additional check for possible imported base override method which
3714 // could not be done during IsOverrideMethodBaseTypeAccessible
3716 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3717 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3718 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3719 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3725 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3727 var fe = left as FieldExpr;
3730 // Using method-group on struct fields makes the struct assigned. I am not sure
3731 // why but that's what .net does
3733 fe.Spec.MemberDefinition.SetIsAssigned ();
3736 simple_name = original;
3737 return base.ResolveMemberAccess (ec, left, original);
3740 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3742 type_arguments = ta;
3745 #region IBaseMembersProvider Members
3747 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3749 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3752 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3754 if (queried_type == member.DeclaringType)
3757 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3758 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3762 // Extension methods lookup after ordinary methods candidates failed to apply
3764 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3766 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3769 if (!IsExtensionMethodArgument (InstanceExpression))
3772 int arity = type_arguments == null ? 0 : type_arguments.Count;
3773 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3774 if (methods == null)
3777 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3778 emg.SetTypeArguments (rc, type_arguments);
3785 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3787 public ConstructorInstanceQualifier (TypeSpec type)
3790 InstanceType = type;
3793 public TypeSpec InstanceType { get; private set; }
3795 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3797 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3801 public struct OverloadResolver
3804 public enum Restrictions
3808 ProbingOnly = 1 << 1,
3809 CovariantDelegate = 1 << 2,
3810 NoBaseMembers = 1 << 3,
3811 BaseMembersIncluded = 1 << 4
3814 public interface IBaseMembersProvider
3816 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3817 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3818 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3821 public interface IErrorHandler
3823 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3824 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3825 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3826 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3829 public interface IInstanceQualifier
3831 TypeSpec InstanceType { get; }
3832 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3835 sealed class NoBaseMembers : IBaseMembersProvider
3837 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3839 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3844 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3849 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3855 struct AmbiguousCandidate
3857 public readonly MemberSpec Member;
3858 public readonly bool Expanded;
3859 public readonly AParametersCollection Parameters;
3861 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3864 Parameters = parameters;
3865 Expanded = expanded;
3870 IList<MemberSpec> members;
3871 TypeArguments type_arguments;
3872 IBaseMembersProvider base_provider;
3873 IErrorHandler custom_errors;
3874 IInstanceQualifier instance_qualifier;
3875 Restrictions restrictions;
3876 MethodGroupExpr best_candidate_extension_group;
3877 TypeSpec best_candidate_return_type;
3879 SessionReportPrinter lambda_conv_msgs;
3881 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3882 : this (members, null, restrictions, loc)
3886 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3889 if (members == null || members.Count == 0)
3890 throw new ArgumentException ("empty members set");
3892 this.members = members;
3894 type_arguments = targs;
3895 this.restrictions = restrictions;
3896 if (IsDelegateInvoke)
3897 this.restrictions |= Restrictions.NoBaseMembers;
3899 base_provider = NoBaseMembers.Instance;
3904 public IBaseMembersProvider BaseMembersProvider {
3906 return base_provider;
3909 base_provider = value;
3913 public bool BestCandidateIsDynamic { get; set; }
3916 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3918 public MethodGroupExpr BestCandidateNewMethodGroup {
3920 return best_candidate_extension_group;
3925 // Return type can be different between best candidate and closest override
3927 public TypeSpec BestCandidateReturnType {
3929 return best_candidate_return_type;
3933 public IErrorHandler CustomErrors {
3935 return custom_errors;
3938 custom_errors = value;
3942 TypeSpec DelegateType {
3944 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3945 throw new InternalErrorException ("Not running in delegate mode", loc);
3947 return members [0].DeclaringType;
3951 public IInstanceQualifier InstanceQualifier {
3953 return instance_qualifier;
3956 instance_qualifier = value;
3960 bool IsProbingOnly {
3962 return (restrictions & Restrictions.ProbingOnly) != 0;
3966 bool IsDelegateInvoke {
3968 return (restrictions & Restrictions.DelegateInvoke) != 0;
3975 // 7.4.3.3 Better conversion from expression
3976 // Returns : 1 if a->p is better,
3977 // 2 if a->q is better,
3978 // 0 if neither is better
3980 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3982 TypeSpec argument_type = a.Type;
3985 // If argument is an anonymous function
3987 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3989 // p and q are delegate types or expression tree types
3991 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3992 if (q.MemberDefinition != p.MemberDefinition) {
3997 // Uwrap delegate from Expression<T>
3999 q = TypeManager.GetTypeArguments (q)[0];
4000 p = TypeManager.GetTypeArguments (p)[0];
4003 var p_m = Delegate.GetInvokeMethod (p);
4004 var q_m = Delegate.GetInvokeMethod (q);
4007 // With identical parameter lists
4009 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4018 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4020 if (p.Kind == MemberKind.Void) {
4021 return q.Kind != MemberKind.Void ? 2 : 0;
4025 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4027 if (q.Kind == MemberKind.Void) {
4028 return p.Kind != MemberKind.Void ? 1: 0;
4031 var am = (AnonymousMethodExpression) a.Expr;
4034 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4035 // better conversion is performed between underlying types Y1 and Y2
4037 if (p.IsGenericTask || q.IsGenericTask) {
4038 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4039 q = q.TypeArguments[0];
4040 p = p.TypeArguments[0];
4042 } else if (q != p) {
4044 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4046 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4047 var am_rt = am.InferReturnType (ec, null, orig_q);
4048 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4050 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4051 var am_rt = am.InferReturnType (ec, null, orig_p);
4052 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4058 // The parameters are identicial and return type is not void, use better type conversion
4059 // on return type to determine better one
4062 if (argument_type == p)
4065 if (argument_type == q)
4069 return BetterTypeConversion (ec, p, q);
4073 // 7.4.3.4 Better conversion from type
4075 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4077 if (p == null || q == null)
4078 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4080 switch (p.BuiltinType) {
4081 case BuiltinTypeSpec.Type.Int:
4082 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4085 case BuiltinTypeSpec.Type.Long:
4086 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4089 case BuiltinTypeSpec.Type.SByte:
4090 switch (q.BuiltinType) {
4091 case BuiltinTypeSpec.Type.Byte:
4092 case BuiltinTypeSpec.Type.UShort:
4093 case BuiltinTypeSpec.Type.UInt:
4094 case BuiltinTypeSpec.Type.ULong:
4098 case BuiltinTypeSpec.Type.Short:
4099 switch (q.BuiltinType) {
4100 case BuiltinTypeSpec.Type.UShort:
4101 case BuiltinTypeSpec.Type.UInt:
4102 case BuiltinTypeSpec.Type.ULong:
4106 case BuiltinTypeSpec.Type.Dynamic:
4107 // Dynamic is never better
4111 switch (q.BuiltinType) {
4112 case BuiltinTypeSpec.Type.Int:
4113 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4116 case BuiltinTypeSpec.Type.Long:
4117 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4120 case BuiltinTypeSpec.Type.SByte:
4121 switch (p.BuiltinType) {
4122 case BuiltinTypeSpec.Type.Byte:
4123 case BuiltinTypeSpec.Type.UShort:
4124 case BuiltinTypeSpec.Type.UInt:
4125 case BuiltinTypeSpec.Type.ULong:
4129 case BuiltinTypeSpec.Type.Short:
4130 switch (p.BuiltinType) {
4131 case BuiltinTypeSpec.Type.UShort:
4132 case BuiltinTypeSpec.Type.UInt:
4133 case BuiltinTypeSpec.Type.ULong:
4137 case BuiltinTypeSpec.Type.Dynamic:
4138 // Dynamic is never better
4142 // FIXME: handle lifted operators
4144 // TODO: this is expensive
4145 Expression p_tmp = new EmptyExpression (p);
4146 Expression q_tmp = new EmptyExpression (q);
4148 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4149 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4151 if (p_to_q && !q_to_p)
4154 if (q_to_p && !p_to_q)
4161 /// Determines "Better function" between candidate
4162 /// and the current best match
4165 /// Returns a boolean indicating :
4166 /// false if candidate ain't better
4167 /// true if candidate is better than the current best match
4169 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4170 MemberSpec best, AParametersCollection bparam, bool best_params)
4172 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4173 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4175 bool better_at_least_one = false;
4177 int args_count = args == null ? 0 : args.Count;
4181 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4184 // Default arguments are ignored for better decision
4185 if (a.IsDefaultArgument)
4189 // When comparing named argument the parameter type index has to be looked up
4190 // in original parameter set (override version for virtual members)
4192 NamedArgument na = a as NamedArgument;
4194 int idx = cparam.GetParameterIndexByName (na.Name);
4195 ct = candidate_pd.Types[idx];
4196 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4197 ct = TypeManager.GetElementType (ct);
4199 idx = bparam.GetParameterIndexByName (na.Name);
4200 bt = best_pd.Types[idx];
4201 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4202 bt = TypeManager.GetElementType (bt);
4204 ct = candidate_pd.Types[c_idx];
4205 bt = best_pd.Types[b_idx];
4207 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4208 ct = TypeManager.GetElementType (ct);
4212 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4213 bt = TypeManager.GetElementType (bt);
4218 if (TypeSpecComparer.IsEqual (ct, bt))
4222 int result = BetterExpressionConversion (ec, a, ct, bt);
4224 // for each argument, the conversion to 'ct' should be no worse than
4225 // the conversion to 'bt'.
4229 // for at least one argument, the conversion to 'ct' should be better than
4230 // the conversion to 'bt'.
4232 better_at_least_one = true;
4235 if (better_at_least_one)
4239 // This handles the case
4241 // Add (float f1, float f2, float f3);
4242 // Add (params decimal [] foo);
4244 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4245 // first candidate would've chosen as better.
4247 if (!same && !a.IsDefaultArgument)
4251 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4255 // This handles the following cases:
4257 // Foo (int i) is better than Foo (int i, long l = 0)
4258 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4259 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4261 // Prefer non-optional version
4263 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4265 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4266 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4269 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4272 return candidate_pd.Count >= best_pd.Count;
4276 // One is a non-generic method and second is a generic method, then non-generic is better
4278 if (best.IsGeneric != candidate.IsGeneric)
4279 return best.IsGeneric;
4282 // This handles the following cases:
4284 // Trim () is better than Trim (params char[] chars)
4285 // Concat (string s1, string s2, string s3) is better than
4286 // Concat (string s1, params string [] srest)
4287 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4289 // Prefer non-expanded version
4291 if (candidate_params != best_params)
4294 int candidate_param_count = candidate_pd.Count;
4295 int best_param_count = best_pd.Count;
4297 if (candidate_param_count != best_param_count)
4298 // can only happen if (candidate_params && best_params)
4299 return candidate_param_count > best_param_count && best_pd.HasParams;
4302 // Both methods have the same number of parameters, and the parameters have equal types
4303 // Pick the "more specific" signature using rules over original (non-inflated) types
4305 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4306 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4308 bool specific_at_least_once = false;
4309 for (j = 0; j < args_count; ++j) {
4310 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4312 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4313 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4315 ct = candidate_def_pd.Types[j];
4316 bt = best_def_pd.Types[j];
4321 TypeSpec specific = MoreSpecific (ct, bt);
4325 specific_at_least_once = true;
4328 if (specific_at_least_once)
4334 static bool CheckInflatedArguments (MethodSpec ms)
4336 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4339 // Setup constraint checker for probing only
4340 ConstraintChecker cc = new ConstraintChecker (null);
4342 var mp = ms.Parameters.Types;
4343 for (int i = 0; i < mp.Length; ++i) {
4344 var type = mp[i] as InflatedTypeSpec;
4348 var targs = type.TypeArguments;
4349 if (targs.Length == 0)
4352 // TODO: Checking inflated MVAR arguments should be enough
4353 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4360 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4362 rc.Report.Error (1729, loc,
4363 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4364 type.GetSignatureForError (), argCount.ToString ());
4368 // Determines if the candidate method is applicable to the given set of arguments
4369 // There could be two different set of parameters for same candidate where one
4370 // is the closest override for default values and named arguments checks and second
4371 // one being the virtual base for the parameter types and modifiers.
4373 // A return value rates candidate method compatibility,
4374 // 0 = the best, int.MaxValue = the worst
4377 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)
4379 // Parameters of most-derived type used mainly for named and optional parameters
4380 var pd = pm.Parameters;
4382 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4383 // params modifier instead of most-derived type
4384 var cpd = ((IParametersMember) candidate).Parameters;
4385 int param_count = pd.Count;
4386 int optional_count = 0;
4388 Arguments orig_args = arguments;
4390 if (arg_count != param_count) {
4392 // No arguments expansion when doing exact match for delegates
4394 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4395 for (int i = 0; i < pd.Count; ++i) {
4396 if (pd.FixedParameters[i].HasDefaultValue) {
4397 optional_count = pd.Count - i;
4403 if (optional_count != 0) {
4404 // Readjust expected number when params used
4405 if (cpd.HasParams) {
4407 if (arg_count < param_count)
4409 } else if (arg_count > param_count) {
4410 int args_gap = System.Math.Abs (arg_count - param_count);
4411 return int.MaxValue - 10000 + args_gap;
4412 } else if (arg_count < param_count - optional_count) {
4413 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4414 return int.MaxValue - 10000 + args_gap;
4416 } else if (arg_count != param_count) {
4417 int args_gap = System.Math.Abs (arg_count - param_count);
4419 return int.MaxValue - 10000 + args_gap;
4420 if (arg_count < param_count - 1)
4421 return int.MaxValue - 10000 + args_gap;
4424 // Resize to fit optional arguments
4425 if (optional_count != 0) {
4426 if (arguments == null) {
4427 arguments = new Arguments (optional_count);
4429 // Have to create a new container, so the next run can do same
4430 var resized = new Arguments (param_count);
4431 resized.AddRange (arguments);
4432 arguments = resized;
4435 for (int i = arg_count; i < param_count; ++i)
4436 arguments.Add (null);
4440 if (arg_count > 0) {
4442 // Shuffle named arguments to the right positions if there are any
4444 if (arguments[arg_count - 1] is NamedArgument) {
4445 arg_count = arguments.Count;
4447 for (int i = 0; i < arg_count; ++i) {
4448 bool arg_moved = false;
4450 NamedArgument na = arguments[i] as NamedArgument;
4454 int index = pd.GetParameterIndexByName (na.Name);
4456 // Named parameter not found
4460 // already reordered
4465 if (index >= param_count) {
4466 // When using parameters which should not be available to the user
4467 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4470 arguments.Add (null);
4474 temp = arguments[index];
4476 // The slot has been taken by positional argument
4477 if (temp != null && !(temp is NamedArgument))
4482 arguments = arguments.MarkOrderedArgument (na);
4486 if (arguments == orig_args) {
4487 arguments = new Arguments (orig_args.Count);
4488 arguments.AddRange (orig_args);
4491 arguments[index] = arguments[i];
4492 arguments[i] = temp;
4499 arg_count = arguments.Count;
4501 } else if (arguments != null) {
4502 arg_count = arguments.Count;
4506 // Don't do any expensive checks when the candidate cannot succeed
4508 if (arg_count != param_count && !cpd.HasParams)
4509 return (param_count - arg_count) * 2 + 1;
4511 var dep = candidate.GetMissingDependencies ();
4513 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4518 // 1. Handle generic method using type arguments when specified or type inference
4521 var ms = candidate as MethodSpec;
4522 if (ms != null && ms.IsGeneric) {
4523 if (type_arguments != null) {
4524 var g_args_count = ms.Arity;
4525 if (g_args_count != type_arguments.Count)
4526 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4528 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4531 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4532 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4533 // candidate was found use the set to report more details about what was wrong with lambda body.
4534 // The general idea is to distinguish between code errors and errors caused by
4535 // trial-and-error type inference
4537 if (lambda_conv_msgs == null) {
4538 for (int i = 0; i < arg_count; i++) {
4539 Argument a = arguments[i];
4543 var am = a.Expr as AnonymousMethodExpression;
4545 if (lambda_conv_msgs == null)
4546 lambda_conv_msgs = new SessionReportPrinter ();
4548 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4553 var ti = new TypeInference (arguments);
4554 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4557 return ti.InferenceScore - 20000;
4560 // Clear any error messages when the result was success
4562 if (lambda_conv_msgs != null)
4563 lambda_conv_msgs.ClearSession ();
4565 if (i_args.Length != 0) {
4566 ms = ms.MakeGenericMethod (ec, i_args);
4571 // Type arguments constraints have to match for the method to be applicable
4573 if (!CheckInflatedArguments (ms)) {
4575 return int.MaxValue - 25000;
4579 // We have a generic return type and at same time the method is override which
4580 // means we have to also inflate override return type in case the candidate is
4581 // best candidate and override return type is different to base return type.
4583 // virtual Foo<T, object> with override Foo<T, dynamic>
4585 if (candidate != pm) {
4586 MethodSpec override_ms = (MethodSpec) pm;
4587 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4588 returnType = inflator.Inflate (returnType);
4590 returnType = ms.ReturnType;
4597 if (type_arguments != null)
4598 return int.MaxValue - 15000;
4604 // 2. Each argument has to be implicitly convertible to method parameter
4606 Parameter.Modifier p_mod = 0;
4609 for (int i = 0; i < arg_count; i++) {
4610 Argument a = arguments[i];
4612 var fp = pd.FixedParameters[i];
4613 if (!fp.HasDefaultValue) {
4614 arguments = orig_args;
4615 return arg_count * 2 + 2;
4619 // Get the default value expression, we can use the same expression
4620 // if the type matches
4622 Expression e = fp.DefaultValue;
4624 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4626 // Restore for possible error reporting
4627 for (int ii = i; ii < arg_count; ++ii)
4628 arguments.RemoveAt (i);
4630 return (arg_count - i) * 2 + 1;
4634 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4636 // LAMESPEC: Attributes can be mixed together with build-in priority
4638 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4639 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4640 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4641 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4642 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4643 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4647 arguments[i] = new Argument (e, Argument.AType.Default);
4651 if (p_mod != Parameter.Modifier.PARAMS) {
4652 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4654 } else if (!params_expanded_form) {
4655 params_expanded_form = true;
4656 pt = ((ElementTypeSpec) pt).Element;
4662 if (!params_expanded_form) {
4663 if (a.ArgType == Argument.AType.ExtensionType) {
4665 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4667 // LAMESPEC: or implicit type parameter conversion
4670 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4671 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4672 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4677 score = IsArgumentCompatible (ec, a, p_mod, pt);
4680 dynamicArgument = true;
4685 // It can be applicable in expanded form (when not doing exact match like for delegates)
4687 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4688 if (!params_expanded_form) {
4689 pt = ((ElementTypeSpec) pt).Element;
4693 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4696 params_expanded_form = true;
4697 dynamicArgument = true;
4698 } else if (score == 0 || arg_count > pd.Count) {
4699 params_expanded_form = true;
4704 if (params_expanded_form)
4706 return (arg_count - i) * 2 + score;
4711 // When params parameter has no argument it will be provided later if the method is the best candidate
4713 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4714 params_expanded_form = true;
4717 // Restore original arguments for dynamic binder to keep the intention of original source code
4719 if (dynamicArgument)
4720 arguments = orig_args;
4725 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4727 if (e is Constant && e.Type == ptype)
4731 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4733 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4734 e = new MemberAccess (new MemberAccess (new MemberAccess (
4735 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4736 } else if (e is Constant) {
4738 // Handles int to int? conversions, DefaultParameterValue check
4740 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4744 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4747 return e.Resolve (ec);
4751 // Tests argument compatibility with the parameter
4752 // The possible return values are
4754 // 1 - modifier mismatch
4755 // 2 - type mismatch
4756 // -1 - dynamic binding required
4758 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4761 // Types have to be identical when ref or out modifer
4762 // is used and argument is not of dynamic type
4764 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4765 if (argument.Type != parameter) {
4767 // Do full equality check after quick path
4769 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4771 // Using dynamic for ref/out parameter can still succeed at runtime
4773 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4780 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4782 // Using dynamic for ref/out parameter can still succeed at runtime
4784 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4791 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4795 // Use implicit conversion in all modes to return same candidates when the expression
4796 // is used as argument or delegate conversion
4798 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4799 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4806 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4808 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4810 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4813 var ac_p = p as ArrayContainer;
4815 var ac_q = q as ArrayContainer;
4819 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4820 if (specific == ac_p.Element)
4822 if (specific == ac_q.Element)
4824 } else if (p.IsGeneric && q.IsGeneric) {
4825 var pargs = TypeManager.GetTypeArguments (p);
4826 var qargs = TypeManager.GetTypeArguments (q);
4828 bool p_specific_at_least_once = false;
4829 bool q_specific_at_least_once = false;
4831 for (int i = 0; i < pargs.Length; i++) {
4832 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4833 if (specific == pargs[i])
4834 p_specific_at_least_once = true;
4835 if (specific == qargs[i])
4836 q_specific_at_least_once = true;
4839 if (p_specific_at_least_once && !q_specific_at_least_once)
4841 if (!p_specific_at_least_once && q_specific_at_least_once)
4849 // Find the best method from candidate list
4851 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4853 List<AmbiguousCandidate> ambiguous_candidates = null;
4855 MemberSpec best_candidate;
4856 Arguments best_candidate_args = null;
4857 bool best_candidate_params = false;
4858 bool best_candidate_dynamic = false;
4859 int best_candidate_rate;
4860 IParametersMember best_parameter_member = null;
4862 int args_count = args != null ? args.Count : 0;
4864 Arguments candidate_args = args;
4865 bool error_mode = false;
4866 MemberSpec invocable_member = null;
4869 best_candidate = null;
4870 best_candidate_rate = int.MaxValue;
4872 var type_members = members;
4874 for (int i = 0; i < type_members.Count; ++i) {
4875 var member = type_members[i];
4878 // Methods in a base class are not candidates if any method in a derived
4879 // class is applicable
4881 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4885 if (!member.IsAccessible (rc))
4888 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4891 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4892 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4897 IParametersMember pm = member as IParametersMember;
4900 // Will use it later to report ambiguity between best method and invocable member
4902 if (Invocation.IsMemberInvocable (member))
4903 invocable_member = member;
4909 // Overload resolution is looking for base member but using parameter names
4910 // and default values from the closest member. That means to do expensive lookup
4911 // for the closest override for virtual or abstract members
4913 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4914 var override_params = base_provider.GetOverrideMemberParameters (member);
4915 if (override_params != null)
4916 pm = override_params;
4920 // Check if the member candidate is applicable
4922 bool params_expanded_form = false;
4923 bool dynamic_argument = false;
4924 TypeSpec rt = pm.MemberType;
4925 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4927 if (lambda_conv_msgs != null)
4928 lambda_conv_msgs.EndSession ();
4931 // How does it score compare to others
4933 if (candidate_rate < best_candidate_rate) {
4935 // Fatal error (missing dependency), cannot continue
4936 if (candidate_rate < 0)
4939 best_candidate_rate = candidate_rate;
4940 best_candidate = member;
4941 best_candidate_args = candidate_args;
4942 best_candidate_params = params_expanded_form;
4943 best_candidate_dynamic = dynamic_argument;
4944 best_parameter_member = pm;
4945 best_candidate_return_type = rt;
4946 } else if (candidate_rate == 0) {
4948 // The member look is done per type for most operations but sometimes
4949 // it's not possible like for binary operators overload because they
4950 // are unioned between 2 sides
4952 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4953 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4958 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4960 // We pack all interface members into top level type which makes the overload resolution
4961 // more complicated for interfaces. We compensate it by removing methods with same
4962 // signature when building the cache hence this path should not really be hit often
4965 // interface IA { void Foo (int arg); }
4966 // interface IB : IA { void Foo (params int[] args); }
4968 // IB::Foo is the best overload when calling IB.Foo (1)
4971 if (ambiguous_candidates != null) {
4972 foreach (var amb_cand in ambiguous_candidates) {
4973 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4982 ambiguous_candidates = null;
4985 // Is the new candidate better
4986 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4990 best_candidate = member;
4991 best_candidate_args = candidate_args;
4992 best_candidate_params = params_expanded_form;
4993 best_candidate_dynamic = dynamic_argument;
4994 best_parameter_member = pm;
4995 best_candidate_return_type = rt;
4997 // It's not better but any other found later could be but we are not sure yet
4998 if (ambiguous_candidates == null)
4999 ambiguous_candidates = new List<AmbiguousCandidate> ();
5001 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5005 // Restore expanded arguments
5006 if (candidate_args != args)
5007 candidate_args = args;
5009 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5012 // We've found exact match
5014 if (best_candidate_rate == 0)
5018 // Try extension methods lookup when no ordinary method match was found and provider enables it
5021 var emg = base_provider.LookupExtensionMethod (rc);
5023 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5025 best_candidate_extension_group = emg;
5026 return (T) (MemberSpec) emg.BestCandidate;
5031 // Don't run expensive error reporting mode for probing
5038 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5041 lambda_conv_msgs = null;
5046 // No best member match found, report an error
5048 if (best_candidate_rate != 0 || error_mode) {
5049 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5053 if (best_candidate_dynamic) {
5054 if (args[0].ArgType == Argument.AType.ExtensionType) {
5055 rc.Report.Error (1973, loc,
5056 "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",
5057 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5061 // Check type constraints only when explicit type arguments are used
5063 if (best_candidate.IsGeneric && type_arguments != null) {
5064 MethodSpec bc = best_candidate as MethodSpec;
5065 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5066 ConstraintChecker cc = new ConstraintChecker (rc);
5067 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5071 BestCandidateIsDynamic = true;
5076 // These flags indicates we are running delegate probing conversion. No need to
5077 // do more expensive checks
5079 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5080 return (T) best_candidate;
5082 if (ambiguous_candidates != null) {
5084 // Now check that there are no ambiguities i.e the selected method
5085 // should be better than all the others
5087 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5088 var candidate = ambiguous_candidates [ix];
5090 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5091 var ambiguous = candidate.Member;
5092 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5093 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5094 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5095 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5096 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5099 return (T) best_candidate;
5104 if (invocable_member != null && !IsProbingOnly) {
5105 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5106 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5107 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5108 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5112 // And now check if the arguments are all
5113 // compatible, perform conversions if
5114 // necessary etc. and return if everything is
5117 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5120 if (best_candidate == null)
5124 // Don't run possibly expensive checks in probing mode
5126 if (!IsProbingOnly && !rc.IsInProbingMode) {
5128 // Check ObsoleteAttribute on the best method
5130 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5131 if (oa != null && !rc.IsObsolete)
5132 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5134 best_candidate.MemberDefinition.SetIsUsed ();
5137 args = best_candidate_args;
5138 return (T) best_candidate;
5141 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5143 return ResolveMember<MethodSpec> (rc, ref args);
5146 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5147 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5149 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5152 if (a.Type == InternalType.ErrorType)
5155 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5156 ec.Report.SymbolRelatedToPreviousError (method);
5157 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5158 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5159 TypeManager.CSharpSignature (method));
5162 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5163 TypeManager.CSharpSignature (method));
5164 } else if (IsDelegateInvoke) {
5165 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5166 DelegateType.GetSignatureForError ());
5168 ec.Report.SymbolRelatedToPreviousError (method);
5169 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5170 method.GetSignatureForError ());
5173 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5175 string index = (idx + 1).ToString ();
5176 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5177 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5178 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5179 index, Parameter.GetModifierSignature (a.Modifier));
5181 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5182 index, Parameter.GetModifierSignature (mod));
5184 string p1 = a.GetSignatureForError ();
5185 string p2 = paramType.GetSignatureForError ();
5188 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5189 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5192 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5193 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5194 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5197 ec.Report.Error (1503, a.Expr.Location,
5198 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5203 // We have failed to find exact match so we return error info about the closest match
5205 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5207 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5208 int arg_count = args == null ? 0 : args.Count;
5210 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5211 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5212 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5216 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5221 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5222 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5223 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5227 // For candidates which match on parameters count report more details about incorrect arguments
5230 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5231 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5232 // Reject any inaccessible member
5233 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5234 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5235 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5239 var ms = best_candidate as MethodSpec;
5240 if (ms != null && ms.IsGeneric) {
5241 bool constr_ok = true;
5242 if (ms.TypeArguments != null)
5243 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5245 if (ta_count == 0) {
5246 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5250 rc.Report.Error (411, loc,
5251 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5252 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5259 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5265 // We failed to find any method with correct argument count, report best candidate
5267 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5270 if (best_candidate.Kind == MemberKind.Constructor) {
5271 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5272 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5273 } else if (IsDelegateInvoke) {
5274 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5275 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5276 DelegateType.GetSignatureForError (), arg_count.ToString ());
5278 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5279 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5280 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5281 name, arg_count.ToString ());
5285 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5287 var pd = pm.Parameters;
5288 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5290 Parameter.Modifier p_mod = 0;
5292 int a_idx = 0, a_pos = 0;
5294 ArrayInitializer params_initializers = null;
5295 bool has_unsafe_arg = pm.MemberType.IsPointer;
5296 int arg_count = args == null ? 0 : args.Count;
5298 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5303 if (p_mod != Parameter.Modifier.PARAMS) {
5304 p_mod = pd.FixedParameters[a_idx].ModFlags;
5306 has_unsafe_arg |= pt.IsPointer;
5308 if (p_mod == Parameter.Modifier.PARAMS) {
5309 if (chose_params_expanded) {
5310 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5311 pt = TypeManager.GetElementType (pt);
5317 // Types have to be identical when ref or out modifer is used
5319 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5320 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5323 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5329 NamedArgument na = a as NamedArgument;
5331 int name_index = pd.GetParameterIndexByName (na.Name);
5332 if (name_index < 0 || name_index >= pd.Count) {
5333 if (IsDelegateInvoke) {
5334 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5335 ec.Report.Error (1746, na.Location,
5336 "The delegate `{0}' does not contain a parameter named `{1}'",
5337 DelegateType.GetSignatureForError (), na.Name);
5339 ec.Report.SymbolRelatedToPreviousError (member);
5340 ec.Report.Error (1739, na.Location,
5341 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5342 TypeManager.CSharpSignature (member), na.Name);
5344 } else if (args[name_index] != a) {
5345 if (IsDelegateInvoke)
5346 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5348 ec.Report.SymbolRelatedToPreviousError (member);
5350 ec.Report.Error (1744, na.Location,
5351 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5356 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5359 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5360 custom_errors.NoArgumentMatch (ec, member);
5365 if (a.ArgType == Argument.AType.ExtensionType) {
5366 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5369 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5371 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5374 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5381 // Convert params arguments to an array initializer
5383 if (params_initializers != null) {
5384 // we choose to use 'a.Expr' rather than 'conv' so that
5385 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5386 params_initializers.Add (a.Expr);
5387 args.RemoveAt (a_idx--);
5393 // Update the argument with the implicit conversion
5397 if (a_idx != arg_count) {
5398 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5403 // Fill not provided arguments required by params modifier
5405 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5407 args = new Arguments (1);
5409 pt = ptypes[pd.Count - 1];
5410 pt = TypeManager.GetElementType (pt);
5411 has_unsafe_arg |= pt.IsPointer;
5412 params_initializers = new ArrayInitializer (0, loc);
5416 // Append an array argument with all params arguments
5418 if (params_initializers != null) {
5419 args.Add (new Argument (
5420 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5424 if (has_unsafe_arg && !ec.IsUnsafe) {
5425 Expression.UnsafeError (ec, loc);
5429 // We could infer inaccesible type arguments
5431 if (type_arguments == null && member.IsGeneric) {
5432 var ms = (MethodSpec) member;
5433 foreach (var ta in ms.TypeArguments) {
5434 if (!ta.IsAccessible (ec)) {
5435 ec.Report.SymbolRelatedToPreviousError (ta);
5436 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5446 public class ConstantExpr : MemberExpr
5448 readonly ConstSpec constant;
5450 public ConstantExpr (ConstSpec constant, Location loc)
5452 this.constant = constant;
5456 public override string Name {
5457 get { throw new NotImplementedException (); }
5460 public override string KindName {
5461 get { return "constant"; }
5464 public override bool IsInstance {
5465 get { return !IsStatic; }
5468 public override bool IsStatic {
5469 get { return true; }
5472 protected override TypeSpec DeclaringType {
5473 get { return constant.DeclaringType; }
5476 public override Expression CreateExpressionTree (ResolveContext ec)
5478 throw new NotSupportedException ("ET");
5481 protected override Expression DoResolve (ResolveContext rc)
5483 ResolveInstanceExpression (rc, null);
5484 DoBestMemberChecks (rc, constant);
5486 var c = constant.GetConstant (rc);
5488 // Creates reference expression to the constant value
5489 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5492 public override void Emit (EmitContext ec)
5494 throw new NotSupportedException ();
5497 public override string GetSignatureForError ()
5499 return constant.GetSignatureForError ();
5502 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5504 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5509 // Fully resolved expression that references a Field
5511 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5513 protected FieldSpec spec;
5514 VariableInfo variable_info;
5516 LocalTemporary temp;
5519 protected FieldExpr (Location l)
5524 public FieldExpr (FieldSpec spec, Location loc)
5529 type = spec.MemberType;
5532 public FieldExpr (FieldBase fi, Location l)
5539 public override string Name {
5545 public bool IsHoisted {
5547 IVariableReference hv = InstanceExpression as IVariableReference;
5548 return hv != null && hv.IsHoisted;
5552 public override bool IsInstance {
5554 return !spec.IsStatic;
5558 public override bool IsStatic {
5560 return spec.IsStatic;
5564 public override string KindName {
5565 get { return "field"; }
5568 public FieldSpec Spec {
5574 protected override TypeSpec DeclaringType {
5576 return spec.DeclaringType;
5580 public VariableInfo VariableInfo {
5582 return variable_info;
5588 public override string GetSignatureForError ()
5590 return spec.GetSignatureForError ();
5593 public bool IsMarshalByRefAccess (ResolveContext rc)
5595 // Checks possible ldflda of field access expression
5596 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5597 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5598 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5601 public void SetHasAddressTaken ()
5603 IVariableReference vr = InstanceExpression as IVariableReference;
5605 vr.SetHasAddressTaken ();
5609 public override Expression CreateExpressionTree (ResolveContext ec)
5611 return CreateExpressionTree (ec, true);
5614 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5617 Expression instance;
5619 if (InstanceExpression == null) {
5620 instance = new NullLiteral (loc);
5621 } else if (convertInstance) {
5622 instance = InstanceExpression.CreateExpressionTree (ec);
5624 args = new Arguments (1);
5625 args.Add (new Argument (InstanceExpression));
5626 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5629 args = Arguments.CreateForExpressionTree (ec, null,
5631 CreateTypeOfExpression ());
5633 return CreateExpressionFactoryCall (ec, "Field", args);
5636 public Expression CreateTypeOfExpression ()
5638 return new TypeOfField (spec, loc);
5641 protected override Expression DoResolve (ResolveContext ec)
5643 spec.MemberDefinition.SetIsUsed ();
5645 return DoResolve (ec, null);
5648 Expression DoResolve (ResolveContext ec, Expression rhs)
5650 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5653 if (ResolveInstanceExpression (ec, rhs)) {
5654 // Resolve the field's instance expression while flow analysis is turned
5655 // off: when accessing a field "a.b", we must check whether the field
5656 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5658 if (lvalue_instance) {
5659 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5660 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5662 Expression right_side =
5663 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5665 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5668 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5669 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5673 if (InstanceExpression == null)
5677 DoBestMemberChecks (ec, spec);
5680 var fb = spec as FixedFieldSpec;
5681 IVariableReference var = InstanceExpression as IVariableReference;
5683 if (lvalue_instance && var != null && var.VariableInfo != null) {
5684 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5688 IFixedExpression fe = InstanceExpression as IFixedExpression;
5689 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5690 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5693 if (InstanceExpression.eclass != ExprClass.Variable) {
5694 ec.Report.SymbolRelatedToPreviousError (spec);
5695 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5696 TypeManager.GetFullNameSignature (spec));
5697 } else if (var != null && var.IsHoisted) {
5698 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5701 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5705 // Set flow-analysis variable info for struct member access. It will be check later
5706 // for precise error reporting
5708 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5709 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5710 if (rhs != null && variable_info != null)
5711 variable_info.SetStructFieldAssigned (ec, Name);
5714 eclass = ExprClass.Variable;
5718 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5723 var var = fe.InstanceExpression as IVariableReference;
5725 var vi = var.VariableInfo;
5727 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5729 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5731 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5738 fe = fe.InstanceExpression as FieldExpr;
5740 } while (fe != null);
5743 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5745 // The return value is always null. Returning a value simplifies calling code.
5747 if (right_side == EmptyExpression.OutAccess) {
5749 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5750 GetSignatureForError ());
5752 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5753 GetSignatureForError ());
5759 if (right_side == EmptyExpression.LValueMemberAccess) {
5760 // Already reported as CS1648/CS1650
5764 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5766 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5767 GetSignatureForError ());
5769 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5770 GetSignatureForError ());
5777 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5778 GetSignatureForError ());
5780 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5781 GetSignatureForError ());
5787 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5789 if (spec is FixedFieldSpec) {
5790 // It could be much better error message but we want to be error compatible
5791 Error_ValueAssignment (ec, right_side);
5794 Expression e = DoResolve (ec, right_side);
5799 spec.MemberDefinition.SetIsAssigned ();
5801 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5802 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5803 ec.Report.Warning (420, 1, loc,
5804 "`{0}': A volatile field references will not be treated as volatile",
5805 spec.GetSignatureForError ());
5808 if (spec.IsReadOnly) {
5809 // InitOnly fields can only be assigned in constructors or initializers
5810 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5811 return Error_AssignToReadonly (ec, right_side);
5813 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5815 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5816 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5817 return Error_AssignToReadonly (ec, right_side);
5818 // static InitOnly fields cannot be assigned-to in an instance constructor
5819 if (IsStatic && !ec.IsStatic)
5820 return Error_AssignToReadonly (ec, right_side);
5821 // instance constructors can't modify InitOnly fields of other instances of the same type
5822 if (!IsStatic && !(InstanceExpression is This))
5823 return Error_AssignToReadonly (ec, right_side);
5827 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5828 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5829 ec.Report.Warning (197, 1, loc,
5830 "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",
5831 GetSignatureForError ());
5834 eclass = ExprClass.Variable;
5838 public override int GetHashCode ()
5840 return spec.GetHashCode ();
5843 public bool IsFixed {
5846 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5848 IVariableReference variable = InstanceExpression as IVariableReference;
5849 if (variable != null)
5850 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5852 IFixedExpression fe = InstanceExpression as IFixedExpression;
5853 return fe != null && fe.IsFixed;
5857 public override bool Equals (object obj)
5859 FieldExpr fe = obj as FieldExpr;
5863 if (spec != fe.spec)
5866 if (InstanceExpression == null || fe.InstanceExpression == null)
5869 return InstanceExpression.Equals (fe.InstanceExpression);
5872 public void Emit (EmitContext ec, bool leave_copy)
5874 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5878 ec.Emit (OpCodes.Volatile);
5880 ec.Emit (OpCodes.Ldsfld, spec);
5883 EmitInstance (ec, false);
5885 // Optimization for build-in types
5886 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5887 ec.EmitLoadFromPtr (type);
5889 var ff = spec as FixedFieldSpec;
5891 ec.Emit (OpCodes.Ldflda, spec);
5892 ec.Emit (OpCodes.Ldflda, ff.Element);
5895 ec.Emit (OpCodes.Volatile);
5897 ec.Emit (OpCodes.Ldfld, spec);
5903 ec.Emit (OpCodes.Dup);
5905 temp = new LocalTemporary (this.Type);
5911 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5913 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5914 if (isCompound && !(source is DynamicExpressionStatement)) {
5915 if (has_await_source) {
5917 InstanceExpression = InstanceExpression.EmitToField (ec);
5924 if (has_await_source)
5925 source = source.EmitToField (ec);
5927 EmitInstance (ec, prepared);
5933 ec.Emit (OpCodes.Dup);
5935 temp = new LocalTemporary (this.Type);
5940 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5941 ec.Emit (OpCodes.Volatile);
5943 spec.MemberDefinition.SetIsAssigned ();
5946 ec.Emit (OpCodes.Stsfld, spec);
5948 ec.Emit (OpCodes.Stfld, spec);
5958 // Emits store to field with prepared values on stack
5960 public void EmitAssignFromStack (EmitContext ec)
5963 ec.Emit (OpCodes.Stsfld, spec);
5965 ec.Emit (OpCodes.Stfld, spec);
5969 public override void Emit (EmitContext ec)
5974 public override void EmitSideEffect (EmitContext ec)
5976 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5978 if (is_volatile) // || is_marshal_by_ref ())
5979 base.EmitSideEffect (ec);
5982 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5984 if ((mode & AddressOp.Store) != 0)
5985 spec.MemberDefinition.SetIsAssigned ();
5986 if ((mode & AddressOp.Load) != 0)
5987 spec.MemberDefinition.SetIsUsed ();
5990 // Handle initonly fields specially: make a copy and then
5991 // get the address of the copy.
5994 if (spec.IsReadOnly){
5996 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6008 var temp = ec.GetTemporaryLocal (type);
6009 ec.Emit (OpCodes.Stloc, temp);
6010 ec.Emit (OpCodes.Ldloca, temp);
6011 ec.FreeTemporaryLocal (temp, type);
6017 ec.Emit (OpCodes.Ldsflda, spec);
6020 EmitInstance (ec, false);
6021 ec.Emit (OpCodes.Ldflda, spec);
6025 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6027 return MakeExpression (ctx);
6030 public override SLE.Expression MakeExpression (BuilderContext ctx)
6033 return base.MakeExpression (ctx);
6035 return SLE.Expression.Field (
6036 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6037 spec.GetMetaInfo ());
6041 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6043 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6049 // Expression that evaluates to a Property.
6051 // This is not an LValue because we need to re-write the expression. We
6052 // can not take data from the stack and store it.
6054 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6056 Arguments arguments;
6058 public PropertyExpr (PropertySpec spec, Location l)
6061 best_candidate = spec;
6062 type = spec.MemberType;
6067 protected override Arguments Arguments {
6076 protected override TypeSpec DeclaringType {
6078 return best_candidate.DeclaringType;
6082 public override string Name {
6084 return best_candidate.Name;
6088 public override bool IsInstance {
6094 public override bool IsStatic {
6096 return best_candidate.IsStatic;
6100 public override string KindName {
6101 get { return "property"; }
6104 public PropertySpec PropertyInfo {
6106 return best_candidate;
6112 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6114 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6117 var args_count = arguments == null ? 0 : arguments.Count;
6118 if (args_count != body.Parameters.Count && args_count == 0)
6121 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6122 mg.InstanceExpression = InstanceExpression;
6127 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6129 return new PropertyExpr (spec, loc) {
6135 public override Expression CreateExpressionTree (ResolveContext ec)
6138 if (IsSingleDimensionalArrayLength ()) {
6139 args = new Arguments (1);
6140 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6141 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6144 args = new Arguments (2);
6145 if (InstanceExpression == null)
6146 args.Add (new Argument (new NullLiteral (loc)));
6148 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6149 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6150 return CreateExpressionFactoryCall (ec, "Property", args);
6153 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6155 DoResolveLValue (rc, null);
6156 return new TypeOfMethod (Setter, loc);
6159 public override string GetSignatureForError ()
6161 return best_candidate.GetSignatureForError ();
6164 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6167 return base.MakeExpression (ctx);
6169 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6173 public override SLE.Expression MakeExpression (BuilderContext ctx)
6176 return base.MakeExpression (ctx);
6178 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6182 void Error_PropertyNotValid (ResolveContext ec)
6184 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6185 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6186 GetSignatureForError ());
6189 bool IsSingleDimensionalArrayLength ()
6191 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6194 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6195 return ac != null && ac.Rank == 1;
6198 public override void Emit (EmitContext ec, bool leave_copy)
6201 // Special case: length of single dimension array property is turned into ldlen
6203 if (IsSingleDimensionalArrayLength ()) {
6204 EmitInstance (ec, false);
6205 ec.Emit (OpCodes.Ldlen);
6206 ec.Emit (OpCodes.Conv_I4);
6210 base.Emit (ec, leave_copy);
6213 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6216 LocalTemporary await_source_arg = null;
6218 if (isCompound && !(source is DynamicExpressionStatement)) {
6219 emitting_compound_assignment = true;
6222 if (has_await_arguments) {
6223 await_source_arg = new LocalTemporary (Type);
6224 await_source_arg.Store (ec);
6226 args = new Arguments (1);
6227 args.Add (new Argument (await_source_arg));
6230 temp = await_source_arg;
6233 has_await_arguments = false;
6238 ec.Emit (OpCodes.Dup);
6239 temp = new LocalTemporary (this.Type);
6244 args = arguments ?? new Arguments (1);
6248 temp = new LocalTemporary (this.Type);
6250 args.Add (new Argument (temp));
6252 args.Add (new Argument (source));
6256 emitting_compound_assignment = false;
6258 var call = new CallEmitter ();
6259 call.InstanceExpression = InstanceExpression;
6261 call.InstanceExpressionOnStack = true;
6263 call.Emit (ec, Setter, args, loc);
6270 if (await_source_arg != null) {
6271 await_source_arg.Release (ec);
6275 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6277 eclass = ExprClass.PropertyAccess;
6279 if (best_candidate.IsNotCSharpCompatible) {
6280 Error_PropertyNotValid (rc);
6283 ResolveInstanceExpression (rc, right_side);
6285 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6286 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6287 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6289 type = p.MemberType;
6293 DoBestMemberChecks (rc, best_candidate);
6295 // Handling of com-imported properties with any number of default property parameters
6296 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6297 var p = best_candidate.Get.Parameters;
6298 arguments = new Arguments (p.Count);
6299 for (int i = 0; i < p.Count; ++i) {
6300 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6302 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6303 var p = best_candidate.Set.Parameters;
6304 arguments = new Arguments (p.Count - 1);
6305 for (int i = 0; i < p.Count - 1; ++i) {
6306 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6313 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6315 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6319 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6321 // getter and setter can be different for base calls
6322 MethodSpec getter, setter;
6323 protected T best_candidate;
6325 protected LocalTemporary temp;
6326 protected bool emitting_compound_assignment;
6327 protected bool has_await_arguments;
6329 protected PropertyOrIndexerExpr (Location l)
6336 protected abstract Arguments Arguments { get; set; }
6338 public MethodSpec Getter {
6347 public MethodSpec Setter {
6358 protected override Expression DoResolve (ResolveContext ec)
6360 if (eclass == ExprClass.Unresolved) {
6361 var expr = OverloadResolve (ec, null);
6366 return expr.Resolve (ec);
6369 if (!ResolveGetter (ec))
6375 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6377 if (right_side == EmptyExpression.OutAccess) {
6378 // TODO: best_candidate can be null at this point
6379 INamedBlockVariable variable = null;
6380 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6381 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6382 best_candidate.Name);
6384 right_side.DoResolveLValue (ec, this);
6389 if (eclass == ExprClass.Unresolved) {
6390 var expr = OverloadResolve (ec, right_side);
6395 return expr.ResolveLValue (ec, right_side);
6398 if (!ResolveSetter (ec))
6405 // Implements the IAssignMethod interface for assignments
6407 public virtual void Emit (EmitContext ec, bool leave_copy)
6409 var call = new CallEmitter ();
6410 call.InstanceExpression = InstanceExpression;
6411 if (has_await_arguments)
6412 call.HasAwaitArguments = true;
6414 call.DuplicateArguments = emitting_compound_assignment;
6416 call.Emit (ec, Getter, Arguments, loc);
6418 if (call.HasAwaitArguments) {
6419 InstanceExpression = call.InstanceExpression;
6420 Arguments = call.EmittedArguments;
6421 has_await_arguments = true;
6425 ec.Emit (OpCodes.Dup);
6426 temp = new LocalTemporary (Type);
6431 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6433 public override void Emit (EmitContext ec)
6438 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6440 has_await_arguments = true;
6445 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6447 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6449 bool ResolveGetter (ResolveContext rc)
6451 if (!best_candidate.HasGet) {
6452 if (InstanceExpression != EmptyExpression.Null) {
6453 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6454 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6455 best_candidate.GetSignatureForError ());
6458 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6459 if (best_candidate.HasDifferentAccessibility) {
6460 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6461 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6462 TypeManager.CSharpSignature (best_candidate));
6464 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6465 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6469 if (best_candidate.HasDifferentAccessibility) {
6470 CheckProtectedMemberAccess (rc, best_candidate.Get);
6473 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6477 bool ResolveSetter (ResolveContext rc)
6479 if (!best_candidate.HasSet) {
6480 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6481 GetSignatureForError ());
6485 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6486 if (best_candidate.HasDifferentAccessibility) {
6487 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6488 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6489 GetSignatureForError ());
6491 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6492 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6496 if (best_candidate.HasDifferentAccessibility)
6497 CheckProtectedMemberAccess (rc, best_candidate.Set);
6499 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6505 /// Fully resolved expression that evaluates to an Event
6507 public class EventExpr : MemberExpr, IAssignMethod
6509 readonly EventSpec spec;
6512 public EventExpr (EventSpec spec, Location loc)
6520 protected override TypeSpec DeclaringType {
6522 return spec.DeclaringType;
6526 public override string Name {
6532 public override bool IsInstance {
6534 return !spec.IsStatic;
6538 public override bool IsStatic {
6540 return spec.IsStatic;
6544 public override string KindName {
6545 get { return "event"; }
6548 public MethodSpec Operator {
6556 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6559 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6561 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6562 if (spec.BackingField != null &&
6563 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6565 spec.MemberDefinition.SetIsUsed ();
6567 if (!ec.IsObsolete) {
6568 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6570 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6573 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6574 Error_AssignmentEventOnly (ec);
6576 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6578 InstanceExpression = null;
6580 return ml.ResolveMemberAccess (ec, left, original);
6584 return base.ResolveMemberAccess (ec, left, original);
6587 public override Expression CreateExpressionTree (ResolveContext ec)
6589 throw new NotSupportedException ("ET");
6592 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6594 if (right_side == EmptyExpression.EventAddition) {
6595 op = spec.AccessorAdd;
6596 } else if (right_side == EmptyExpression.EventSubtraction) {
6597 op = spec.AccessorRemove;
6601 Error_AssignmentEventOnly (ec);
6605 op = CandidateToBaseOverride (ec, op);
6609 protected override Expression DoResolve (ResolveContext ec)
6611 eclass = ExprClass.EventAccess;
6612 type = spec.MemberType;
6614 ResolveInstanceExpression (ec, null);
6616 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6617 Error_AssignmentEventOnly (ec);
6620 DoBestMemberChecks (ec, spec);
6624 public override void Emit (EmitContext ec)
6626 throw new NotSupportedException ();
6627 //Error_CannotAssign ();
6630 #region IAssignMethod Members
6632 public void Emit (EmitContext ec, bool leave_copy)
6634 throw new NotImplementedException ();
6637 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6639 if (leave_copy || !isCompound)
6640 throw new NotImplementedException ("EventExpr::EmitAssign");
6642 Arguments args = new Arguments (1);
6643 args.Add (new Argument (source));
6645 var call = new CallEmitter ();
6646 call.InstanceExpression = InstanceExpression;
6647 call.Emit (ec, op, args, loc);
6652 void Error_AssignmentEventOnly (ResolveContext ec)
6654 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6655 ec.Report.Error (79, loc,
6656 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6657 GetSignatureForError ());
6659 ec.Report.Error (70, loc,
6660 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6661 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6665 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6667 name = name.Substring (0, name.LastIndexOf ('.'));
6668 base.Error_CannotCallAbstractBase (rc, name);
6671 public override string GetSignatureForError ()
6673 return TypeManager.CSharpSignature (spec);
6676 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6678 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6682 public class TemporaryVariableReference : VariableReference
6684 public class Declarator : Statement
6686 TemporaryVariableReference variable;
6688 public Declarator (TemporaryVariableReference variable)
6690 this.variable = variable;
6694 protected override void DoEmit (EmitContext ec)
6696 variable.li.CreateBuilder (ec);
6699 public override void Emit (EmitContext ec)
6701 // Don't create sequence point
6705 protected override void CloneTo (CloneContext clonectx, Statement target)
6713 public TemporaryVariableReference (LocalVariable li, Location loc)
6716 this.type = li.Type;
6720 public override bool IsLockedByStatement {
6728 public LocalVariable LocalInfo {
6734 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6736 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6737 return new TemporaryVariableReference (li, loc);
6740 protected override Expression DoResolve (ResolveContext ec)
6742 eclass = ExprClass.Variable;
6745 // Don't capture temporary variables except when using
6746 // state machine redirection and block yields
6748 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6749 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6750 ec.IsVariableCapturingRequired) {
6751 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6752 storey.CaptureLocalVariable (ec, li);
6758 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6760 return Resolve (ec);
6763 public override void Emit (EmitContext ec)
6765 li.CreateBuilder (ec);
6770 public void EmitAssign (EmitContext ec, Expression source)
6772 li.CreateBuilder (ec);
6774 EmitAssign (ec, source, false, false);
6777 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6779 return li.HoistedVariant;
6782 public override bool IsFixed {
6783 get { return true; }
6786 public override bool IsRef {
6787 get { return false; }
6790 public override string Name {
6791 get { throw new NotImplementedException (); }
6794 public override void SetHasAddressTaken ()
6796 throw new NotImplementedException ();
6799 protected override ILocalVariable Variable {
6803 public override VariableInfo VariableInfo {
6804 get { return null; }
6807 public override void VerifyAssigned (ResolveContext rc)
6813 /// Handles `var' contextual keyword; var becomes a keyword only
6814 /// if no type called var exists in a variable scope
6816 class VarExpr : SimpleName
6818 public VarExpr (Location loc)
6823 public bool InferType (ResolveContext ec, Expression right_side)
6826 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6828 type = right_side.Type;
6829 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6830 ec.Report.Error (815, loc,
6831 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6832 type.GetSignatureForError ());
6836 eclass = ExprClass.Variable;
6840 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6842 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6843 base.Error_TypeOrNamespaceNotFound (ec);
6845 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");