2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public 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 static 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 Expression OriginalExpression {
2066 public override Constant ConvertImplicitly (TypeSpec target_type)
2068 Constant c = base.ConvertImplicitly (target_type);
2070 c = new ReducedConstantExpression (c, orig_expr);
2075 public override Expression CreateExpressionTree (ResolveContext ec)
2077 return orig_expr.CreateExpressionTree (ec);
2080 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2082 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2084 c = new ReducedConstantExpression (c, orig_expr);
2088 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2091 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2093 if (orig_expr is Conditional)
2094 child.EncodeAttributeValue (rc, enc, targetType);
2096 base.EncodeAttributeValue (rc, enc, targetType);
2100 sealed class ReducedExpressionStatement : ExpressionStatement
2102 readonly Expression orig_expr;
2103 readonly ExpressionStatement stm;
2105 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2107 this.orig_expr = orig;
2109 this.eclass = stm.eclass;
2110 this.type = stm.Type;
2112 this.loc = orig.Location;
2115 public override bool ContainsEmitWithAwait ()
2117 return stm.ContainsEmitWithAwait ();
2120 public override Expression CreateExpressionTree (ResolveContext ec)
2122 return orig_expr.CreateExpressionTree (ec);
2125 protected override Expression DoResolve (ResolveContext ec)
2130 public override void Emit (EmitContext ec)
2135 public override void EmitStatement (EmitContext ec)
2137 stm.EmitStatement (ec);
2141 readonly Expression expr, orig_expr;
2143 private ReducedExpression (Expression expr, Expression orig_expr)
2146 this.eclass = expr.eclass;
2147 this.type = expr.Type;
2148 this.orig_expr = orig_expr;
2149 this.loc = orig_expr.Location;
2154 public override bool IsSideEffectFree {
2156 return expr.IsSideEffectFree;
2160 public Expression OriginalExpression {
2168 public override bool ContainsEmitWithAwait ()
2170 return expr.ContainsEmitWithAwait ();
2174 // Creates fully resolved expression switcher
2176 public static Constant Create (Constant expr, Expression original_expr)
2178 if (expr.eclass == ExprClass.Unresolved)
2179 throw new ArgumentException ("Unresolved expression");
2181 return new ReducedConstantExpression (expr, original_expr);
2184 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2186 return new ReducedExpressionStatement (s, orig);
2189 public static Expression Create (Expression expr, Expression original_expr)
2191 return Create (expr, original_expr, true);
2195 // Creates unresolved reduce expression. The original expression has to be
2196 // already resolved. Created expression is constant based based on `expr'
2197 // value unless canBeConstant is used
2199 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2201 if (canBeConstant) {
2202 Constant c = expr as Constant;
2204 return Create (c, original_expr);
2207 ExpressionStatement s = expr as ExpressionStatement;
2209 return Create (s, original_expr);
2211 if (expr.eclass == ExprClass.Unresolved)
2212 throw new ArgumentException ("Unresolved expression");
2214 return new ReducedExpression (expr, original_expr);
2217 public override Expression CreateExpressionTree (ResolveContext ec)
2219 return orig_expr.CreateExpressionTree (ec);
2222 protected override Expression DoResolve (ResolveContext ec)
2227 public override void Emit (EmitContext ec)
2232 public override Expression EmitToField (EmitContext ec)
2234 return expr.EmitToField(ec);
2237 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2239 expr.EmitBranchable (ec, target, on_true);
2242 public override SLE.Expression MakeExpression (BuilderContext ctx)
2244 return orig_expr.MakeExpression (ctx);
2249 // Standard composite pattern
2251 public abstract class CompositeExpression : Expression
2253 protected Expression expr;
2255 protected CompositeExpression (Expression expr)
2258 this.loc = expr.Location;
2261 public override bool ContainsEmitWithAwait ()
2263 return expr.ContainsEmitWithAwait ();
2266 public override Expression CreateExpressionTree (ResolveContext rc)
2268 return expr.CreateExpressionTree (rc);
2271 public Expression Child {
2272 get { return expr; }
2275 protected override Expression DoResolve (ResolveContext rc)
2277 expr = expr.Resolve (rc);
2280 eclass = expr.eclass;
2286 public override void Emit (EmitContext ec)
2291 public override bool IsNull {
2292 get { return expr.IsNull; }
2297 // Base of expressions used only to narrow resolve flow
2299 public abstract class ShimExpression : Expression
2301 protected Expression expr;
2303 protected ShimExpression (Expression expr)
2308 public Expression Expr {
2314 protected override void CloneTo (CloneContext clonectx, Expression t)
2319 ShimExpression target = (ShimExpression) t;
2320 target.expr = expr.Clone (clonectx);
2323 public override bool ContainsEmitWithAwait ()
2325 return expr.ContainsEmitWithAwait ();
2328 public override Expression CreateExpressionTree (ResolveContext ec)
2330 throw new NotSupportedException ("ET");
2333 public override void Emit (EmitContext ec)
2335 throw new InternalErrorException ("Missing Resolve call");
2341 // Unresolved type name expressions
2343 public abstract class ATypeNameExpression : FullNamedExpression
2346 protected TypeArguments targs;
2348 protected ATypeNameExpression (string name, Location l)
2354 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2361 protected ATypeNameExpression (string name, int arity, Location l)
2362 : this (name, new UnboundTypeArguments (arity), l)
2368 protected int Arity {
2370 return targs == null ? 0 : targs.Count;
2374 public bool HasTypeArguments {
2376 return targs != null && !targs.IsEmpty;
2380 public string Name {
2389 public TypeArguments TypeArguments {
2397 public override bool Equals (object obj)
2399 ATypeNameExpression atne = obj as ATypeNameExpression;
2400 return atne != null && atne.Name == Name &&
2401 (targs == null || targs.Equals (atne.targs));
2404 public override int GetHashCode ()
2406 return Name.GetHashCode ();
2409 // TODO: Move it to MemberCore
2410 public static string GetMemberType (MemberCore mc)
2416 if (mc is FieldBase)
2418 if (mc is MethodCore)
2420 if (mc is EnumMember)
2428 public override string GetSignatureForError ()
2430 if (targs != null) {
2431 return Name + "<" + targs.GetSignatureForError () + ">";
2437 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2441 /// SimpleName expressions are formed of a single word and only happen at the beginning
2442 /// of a dotted-name.
2444 public class SimpleName : ATypeNameExpression
2446 public SimpleName (string name, Location l)
2451 public SimpleName (string name, TypeArguments args, Location l)
2452 : base (name, args, l)
2456 public SimpleName (string name, int arity, Location l)
2457 : base (name, arity, l)
2461 public SimpleName GetMethodGroup ()
2463 return new SimpleName (Name, targs, loc);
2466 protected override Expression DoResolve (ResolveContext rc)
2468 var e = SimpleNameResolve (rc, null);
2470 var fe = e as FieldExpr;
2472 fe.VerifyAssignedStructField (rc, null);
2478 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2480 return SimpleNameResolve (ec, right_side);
2483 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2485 if (ctx.CurrentType != null) {
2486 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2487 if (member != null) {
2488 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2493 var report = ctx.Module.Compiler.Report;
2495 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2496 if (retval != null) {
2497 report.SymbolRelatedToPreviousError (retval.Type);
2498 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2502 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2503 if (retval != null) {
2504 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2508 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2509 if (ns_candidates != null) {
2510 if (ctx is UsingAliasNamespace.AliasContext) {
2511 report.Error (246, loc,
2512 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2513 ns_candidates[0], Name);
2515 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2516 report.Error (246, loc,
2517 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2521 report.Error (246, loc,
2522 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2527 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2529 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2532 if (fne.Type != null && Arity > 0) {
2533 if (HasTypeArguments) {
2534 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2535 if (ct.ResolveAsType (mc) == null)
2541 return new GenericOpenTypeExpr (fne.Type, loc);
2545 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2547 if (!(fne is Namespace))
2551 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2552 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2553 mc.Module.Compiler.Report.Error (1980, Location,
2554 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2555 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2558 fne = new DynamicTypeExpr (loc);
2559 fne.ResolveAsType (mc);
2565 Error_TypeOrNamespaceNotFound (mc);
2569 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2571 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2574 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2576 int lookup_arity = Arity;
2577 bool errorMode = false;
2579 Block current_block = rc.CurrentBlock;
2580 INamedBlockVariable variable = null;
2581 bool variable_found = false;
2585 // Stage 1: binding to local variables or parameters
2587 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2589 if (current_block != null && lookup_arity == 0) {
2590 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2591 if (!variable.IsDeclared) {
2592 // We found local name in accessible block but it's not
2593 // initialized yet, maybe the user wanted to bind to something else
2595 variable_found = true;
2597 e = variable.CreateReferenceExpression (rc, loc);
2600 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2609 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2611 TypeSpec member_type = rc.CurrentType;
2612 for (; member_type != null; member_type = member_type.DeclaringType) {
2613 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2617 var me = e as MemberExpr;
2619 // The name matches a type, defer to ResolveAsTypeStep
2627 if (variable != null) {
2628 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2629 rc.Report.Error (844, loc,
2630 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2631 Name, me.GetSignatureForError ());
2635 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2636 // Leave it to overload resolution to report correct error
2638 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2639 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2642 // LAMESPEC: again, ignores InvocableOnly
2643 if (variable != null) {
2644 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2645 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2649 // MemberLookup does not check accessors availability, this is actually needed for properties only
2651 var pe = me as PropertyExpr;
2654 // Break as there is no other overload available anyway
2655 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2656 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2659 pe.Getter = pe.PropertyInfo.Get;
2661 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2664 pe.Setter = pe.PropertyInfo.Set;
2669 // TODO: It's used by EventExpr -> FieldExpr transformation only
2670 // TODO: Should go to MemberAccess
2671 me = me.ResolveMemberAccess (rc, null, null);
2675 me.SetTypeArguments (rc, targs);
2682 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2684 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2685 if (IsPossibleTypeOrNamespace (rc)) {
2686 if (variable != null) {
2687 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2688 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2691 return ResolveAsTypeOrNamespace (rc);
2696 if (variable_found) {
2697 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2700 var tparams = rc.CurrentTypeParameters;
2701 if (tparams != null) {
2702 if (tparams.Find (Name) != null) {
2703 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2708 var ct = rc.CurrentType;
2710 if (ct.MemberDefinition.TypeParametersCount > 0) {
2711 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2712 if (ctp.Name == Name) {
2713 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2719 ct = ct.DeclaringType;
2720 } while (ct != null);
2723 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2724 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2726 rc.Report.SymbolRelatedToPreviousError (e.Type);
2727 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2731 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2733 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2734 return ErrorExpression.Instance;
2738 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2740 if (e.Type.Arity != Arity) {
2741 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2745 if (e is TypeExpr) {
2746 // TypeExpression does not have correct location
2747 if (e is TypeExpression)
2748 e = new TypeExpression (e.Type, loc);
2754 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2757 return ErrorExpression.Instance;
2760 if (rc.Module.Evaluator != null) {
2761 var fi = rc.Module.Evaluator.LookupField (Name);
2763 return new FieldExpr (fi.Item1, loc);
2771 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2773 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2778 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2779 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2783 if (right_side != null) {
2784 e = e.ResolveLValue (ec, right_side);
2792 public override object Accept (StructuralVisitor visitor)
2794 return visitor.Visit (this);
2799 /// Represents a namespace or a type. The name of the class was inspired by
2800 /// section 10.8.1 (Fully Qualified Names).
2802 public abstract class FullNamedExpression : Expression
2804 protected override void CloneTo (CloneContext clonectx, Expression target)
2806 // Do nothing, most unresolved type expressions cannot be
2807 // resolved to different type
2810 public override bool ContainsEmitWithAwait ()
2815 public override Expression CreateExpressionTree (ResolveContext ec)
2817 throw new NotSupportedException ("ET");
2820 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2823 // This is used to resolve the expression as a type, a null
2824 // value will be returned if the expression is not a type
2827 public override TypeSpec ResolveAsType (IMemberContext mc)
2829 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2834 TypeExpr te = fne as TypeExpr;
2836 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2844 var dep = type.GetMissingDependencies ();
2846 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2849 if (type.Kind == MemberKind.Void) {
2850 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2854 // Obsolete checks cannot be done when resolving base context as they
2855 // require type dependencies to be set but we are in process of resolving them
2857 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2858 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2859 if (obsolete_attr != null && !mc.IsObsolete) {
2860 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2868 public override void Emit (EmitContext ec)
2870 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2871 GetSignatureForError ());
2876 /// Expression that evaluates to a type
2878 public abstract class TypeExpr : FullNamedExpression
2880 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2886 protected sealed override Expression DoResolve (ResolveContext ec)
2892 public override bool Equals (object obj)
2894 TypeExpr tobj = obj as TypeExpr;
2898 return Type == tobj.Type;
2901 public override int GetHashCode ()
2903 return Type.GetHashCode ();
2908 /// Fully resolved Expression that already evaluated to a type
2910 public class TypeExpression : TypeExpr
2912 public TypeExpression (TypeSpec t, Location l)
2915 eclass = ExprClass.Type;
2919 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2926 /// This class denotes an expression which evaluates to a member
2927 /// of a struct or a class.
2929 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2932 // An instance expression associated with this member, if it's a
2933 // non-static member
2935 public Expression InstanceExpression;
2938 /// The name of this member.
2940 public abstract string Name {
2945 // When base.member is used
2947 public bool IsBase {
2948 get { return InstanceExpression is BaseThis; }
2952 /// Whether this is an instance member.
2954 public abstract bool IsInstance {
2959 /// Whether this is a static member.
2961 public abstract bool IsStatic {
2965 public abstract string KindName {
2969 protected abstract TypeSpec DeclaringType {
2973 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2975 return InstanceExpression.Type;
2980 // Converts best base candidate for virtual method starting from QueriedBaseType
2982 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2985 // Only when base.member is used and method is virtual
2991 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2992 // means for base.member access we have to find the closest match after we found best candidate
2994 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2996 // The method could already be what we are looking for
2998 TypeSpec[] targs = null;
2999 if (method.DeclaringType != InstanceExpression.Type) {
3000 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3001 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3002 if (base_override.IsGeneric)
3003 targs = method.TypeArguments;
3005 method = base_override;
3010 // When base access is used inside anonymous method/iterator/etc we need to
3011 // get back to the context of original type. We do it by emiting proxy
3012 // method in original class and rewriting base call to this compiler
3013 // generated method call which does the actual base invocation. This may
3014 // introduce redundant storey but with `this' only but it's tricky to avoid
3015 // at this stage as we don't know what expressions follow base
3017 if (rc.CurrentAnonymousMethod != null) {
3018 if (targs == null && method.IsGeneric) {
3019 targs = method.TypeArguments;
3020 method = method.GetGenericMethodDefinition ();
3023 if (method.Parameters.HasArglist)
3024 throw new NotImplementedException ("__arglist base call proxy");
3026 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3028 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3029 // get/set member expressions second call would fail to proxy because left expression
3030 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3031 // FIXME: The async check is another hack but will probably fail with mutators
3032 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3033 InstanceExpression = new This (loc).Resolve (rc);
3037 method = method.MakeGenericMethod (rc, targs);
3041 // Only base will allow this invocation to happen.
3043 if (method.IsAbstract) {
3044 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3050 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3052 if (InstanceExpression == null)
3055 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3056 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3057 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3062 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3064 if (InstanceExpression == null)
3067 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3070 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3072 var ct = rc.CurrentType;
3073 if (ct == qualifier)
3076 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3079 qualifier = qualifier.GetDefinition ();
3080 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3087 public override bool ContainsEmitWithAwait ()
3089 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3092 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3095 type = type.GetDefinition ();
3097 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3100 type = type.DeclaringType;
3101 } while (type != null);
3106 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3108 if (InstanceExpression != null) {
3109 InstanceExpression = InstanceExpression.Resolve (rc);
3110 CheckProtectedMemberAccess (rc, member);
3113 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3114 UnsafeError (rc, loc);
3117 var dep = member.GetMissingDependencies ();
3119 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3122 if (!rc.IsObsolete) {
3123 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3125 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3128 if (!(member is FieldSpec))
3129 member.MemberDefinition.SetIsUsed ();
3132 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3134 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3137 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3139 rc.Report.SymbolRelatedToPreviousError (member);
3140 rc.Report.Error (1540, loc,
3141 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3142 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3145 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3147 if (!ResolveInstanceExpressionCore (rc, rhs))
3151 // Check intermediate value modification which won't have any effect
3153 if (rhs != null && InstanceExpression.Type.IsStruct) {
3154 var fexpr = InstanceExpression as FieldExpr;
3155 if (fexpr != null) {
3156 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3159 if (fexpr.IsStatic) {
3160 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3161 fexpr.GetSignatureForError ());
3163 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3164 fexpr.GetSignatureForError ());
3166 } else if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3167 if (rc.CurrentInitializerVariable != null) {
3168 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3169 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3171 rc.Report.Error (1612, loc,
3172 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3173 InstanceExpression.GetSignatureForError ());
3181 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3184 if (InstanceExpression != null) {
3185 if (InstanceExpression is TypeExpr) {
3186 var t = InstanceExpression.Type;
3188 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3189 if (oa != null && !rc.IsObsolete) {
3190 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3193 t = t.DeclaringType;
3194 } while (t != null);
3196 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3197 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3198 rc.Report.Error (176, loc,
3199 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3200 GetSignatureForError ());
3204 InstanceExpression = null;
3210 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3211 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3212 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3213 rc.Report.Error (236, loc,
3214 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3215 GetSignatureForError ());
3217 rc.Report.Error (120, loc,
3218 "An object reference is required to access non-static member `{0}'",
3219 GetSignatureForError ());
3221 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3225 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3226 rc.Report.Error (38, loc,
3227 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3228 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3231 InstanceExpression = new This (loc);
3232 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3233 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3234 InstanceExpression = InstanceExpression.Resolve (rc);
3237 InstanceExpression = InstanceExpression.Resolve (rc);
3243 var me = InstanceExpression as MemberExpr;
3245 me.ResolveInstanceExpressionCore (rc, rhs);
3247 // Using this check to detect probing instance expression resolve
3248 if (!rc.OmitStructFlowAnalysis) {
3249 var fe = me as FieldExpr;
3250 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3251 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3252 rc.Report.Warning (1690, 1, loc,
3253 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3254 me.GetSignatureForError ());
3262 // Run member-access postponed check once we know that
3263 // the expression is not field expression which is the only
3264 // expression which can use uninitialized this
3266 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3267 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3271 // Additional checks for l-value member access
3274 if (InstanceExpression is UnboxCast) {
3275 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3282 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3284 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3285 ec.Report.Warning (1720, 1, left.Location,
3286 "Expression will always cause a `{0}'", "System.NullReferenceException");
3289 InstanceExpression = left;
3293 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3295 TypeSpec instance_type = InstanceExpression.Type;
3296 if (TypeSpec.IsValueType (instance_type)) {
3297 if (InstanceExpression is IMemoryLocation) {
3298 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3300 // Cannot release the temporary variable when its address
3301 // is required to be on stack for any parent
3302 LocalTemporary t = new LocalTemporary (instance_type);
3303 InstanceExpression.Emit (ec);
3305 t.AddressOf (ec, AddressOp.Store);
3308 InstanceExpression.Emit (ec);
3310 // Only to make verifier happy
3311 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3312 ec.Emit (OpCodes.Box, instance_type);
3315 if (prepare_for_load)
3316 ec.Emit (OpCodes.Dup);
3319 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3322 public class ExtensionMethodCandidates
3324 readonly NamespaceContainer container;
3325 readonly IList<MethodSpec> methods;
3327 readonly IMemberContext context;
3329 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3331 this.context = context;
3332 this.methods = methods;
3333 this.container = nsContainer;
3334 this.index = lookupIndex;
3337 public NamespaceContainer Container {
3343 public IMemberContext Context {
3349 public int LookupIndex {
3355 public IList<MethodSpec> Methods {
3363 // Represents a group of extension method candidates for whole namespace
3365 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3367 ExtensionMethodCandidates candidates;
3368 public Expression ExtensionExpression;
3370 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3371 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3373 this.candidates = candidates;
3374 this.ExtensionExpression = extensionExpr;
3377 public override bool IsStatic {
3378 get { return true; }
3382 // For extension methodgroup we are not looking for base members but parent
3383 // namespace extension methods
3385 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3387 // TODO: candidates are null only when doing error reporting, that's
3388 // incorrect. We have to discover same extension methods in error mode
3389 if (candidates == null)
3392 int arity = type_arguments == null ? 0 : type_arguments.Count;
3394 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3395 if (candidates == null)
3398 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3401 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3403 // We are already here
3407 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3409 if (arguments == null)
3410 arguments = new Arguments (1);
3412 ExtensionExpression = ExtensionExpression.Resolve (ec);
3413 if (ExtensionExpression == null)
3416 var cand = candidates;
3417 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3418 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3420 // Restore candidates in case we are running in probing mode
3423 // Store resolved argument and restore original arguments
3425 // Clean-up modified arguments for error reporting
3426 arguments.RemoveAt (0);
3430 var me = ExtensionExpression as MemberExpr;
3432 me.ResolveInstanceExpression (ec, null);
3433 var fe = me as FieldExpr;
3435 fe.Spec.MemberDefinition.SetIsUsed ();
3438 InstanceExpression = null;
3442 #region IErrorHandler Members
3444 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3449 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3451 rc.Report.SymbolRelatedToPreviousError (best);
3452 rc.Report.Error (1928, loc,
3453 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3454 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3457 rc.Report.Error (1929, loc,
3458 "Extension method instance type `{0}' cannot be converted to `{1}'",
3459 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3465 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3470 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3479 /// MethodGroupExpr represents a group of method candidates which
3480 /// can be resolved to the best method overload
3482 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3484 protected IList<MemberSpec> Methods;
3485 MethodSpec best_candidate;
3486 TypeSpec best_candidate_return;
3487 protected TypeArguments type_arguments;
3489 SimpleName simple_name;
3490 protected TypeSpec queried_type;
3492 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3496 this.type = InternalType.MethodGroup;
3498 eclass = ExprClass.MethodGroup;
3499 queried_type = type;
3502 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3503 : this (new MemberSpec[] { m }, type, loc)
3509 public MethodSpec BestCandidate {
3511 return best_candidate;
3515 public TypeSpec BestCandidateReturnType {
3517 return best_candidate_return;
3521 public IList<MemberSpec> Candidates {
3527 protected override TypeSpec DeclaringType {
3529 return queried_type;
3533 public override bool IsInstance {
3535 if (best_candidate != null)
3536 return !best_candidate.IsStatic;
3542 public override bool IsSideEffectFree {
3544 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3548 public override bool IsStatic {
3550 if (best_candidate != null)
3551 return best_candidate.IsStatic;
3557 public override string KindName {
3558 get { return "method"; }
3561 public override string Name {
3563 if (best_candidate != null)
3564 return best_candidate.Name;
3567 return Methods.First ().Name;
3574 // When best candidate is already know this factory can be used
3575 // to avoid expensive overload resolution to be called
3577 // NOTE: InstanceExpression has to be set manually
3579 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3581 return new MethodGroupExpr (best, queriedType, loc) {
3582 best_candidate = best,
3583 best_candidate_return = best.ReturnType
3587 public override string GetSignatureForError ()
3589 if (best_candidate != null)
3590 return best_candidate.GetSignatureForError ();
3592 return Methods.First ().GetSignatureForError ();
3595 public override Expression CreateExpressionTree (ResolveContext ec)
3597 if (best_candidate == null) {
3598 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3602 if (best_candidate.IsConditionallyExcluded (ec))
3603 ec.Report.Error (765, loc,
3604 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3606 return new TypeOfMethod (best_candidate, loc);
3609 protected override Expression DoResolve (ResolveContext ec)
3611 this.eclass = ExprClass.MethodGroup;
3613 if (InstanceExpression != null) {
3614 InstanceExpression = InstanceExpression.Resolve (ec);
3615 if (InstanceExpression == null)
3622 public override void Emit (EmitContext ec)
3624 throw new NotSupportedException ();
3627 public void EmitCall (EmitContext ec, Arguments arguments)
3629 var call = new CallEmitter ();
3630 call.InstanceExpression = InstanceExpression;
3631 call.Emit (ec, best_candidate, arguments, loc);
3634 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3636 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3637 Name, target.GetSignatureForError ());
3640 public static bool IsExtensionMethodArgument (Expression expr)
3643 // LAMESPEC: No details about which expressions are not allowed
3645 return !(expr is TypeExpr) && !(expr is BaseThis);
3649 /// Find the Applicable Function Members (7.4.2.1)
3651 /// me: Method Group expression with the members to select.
3652 /// it might contain constructors or methods (or anything
3653 /// that maps to a method).
3655 /// Arguments: ArrayList containing resolved Argument objects.
3657 /// loc: The location if we want an error to be reported, or a Null
3658 /// location for "probing" purposes.
3660 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3661 /// that is the best match of me on Arguments.
3664 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3666 // TODO: causes issues with probing mode, remove explicit Kind check
3667 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3670 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3671 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3672 r.BaseMembersProvider = this;
3673 r.InstanceQualifier = this;
3676 if (cerrors != null)
3677 r.CustomErrors = cerrors;
3679 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3680 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3681 if (best_candidate == null)
3682 return r.BestCandidateIsDynamic ? this : null;
3684 // Overload resolver had to create a new method group, all checks bellow have already been executed
3685 if (r.BestCandidateNewMethodGroup != null)
3686 return r.BestCandidateNewMethodGroup;
3688 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3689 if (InstanceExpression != null) {
3690 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3691 InstanceExpression = null;
3693 if (best_candidate.IsStatic && simple_name != null) {
3694 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3697 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3701 ResolveInstanceExpression (ec, null);
3704 var base_override = CandidateToBaseOverride (ec, best_candidate);
3705 if (base_override == best_candidate) {
3706 best_candidate_return = r.BestCandidateReturnType;
3708 best_candidate = base_override;
3709 best_candidate_return = best_candidate.ReturnType;
3712 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3713 ConstraintChecker cc = new ConstraintChecker (ec);
3714 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3718 // Additional check for possible imported base override method which
3719 // could not be done during IsOverrideMethodBaseTypeAccessible
3721 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3722 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3723 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3724 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3730 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3732 var fe = left as FieldExpr;
3735 // Using method-group on struct fields makes the struct assigned. I am not sure
3736 // why but that's what .net does
3738 fe.Spec.MemberDefinition.SetIsAssigned ();
3741 simple_name = original;
3742 return base.ResolveMemberAccess (ec, left, original);
3745 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3747 type_arguments = ta;
3750 #region IBaseMembersProvider Members
3752 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3754 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3757 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3759 if (queried_type == member.DeclaringType)
3762 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3763 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3767 // Extension methods lookup after ordinary methods candidates failed to apply
3769 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3771 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3774 if (!IsExtensionMethodArgument (InstanceExpression))
3777 int arity = type_arguments == null ? 0 : type_arguments.Count;
3778 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3779 if (methods == null)
3782 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3783 emg.SetTypeArguments (rc, type_arguments);
3790 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3792 public ConstructorInstanceQualifier (TypeSpec type)
3795 InstanceType = type;
3798 public TypeSpec InstanceType { get; private set; }
3800 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3802 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3806 public struct OverloadResolver
3809 public enum Restrictions
3813 ProbingOnly = 1 << 1,
3814 CovariantDelegate = 1 << 2,
3815 NoBaseMembers = 1 << 3,
3816 BaseMembersIncluded = 1 << 4
3819 public interface IBaseMembersProvider
3821 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3822 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3823 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3826 public interface IErrorHandler
3828 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3829 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3830 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3831 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3834 public interface IInstanceQualifier
3836 TypeSpec InstanceType { get; }
3837 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3840 sealed class NoBaseMembers : IBaseMembersProvider
3842 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3844 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3849 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3854 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3860 struct AmbiguousCandidate
3862 public readonly MemberSpec Member;
3863 public readonly bool Expanded;
3864 public readonly AParametersCollection Parameters;
3866 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3869 Parameters = parameters;
3870 Expanded = expanded;
3875 IList<MemberSpec> members;
3876 TypeArguments type_arguments;
3877 IBaseMembersProvider base_provider;
3878 IErrorHandler custom_errors;
3879 IInstanceQualifier instance_qualifier;
3880 Restrictions restrictions;
3881 MethodGroupExpr best_candidate_extension_group;
3882 TypeSpec best_candidate_return_type;
3884 SessionReportPrinter lambda_conv_msgs;
3886 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3887 : this (members, null, restrictions, loc)
3891 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3894 if (members == null || members.Count == 0)
3895 throw new ArgumentException ("empty members set");
3897 this.members = members;
3899 type_arguments = targs;
3900 this.restrictions = restrictions;
3901 if (IsDelegateInvoke)
3902 this.restrictions |= Restrictions.NoBaseMembers;
3904 base_provider = NoBaseMembers.Instance;
3909 public IBaseMembersProvider BaseMembersProvider {
3911 return base_provider;
3914 base_provider = value;
3918 public bool BestCandidateIsDynamic { get; set; }
3921 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3923 public MethodGroupExpr BestCandidateNewMethodGroup {
3925 return best_candidate_extension_group;
3930 // Return type can be different between best candidate and closest override
3932 public TypeSpec BestCandidateReturnType {
3934 return best_candidate_return_type;
3938 public IErrorHandler CustomErrors {
3940 return custom_errors;
3943 custom_errors = value;
3947 TypeSpec DelegateType {
3949 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3950 throw new InternalErrorException ("Not running in delegate mode", loc);
3952 return members [0].DeclaringType;
3956 public IInstanceQualifier InstanceQualifier {
3958 return instance_qualifier;
3961 instance_qualifier = value;
3965 bool IsProbingOnly {
3967 return (restrictions & Restrictions.ProbingOnly) != 0;
3971 bool IsDelegateInvoke {
3973 return (restrictions & Restrictions.DelegateInvoke) != 0;
3980 // 7.4.3.3 Better conversion from expression
3981 // Returns : 1 if a->p is better,
3982 // 2 if a->q is better,
3983 // 0 if neither is better
3985 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3987 TypeSpec argument_type = a.Type;
3990 // If argument is an anonymous function
3992 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3994 // p and q are delegate types or expression tree types
3996 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3997 if (q.MemberDefinition != p.MemberDefinition) {
4002 // Uwrap delegate from Expression<T>
4004 q = TypeManager.GetTypeArguments (q)[0];
4005 p = TypeManager.GetTypeArguments (p)[0];
4008 var p_m = Delegate.GetInvokeMethod (p);
4009 var q_m = Delegate.GetInvokeMethod (q);
4012 // With identical parameter lists
4014 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4023 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4025 if (p.Kind == MemberKind.Void) {
4026 return q.Kind != MemberKind.Void ? 2 : 0;
4030 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4032 if (q.Kind == MemberKind.Void) {
4033 return p.Kind != MemberKind.Void ? 1: 0;
4036 var am = (AnonymousMethodExpression) a.Expr;
4039 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4040 // better conversion is performed between underlying types Y1 and Y2
4042 if (p.IsGenericTask || q.IsGenericTask) {
4043 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4044 q = q.TypeArguments[0];
4045 p = p.TypeArguments[0];
4047 } else if (q != p) {
4049 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4051 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4052 var am_rt = am.InferReturnType (ec, null, orig_q);
4053 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4055 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4056 var am_rt = am.InferReturnType (ec, null, orig_p);
4057 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4063 // The parameters are identicial and return type is not void, use better type conversion
4064 // on return type to determine better one
4067 if (argument_type == p)
4070 if (argument_type == q)
4074 return BetterTypeConversion (ec, p, q);
4078 // 7.4.3.4 Better conversion from type
4080 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4082 if (p == null || q == null)
4083 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4085 switch (p.BuiltinType) {
4086 case BuiltinTypeSpec.Type.Int:
4087 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4090 case BuiltinTypeSpec.Type.Long:
4091 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4094 case BuiltinTypeSpec.Type.SByte:
4095 switch (q.BuiltinType) {
4096 case BuiltinTypeSpec.Type.Byte:
4097 case BuiltinTypeSpec.Type.UShort:
4098 case BuiltinTypeSpec.Type.UInt:
4099 case BuiltinTypeSpec.Type.ULong:
4103 case BuiltinTypeSpec.Type.Short:
4104 switch (q.BuiltinType) {
4105 case BuiltinTypeSpec.Type.UShort:
4106 case BuiltinTypeSpec.Type.UInt:
4107 case BuiltinTypeSpec.Type.ULong:
4111 case BuiltinTypeSpec.Type.Dynamic:
4112 // Dynamic is never better
4116 switch (q.BuiltinType) {
4117 case BuiltinTypeSpec.Type.Int:
4118 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4121 case BuiltinTypeSpec.Type.Long:
4122 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4125 case BuiltinTypeSpec.Type.SByte:
4126 switch (p.BuiltinType) {
4127 case BuiltinTypeSpec.Type.Byte:
4128 case BuiltinTypeSpec.Type.UShort:
4129 case BuiltinTypeSpec.Type.UInt:
4130 case BuiltinTypeSpec.Type.ULong:
4134 case BuiltinTypeSpec.Type.Short:
4135 switch (p.BuiltinType) {
4136 case BuiltinTypeSpec.Type.UShort:
4137 case BuiltinTypeSpec.Type.UInt:
4138 case BuiltinTypeSpec.Type.ULong:
4142 case BuiltinTypeSpec.Type.Dynamic:
4143 // Dynamic is never better
4147 // FIXME: handle lifted operators
4149 // TODO: this is expensive
4150 Expression p_tmp = new EmptyExpression (p);
4151 Expression q_tmp = new EmptyExpression (q);
4153 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4154 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4156 if (p_to_q && !q_to_p)
4159 if (q_to_p && !p_to_q)
4166 /// Determines "Better function" between candidate
4167 /// and the current best match
4170 /// Returns a boolean indicating :
4171 /// false if candidate ain't better
4172 /// true if candidate is better than the current best match
4174 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4175 MemberSpec best, AParametersCollection bparam, bool best_params)
4177 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4178 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4180 bool better_at_least_one = false;
4182 int args_count = args == null ? 0 : args.Count;
4186 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4189 // Default arguments are ignored for better decision
4190 if (a.IsDefaultArgument)
4194 // When comparing named argument the parameter type index has to be looked up
4195 // in original parameter set (override version for virtual members)
4197 NamedArgument na = a as NamedArgument;
4199 int idx = cparam.GetParameterIndexByName (na.Name);
4200 ct = candidate_pd.Types[idx];
4201 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4202 ct = TypeManager.GetElementType (ct);
4204 idx = bparam.GetParameterIndexByName (na.Name);
4205 bt = best_pd.Types[idx];
4206 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4207 bt = TypeManager.GetElementType (bt);
4209 ct = candidate_pd.Types[c_idx];
4210 bt = best_pd.Types[b_idx];
4212 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4213 ct = TypeManager.GetElementType (ct);
4217 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4218 bt = TypeManager.GetElementType (bt);
4223 if (TypeSpecComparer.IsEqual (ct, bt))
4227 int result = BetterExpressionConversion (ec, a, ct, bt);
4229 // for each argument, the conversion to 'ct' should be no worse than
4230 // the conversion to 'bt'.
4234 // for at least one argument, the conversion to 'ct' should be better than
4235 // the conversion to 'bt'.
4237 better_at_least_one = true;
4240 if (better_at_least_one)
4244 // This handles the case
4246 // Add (float f1, float f2, float f3);
4247 // Add (params decimal [] foo);
4249 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4250 // first candidate would've chosen as better.
4252 if (!same && !a.IsDefaultArgument)
4256 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4260 // This handles the following cases:
4262 // Foo (int i) is better than Foo (int i, long l = 0)
4263 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4264 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4266 // Prefer non-optional version
4268 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4270 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4271 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4274 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4277 return candidate_pd.Count >= best_pd.Count;
4281 // One is a non-generic method and second is a generic method, then non-generic is better
4283 if (best.IsGeneric != candidate.IsGeneric)
4284 return best.IsGeneric;
4287 // This handles the following cases:
4289 // Trim () is better than Trim (params char[] chars)
4290 // Concat (string s1, string s2, string s3) is better than
4291 // Concat (string s1, params string [] srest)
4292 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4294 // Prefer non-expanded version
4296 if (candidate_params != best_params)
4299 int candidate_param_count = candidate_pd.Count;
4300 int best_param_count = best_pd.Count;
4302 if (candidate_param_count != best_param_count)
4303 // can only happen if (candidate_params && best_params)
4304 return candidate_param_count > best_param_count && best_pd.HasParams;
4307 // Both methods have the same number of parameters, and the parameters have equal types
4308 // Pick the "more specific" signature using rules over original (non-inflated) types
4310 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4311 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4313 bool specific_at_least_once = false;
4314 for (j = 0; j < args_count; ++j) {
4315 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4317 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4318 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4320 ct = candidate_def_pd.Types[j];
4321 bt = best_def_pd.Types[j];
4326 TypeSpec specific = MoreSpecific (ct, bt);
4330 specific_at_least_once = true;
4333 if (specific_at_least_once)
4339 static bool CheckInflatedArguments (MethodSpec ms)
4341 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4344 // Setup constraint checker for probing only
4345 ConstraintChecker cc = new ConstraintChecker (null);
4347 var mp = ms.Parameters.Types;
4348 for (int i = 0; i < mp.Length; ++i) {
4349 var type = mp[i] as InflatedTypeSpec;
4353 var targs = type.TypeArguments;
4354 if (targs.Length == 0)
4357 // TODO: Checking inflated MVAR arguments should be enough
4358 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4365 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4367 rc.Report.Error (1729, loc,
4368 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4369 type.GetSignatureForError (), argCount.ToString ());
4373 // Determines if the candidate method is applicable to the given set of arguments
4374 // There could be two different set of parameters for same candidate where one
4375 // is the closest override for default values and named arguments checks and second
4376 // one being the virtual base for the parameter types and modifiers.
4378 // A return value rates candidate method compatibility,
4379 // 0 = the best, int.MaxValue = the worst
4382 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)
4384 // Parameters of most-derived type used mainly for named and optional parameters
4385 var pd = pm.Parameters;
4387 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4388 // params modifier instead of most-derived type
4389 var cpd = ((IParametersMember) candidate).Parameters;
4390 int param_count = pd.Count;
4391 int optional_count = 0;
4393 Arguments orig_args = arguments;
4395 if (arg_count != param_count) {
4397 // No arguments expansion when doing exact match for delegates
4399 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4400 for (int i = 0; i < pd.Count; ++i) {
4401 if (pd.FixedParameters[i].HasDefaultValue) {
4402 optional_count = pd.Count - i;
4408 if (optional_count != 0) {
4409 // Readjust expected number when params used
4410 if (cpd.HasParams) {
4412 if (arg_count < param_count)
4414 } else if (arg_count > param_count) {
4415 int args_gap = System.Math.Abs (arg_count - param_count);
4416 return int.MaxValue - 10000 + args_gap;
4417 } else if (arg_count < param_count - optional_count) {
4418 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4419 return int.MaxValue - 10000 + args_gap;
4421 } else if (arg_count != param_count) {
4422 int args_gap = System.Math.Abs (arg_count - param_count);
4424 return int.MaxValue - 10000 + args_gap;
4425 if (arg_count < param_count - 1)
4426 return int.MaxValue - 10000 + args_gap;
4429 // Resize to fit optional arguments
4430 if (optional_count != 0) {
4431 if (arguments == null) {
4432 arguments = new Arguments (optional_count);
4434 // Have to create a new container, so the next run can do same
4435 var resized = new Arguments (param_count);
4436 resized.AddRange (arguments);
4437 arguments = resized;
4440 for (int i = arg_count; i < param_count; ++i)
4441 arguments.Add (null);
4445 if (arg_count > 0) {
4447 // Shuffle named arguments to the right positions if there are any
4449 if (arguments[arg_count - 1] is NamedArgument) {
4450 arg_count = arguments.Count;
4452 for (int i = 0; i < arg_count; ++i) {
4453 bool arg_moved = false;
4455 NamedArgument na = arguments[i] as NamedArgument;
4459 int index = pd.GetParameterIndexByName (na.Name);
4461 // Named parameter not found
4465 // already reordered
4470 if (index >= param_count) {
4471 // When using parameters which should not be available to the user
4472 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4475 arguments.Add (null);
4479 temp = arguments[index];
4481 // The slot has been taken by positional argument
4482 if (temp != null && !(temp is NamedArgument))
4487 arguments = arguments.MarkOrderedArgument (na);
4491 if (arguments == orig_args) {
4492 arguments = new Arguments (orig_args.Count);
4493 arguments.AddRange (orig_args);
4496 arguments[index] = arguments[i];
4497 arguments[i] = temp;
4504 arg_count = arguments.Count;
4506 } else if (arguments != null) {
4507 arg_count = arguments.Count;
4511 // Don't do any expensive checks when the candidate cannot succeed
4513 if (arg_count != param_count && !cpd.HasParams)
4514 return (param_count - arg_count) * 2 + 1;
4516 var dep = candidate.GetMissingDependencies ();
4518 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4523 // 1. Handle generic method using type arguments when specified or type inference
4526 var ms = candidate as MethodSpec;
4527 if (ms != null && ms.IsGeneric) {
4528 if (type_arguments != null) {
4529 var g_args_count = ms.Arity;
4530 if (g_args_count != type_arguments.Count)
4531 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4533 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4536 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4537 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4538 // candidate was found use the set to report more details about what was wrong with lambda body.
4539 // The general idea is to distinguish between code errors and errors caused by
4540 // trial-and-error type inference
4542 if (lambda_conv_msgs == null) {
4543 for (int i = 0; i < arg_count; i++) {
4544 Argument a = arguments[i];
4548 var am = a.Expr as AnonymousMethodExpression;
4550 if (lambda_conv_msgs == null)
4551 lambda_conv_msgs = new SessionReportPrinter ();
4553 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4558 var ti = new TypeInference (arguments);
4559 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4562 return ti.InferenceScore - 20000;
4565 // Clear any error messages when the result was success
4567 if (lambda_conv_msgs != null)
4568 lambda_conv_msgs.ClearSession ();
4570 if (i_args.Length != 0) {
4571 ms = ms.MakeGenericMethod (ec, i_args);
4576 // Type arguments constraints have to match for the method to be applicable
4578 if (!CheckInflatedArguments (ms)) {
4580 return int.MaxValue - 25000;
4584 // We have a generic return type and at same time the method is override which
4585 // means we have to also inflate override return type in case the candidate is
4586 // best candidate and override return type is different to base return type.
4588 // virtual Foo<T, object> with override Foo<T, dynamic>
4590 if (candidate != pm) {
4591 MethodSpec override_ms = (MethodSpec) pm;
4592 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4593 returnType = inflator.Inflate (returnType);
4595 returnType = ms.ReturnType;
4602 if (type_arguments != null)
4603 return int.MaxValue - 15000;
4609 // 2. Each argument has to be implicitly convertible to method parameter
4611 Parameter.Modifier p_mod = 0;
4614 for (int i = 0; i < arg_count; i++) {
4615 Argument a = arguments[i];
4617 var fp = pd.FixedParameters[i];
4618 if (!fp.HasDefaultValue) {
4619 arguments = orig_args;
4620 return arg_count * 2 + 2;
4624 // Get the default value expression, we can use the same expression
4625 // if the type matches
4627 Expression e = fp.DefaultValue;
4629 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4631 // Restore for possible error reporting
4632 for (int ii = i; ii < arg_count; ++ii)
4633 arguments.RemoveAt (i);
4635 return (arg_count - i) * 2 + 1;
4639 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4641 // LAMESPEC: Attributes can be mixed together with build-in priority
4643 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4644 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4645 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4646 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4647 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4648 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4652 arguments[i] = new Argument (e, Argument.AType.Default);
4656 if (p_mod != Parameter.Modifier.PARAMS) {
4657 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4659 } else if (!params_expanded_form) {
4660 params_expanded_form = true;
4661 pt = ((ElementTypeSpec) pt).Element;
4667 if (!params_expanded_form) {
4668 if (a.ArgType == Argument.AType.ExtensionType) {
4670 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4672 // LAMESPEC: or implicit type parameter conversion
4675 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4676 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4677 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4682 score = IsArgumentCompatible (ec, a, p_mod, pt);
4685 dynamicArgument = true;
4690 // It can be applicable in expanded form (when not doing exact match like for delegates)
4692 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4693 if (!params_expanded_form) {
4694 pt = ((ElementTypeSpec) pt).Element;
4698 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4701 params_expanded_form = true;
4702 dynamicArgument = true;
4703 } else if (score == 0 || arg_count > pd.Count) {
4704 params_expanded_form = true;
4709 if (params_expanded_form)
4711 return (arg_count - i) * 2 + score;
4716 // When params parameter has no argument it will be provided later if the method is the best candidate
4718 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4719 params_expanded_form = true;
4722 // Restore original arguments for dynamic binder to keep the intention of original source code
4724 if (dynamicArgument)
4725 arguments = orig_args;
4730 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4732 if (e is Constant && e.Type == ptype)
4736 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4738 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4739 e = new MemberAccess (new MemberAccess (new MemberAccess (
4740 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4741 } else if (e is Constant) {
4743 // Handles int to int? conversions, DefaultParameterValue check
4745 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4749 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4752 return e.Resolve (ec);
4756 // Tests argument compatibility with the parameter
4757 // The possible return values are
4759 // 1 - modifier mismatch
4760 // 2 - type mismatch
4761 // -1 - dynamic binding required
4763 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4766 // Types have to be identical when ref or out modifer
4767 // is used and argument is not of dynamic type
4769 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4770 if (argument.Type != parameter) {
4772 // Do full equality check after quick path
4774 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4776 // Using dynamic for ref/out parameter can still succeed at runtime
4778 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4785 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4787 // Using dynamic for ref/out parameter can still succeed at runtime
4789 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4796 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4800 // Use implicit conversion in all modes to return same candidates when the expression
4801 // is used as argument or delegate conversion
4803 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4804 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4811 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4813 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4815 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4818 var ac_p = p as ArrayContainer;
4820 var ac_q = q as ArrayContainer;
4824 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4825 if (specific == ac_p.Element)
4827 if (specific == ac_q.Element)
4829 } else if (p.IsGeneric && q.IsGeneric) {
4830 var pargs = TypeManager.GetTypeArguments (p);
4831 var qargs = TypeManager.GetTypeArguments (q);
4833 bool p_specific_at_least_once = false;
4834 bool q_specific_at_least_once = false;
4836 for (int i = 0; i < pargs.Length; i++) {
4837 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4838 if (specific == pargs[i])
4839 p_specific_at_least_once = true;
4840 if (specific == qargs[i])
4841 q_specific_at_least_once = true;
4844 if (p_specific_at_least_once && !q_specific_at_least_once)
4846 if (!p_specific_at_least_once && q_specific_at_least_once)
4854 // Find the best method from candidate list
4856 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4858 List<AmbiguousCandidate> ambiguous_candidates = null;
4860 MemberSpec best_candidate;
4861 Arguments best_candidate_args = null;
4862 bool best_candidate_params = false;
4863 bool best_candidate_dynamic = false;
4864 int best_candidate_rate;
4865 IParametersMember best_parameter_member = null;
4867 int args_count = args != null ? args.Count : 0;
4869 Arguments candidate_args = args;
4870 bool error_mode = false;
4871 MemberSpec invocable_member = null;
4874 best_candidate = null;
4875 best_candidate_rate = int.MaxValue;
4877 var type_members = members;
4879 for (int i = 0; i < type_members.Count; ++i) {
4880 var member = type_members[i];
4883 // Methods in a base class are not candidates if any method in a derived
4884 // class is applicable
4886 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4890 if (!member.IsAccessible (rc))
4893 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4896 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4897 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4902 IParametersMember pm = member as IParametersMember;
4905 // Will use it later to report ambiguity between best method and invocable member
4907 if (Invocation.IsMemberInvocable (member))
4908 invocable_member = member;
4914 // Overload resolution is looking for base member but using parameter names
4915 // and default values from the closest member. That means to do expensive lookup
4916 // for the closest override for virtual or abstract members
4918 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4919 var override_params = base_provider.GetOverrideMemberParameters (member);
4920 if (override_params != null)
4921 pm = override_params;
4925 // Check if the member candidate is applicable
4927 bool params_expanded_form = false;
4928 bool dynamic_argument = false;
4929 TypeSpec rt = pm.MemberType;
4930 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4932 if (lambda_conv_msgs != null)
4933 lambda_conv_msgs.EndSession ();
4936 // How does it score compare to others
4938 if (candidate_rate < best_candidate_rate) {
4940 // Fatal error (missing dependency), cannot continue
4941 if (candidate_rate < 0)
4944 best_candidate_rate = candidate_rate;
4945 best_candidate = member;
4946 best_candidate_args = candidate_args;
4947 best_candidate_params = params_expanded_form;
4948 best_candidate_dynamic = dynamic_argument;
4949 best_parameter_member = pm;
4950 best_candidate_return_type = rt;
4951 } else if (candidate_rate == 0) {
4953 // The member look is done per type for most operations but sometimes
4954 // it's not possible like for binary operators overload because they
4955 // are unioned between 2 sides
4957 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4958 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4963 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4965 // We pack all interface members into top level type which makes the overload resolution
4966 // more complicated for interfaces. We compensate it by removing methods with same
4967 // signature when building the cache hence this path should not really be hit often
4970 // interface IA { void Foo (int arg); }
4971 // interface IB : IA { void Foo (params int[] args); }
4973 // IB::Foo is the best overload when calling IB.Foo (1)
4976 if (ambiguous_candidates != null) {
4977 foreach (var amb_cand in ambiguous_candidates) {
4978 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4987 ambiguous_candidates = null;
4990 // Is the new candidate better
4991 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4995 best_candidate = member;
4996 best_candidate_args = candidate_args;
4997 best_candidate_params = params_expanded_form;
4998 best_candidate_dynamic = dynamic_argument;
4999 best_parameter_member = pm;
5000 best_candidate_return_type = rt;
5002 // It's not better but any other found later could be but we are not sure yet
5003 if (ambiguous_candidates == null)
5004 ambiguous_candidates = new List<AmbiguousCandidate> ();
5006 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5010 // Restore expanded arguments
5011 candidate_args = args;
5013 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5016 // We've found exact match
5018 if (best_candidate_rate == 0)
5022 // Try extension methods lookup when no ordinary method match was found and provider enables it
5025 var emg = base_provider.LookupExtensionMethod (rc);
5027 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5029 best_candidate_extension_group = emg;
5030 return (T) (MemberSpec) emg.BestCandidate;
5035 // Don't run expensive error reporting mode for probing
5042 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5045 lambda_conv_msgs = null;
5050 // No best member match found, report an error
5052 if (best_candidate_rate != 0 || error_mode) {
5053 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5057 if (best_candidate_dynamic) {
5058 if (args[0].ArgType == Argument.AType.ExtensionType) {
5059 rc.Report.Error (1973, loc,
5060 "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",
5061 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5065 // Check type constraints only when explicit type arguments are used
5067 if (best_candidate.IsGeneric && type_arguments != null) {
5068 MethodSpec bc = best_candidate as MethodSpec;
5069 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5070 ConstraintChecker cc = new ConstraintChecker (rc);
5071 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5075 BestCandidateIsDynamic = true;
5080 // These flags indicates we are running delegate probing conversion. No need to
5081 // do more expensive checks
5083 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5084 return (T) best_candidate;
5086 if (ambiguous_candidates != null) {
5088 // Now check that there are no ambiguities i.e the selected method
5089 // should be better than all the others
5091 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5092 var candidate = ambiguous_candidates [ix];
5094 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5095 var ambiguous = candidate.Member;
5096 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5097 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5098 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5099 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5100 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5103 return (T) best_candidate;
5108 if (invocable_member != null && !IsProbingOnly) {
5109 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5110 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5111 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5112 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5116 // And now check if the arguments are all
5117 // compatible, perform conversions if
5118 // necessary etc. and return if everything is
5121 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5124 if (best_candidate == null)
5128 // Don't run possibly expensive checks in probing mode
5130 if (!IsProbingOnly && !rc.IsInProbingMode) {
5132 // Check ObsoleteAttribute on the best method
5134 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5135 if (oa != null && !rc.IsObsolete)
5136 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5138 best_candidate.MemberDefinition.SetIsUsed ();
5141 args = best_candidate_args;
5142 return (T) best_candidate;
5145 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5147 return ResolveMember<MethodSpec> (rc, ref args);
5150 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5151 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5153 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5156 if (a.Type == InternalType.ErrorType)
5159 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5160 ec.Report.SymbolRelatedToPreviousError (method);
5161 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5162 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5163 TypeManager.CSharpSignature (method));
5166 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5167 TypeManager.CSharpSignature (method));
5168 } else if (IsDelegateInvoke) {
5169 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5170 DelegateType.GetSignatureForError ());
5172 ec.Report.SymbolRelatedToPreviousError (method);
5173 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5174 method.GetSignatureForError ());
5177 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5179 string index = (idx + 1).ToString ();
5180 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5181 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5182 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5183 index, Parameter.GetModifierSignature (a.Modifier));
5185 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5186 index, Parameter.GetModifierSignature (mod));
5188 string p1 = a.GetSignatureForError ();
5189 string p2 = paramType.GetSignatureForError ();
5192 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5193 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5196 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5197 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5198 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5201 ec.Report.Error (1503, a.Expr.Location,
5202 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5207 // We have failed to find exact match so we return error info about the closest match
5209 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5211 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5212 int arg_count = args == null ? 0 : args.Count;
5214 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5215 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5216 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5220 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5225 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5226 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5227 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5231 // For candidates which match on parameters count report more details about incorrect arguments
5234 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5235 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5236 // Reject any inaccessible member
5237 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5238 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5239 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5243 var ms = best_candidate as MethodSpec;
5244 if (ms != null && ms.IsGeneric) {
5245 bool constr_ok = true;
5246 if (ms.TypeArguments != null)
5247 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5249 if (ta_count == 0) {
5250 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5254 rc.Report.Error (411, loc,
5255 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5256 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5263 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5269 // We failed to find any method with correct argument count, report best candidate
5271 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5274 if (best_candidate.Kind == MemberKind.Constructor) {
5275 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5276 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5277 } else if (IsDelegateInvoke) {
5278 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5279 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5280 DelegateType.GetSignatureForError (), arg_count.ToString ());
5282 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5283 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5284 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5285 name, arg_count.ToString ());
5289 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5291 var pd = pm.Parameters;
5292 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5294 Parameter.Modifier p_mod = 0;
5296 int a_idx = 0, a_pos = 0;
5298 ArrayInitializer params_initializers = null;
5299 bool has_unsafe_arg = pm.MemberType.IsPointer;
5300 int arg_count = args == null ? 0 : args.Count;
5302 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5307 if (p_mod != Parameter.Modifier.PARAMS) {
5308 p_mod = pd.FixedParameters[a_idx].ModFlags;
5310 has_unsafe_arg |= pt.IsPointer;
5312 if (p_mod == Parameter.Modifier.PARAMS) {
5313 if (chose_params_expanded) {
5314 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5315 pt = TypeManager.GetElementType (pt);
5321 // Types have to be identical when ref or out modifer is used
5323 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5324 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5327 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5333 NamedArgument na = a as NamedArgument;
5335 int name_index = pd.GetParameterIndexByName (na.Name);
5336 if (name_index < 0 || name_index >= pd.Count) {
5337 if (IsDelegateInvoke) {
5338 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5339 ec.Report.Error (1746, na.Location,
5340 "The delegate `{0}' does not contain a parameter named `{1}'",
5341 DelegateType.GetSignatureForError (), na.Name);
5343 ec.Report.SymbolRelatedToPreviousError (member);
5344 ec.Report.Error (1739, na.Location,
5345 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5346 TypeManager.CSharpSignature (member), na.Name);
5348 } else if (args[name_index] != a && args[name_index] != null) {
5349 if (IsDelegateInvoke)
5350 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5352 ec.Report.SymbolRelatedToPreviousError (member);
5354 ec.Report.Error (1744, na.Location,
5355 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5360 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5363 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5364 custom_errors.NoArgumentMatch (ec, member);
5369 if (a.ArgType == Argument.AType.ExtensionType) {
5370 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5373 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5375 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5378 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5385 // Convert params arguments to an array initializer
5387 if (params_initializers != null) {
5388 // we choose to use 'a.Expr' rather than 'conv' so that
5389 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5390 params_initializers.Add (a.Expr);
5391 args.RemoveAt (a_idx--);
5397 // Update the argument with the implicit conversion
5401 if (a_idx != arg_count) {
5402 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5407 // Fill not provided arguments required by params modifier
5409 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5411 args = new Arguments (1);
5413 pt = ptypes[pd.Count - 1];
5414 pt = TypeManager.GetElementType (pt);
5415 has_unsafe_arg |= pt.IsPointer;
5416 params_initializers = new ArrayInitializer (0, loc);
5420 // Append an array argument with all params arguments
5422 if (params_initializers != null) {
5423 args.Add (new Argument (
5424 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5428 if (has_unsafe_arg && !ec.IsUnsafe) {
5429 Expression.UnsafeError (ec, loc);
5433 // We could infer inaccesible type arguments
5435 if (type_arguments == null && member.IsGeneric) {
5436 var ms = (MethodSpec) member;
5437 foreach (var ta in ms.TypeArguments) {
5438 if (!ta.IsAccessible (ec)) {
5439 ec.Report.SymbolRelatedToPreviousError (ta);
5440 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5450 public class ConstantExpr : MemberExpr
5452 readonly ConstSpec constant;
5454 public ConstantExpr (ConstSpec constant, Location loc)
5456 this.constant = constant;
5460 public override string Name {
5461 get { throw new NotImplementedException (); }
5464 public override string KindName {
5465 get { return "constant"; }
5468 public override bool IsInstance {
5469 get { return !IsStatic; }
5472 public override bool IsStatic {
5473 get { return true; }
5476 protected override TypeSpec DeclaringType {
5477 get { return constant.DeclaringType; }
5480 public override Expression CreateExpressionTree (ResolveContext ec)
5482 throw new NotSupportedException ("ET");
5485 protected override Expression DoResolve (ResolveContext rc)
5487 ResolveInstanceExpression (rc, null);
5488 DoBestMemberChecks (rc, constant);
5490 var c = constant.GetConstant (rc);
5492 // Creates reference expression to the constant value
5493 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5496 public override void Emit (EmitContext ec)
5498 throw new NotSupportedException ();
5501 public override string GetSignatureForError ()
5503 return constant.GetSignatureForError ();
5506 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5508 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5513 // Fully resolved expression that references a Field
5515 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5517 protected FieldSpec spec;
5518 VariableInfo variable_info;
5520 LocalTemporary temp;
5523 protected FieldExpr (Location l)
5528 public FieldExpr (FieldSpec spec, Location loc)
5533 type = spec.MemberType;
5536 public FieldExpr (FieldBase fi, Location l)
5543 public override string Name {
5549 public bool IsHoisted {
5551 IVariableReference hv = InstanceExpression as IVariableReference;
5552 return hv != null && hv.IsHoisted;
5556 public override bool IsInstance {
5558 return !spec.IsStatic;
5562 public override bool IsStatic {
5564 return spec.IsStatic;
5568 public override string KindName {
5569 get { return "field"; }
5572 public FieldSpec Spec {
5578 protected override TypeSpec DeclaringType {
5580 return spec.DeclaringType;
5584 public VariableInfo VariableInfo {
5586 return variable_info;
5592 public override string GetSignatureForError ()
5594 return spec.GetSignatureForError ();
5597 public bool IsMarshalByRefAccess (ResolveContext rc)
5599 // Checks possible ldflda of field access expression
5600 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5601 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5602 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5605 public void SetHasAddressTaken ()
5607 IVariableReference vr = InstanceExpression as IVariableReference;
5609 vr.SetHasAddressTaken ();
5613 public override Expression CreateExpressionTree (ResolveContext ec)
5615 return CreateExpressionTree (ec, true);
5618 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5621 Expression instance;
5623 if (InstanceExpression == null) {
5624 instance = new NullLiteral (loc);
5625 } else if (convertInstance) {
5626 instance = InstanceExpression.CreateExpressionTree (ec);
5628 args = new Arguments (1);
5629 args.Add (new Argument (InstanceExpression));
5630 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5633 args = Arguments.CreateForExpressionTree (ec, null,
5635 CreateTypeOfExpression ());
5637 return CreateExpressionFactoryCall (ec, "Field", args);
5640 public Expression CreateTypeOfExpression ()
5642 return new TypeOfField (spec, loc);
5645 protected override Expression DoResolve (ResolveContext ec)
5647 spec.MemberDefinition.SetIsUsed ();
5649 return DoResolve (ec, null);
5652 Expression DoResolve (ResolveContext ec, Expression rhs)
5654 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5657 if (ResolveInstanceExpression (ec, rhs)) {
5658 // Resolve the field's instance expression while flow analysis is turned
5659 // off: when accessing a field "a.b", we must check whether the field
5660 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5662 if (lvalue_instance) {
5663 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5664 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5666 Expression right_side =
5667 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5669 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5672 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5673 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5677 if (InstanceExpression == null)
5681 DoBestMemberChecks (ec, spec);
5684 var fb = spec as FixedFieldSpec;
5685 IVariableReference var = InstanceExpression as IVariableReference;
5687 if (lvalue_instance && var != null && var.VariableInfo != null) {
5688 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5692 IFixedExpression fe = InstanceExpression as IFixedExpression;
5693 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5694 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5697 if (InstanceExpression.eclass != ExprClass.Variable) {
5698 ec.Report.SymbolRelatedToPreviousError (spec);
5699 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5700 TypeManager.GetFullNameSignature (spec));
5701 } else if (var != null && var.IsHoisted) {
5702 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5705 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5709 // Set flow-analysis variable info for struct member access. It will be check later
5710 // for precise error reporting
5712 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5713 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5714 if (rhs != null && variable_info != null)
5715 variable_info.SetStructFieldAssigned (ec, Name);
5718 eclass = ExprClass.Variable;
5722 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5727 var var = fe.InstanceExpression as IVariableReference;
5729 var vi = var.VariableInfo;
5731 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5733 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5735 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5742 fe = fe.InstanceExpression as FieldExpr;
5744 } while (fe != null);
5747 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5749 // The return value is always null. Returning a value simplifies calling code.
5751 if (right_side == EmptyExpression.OutAccess) {
5753 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5754 GetSignatureForError ());
5756 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5757 GetSignatureForError ());
5763 if (right_side == EmptyExpression.LValueMemberAccess) {
5764 // Already reported as CS1648/CS1650
5768 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5770 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5771 GetSignatureForError ());
5773 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5774 GetSignatureForError ());
5781 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5782 GetSignatureForError ());
5784 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5785 GetSignatureForError ());
5791 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5793 if (spec is FixedFieldSpec) {
5794 // It could be much better error message but we want to be error compatible
5795 Error_ValueAssignment (ec, right_side);
5798 Expression e = DoResolve (ec, right_side);
5803 spec.MemberDefinition.SetIsAssigned ();
5805 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5806 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5807 ec.Report.Warning (420, 1, loc,
5808 "`{0}': A volatile field references will not be treated as volatile",
5809 spec.GetSignatureForError ());
5812 if (spec.IsReadOnly) {
5813 // InitOnly fields can only be assigned in constructors or initializers
5814 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5815 return Error_AssignToReadonly (ec, right_side);
5817 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5819 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5820 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5821 return Error_AssignToReadonly (ec, right_side);
5822 // static InitOnly fields cannot be assigned-to in an instance constructor
5823 if (IsStatic && !ec.IsStatic)
5824 return Error_AssignToReadonly (ec, right_side);
5825 // instance constructors can't modify InitOnly fields of other instances of the same type
5826 if (!IsStatic && !(InstanceExpression is This))
5827 return Error_AssignToReadonly (ec, right_side);
5831 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5832 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5833 ec.Report.Warning (197, 1, loc,
5834 "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",
5835 GetSignatureForError ());
5838 eclass = ExprClass.Variable;
5842 public override int GetHashCode ()
5844 return spec.GetHashCode ();
5847 public bool IsFixed {
5850 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5852 IVariableReference variable = InstanceExpression as IVariableReference;
5853 if (variable != null)
5854 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5856 IFixedExpression fe = InstanceExpression as IFixedExpression;
5857 return fe != null && fe.IsFixed;
5861 public override bool Equals (object obj)
5863 FieldExpr fe = obj as FieldExpr;
5867 if (spec != fe.spec)
5870 if (InstanceExpression == null || fe.InstanceExpression == null)
5873 return InstanceExpression.Equals (fe.InstanceExpression);
5876 public void Emit (EmitContext ec, bool leave_copy)
5878 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5882 ec.Emit (OpCodes.Volatile);
5884 ec.Emit (OpCodes.Ldsfld, spec);
5887 EmitInstance (ec, false);
5889 // Optimization for build-in types
5890 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5891 ec.EmitLoadFromPtr (type);
5893 var ff = spec as FixedFieldSpec;
5895 ec.Emit (OpCodes.Ldflda, spec);
5896 ec.Emit (OpCodes.Ldflda, ff.Element);
5899 ec.Emit (OpCodes.Volatile);
5901 ec.Emit (OpCodes.Ldfld, spec);
5907 ec.Emit (OpCodes.Dup);
5909 temp = new LocalTemporary (this.Type);
5915 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5917 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5918 if (isCompound && !(source is DynamicExpressionStatement)) {
5919 if (has_await_source) {
5921 InstanceExpression = InstanceExpression.EmitToField (ec);
5928 if (has_await_source)
5929 source = source.EmitToField (ec);
5931 EmitInstance (ec, prepared);
5937 ec.Emit (OpCodes.Dup);
5939 temp = new LocalTemporary (this.Type);
5944 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5945 ec.Emit (OpCodes.Volatile);
5947 spec.MemberDefinition.SetIsAssigned ();
5950 ec.Emit (OpCodes.Stsfld, spec);
5952 ec.Emit (OpCodes.Stfld, spec);
5962 // Emits store to field with prepared values on stack
5964 public void EmitAssignFromStack (EmitContext ec)
5967 ec.Emit (OpCodes.Stsfld, spec);
5969 ec.Emit (OpCodes.Stfld, spec);
5973 public override void Emit (EmitContext ec)
5978 public override void EmitSideEffect (EmitContext ec)
5980 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5982 if (is_volatile) // || is_marshal_by_ref ())
5983 base.EmitSideEffect (ec);
5986 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5988 if ((mode & AddressOp.Store) != 0)
5989 spec.MemberDefinition.SetIsAssigned ();
5990 if ((mode & AddressOp.Load) != 0)
5991 spec.MemberDefinition.SetIsUsed ();
5994 // Handle initonly fields specially: make a copy and then
5995 // get the address of the copy.
5998 if (spec.IsReadOnly){
6000 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6012 var temp = ec.GetTemporaryLocal (type);
6013 ec.Emit (OpCodes.Stloc, temp);
6014 ec.Emit (OpCodes.Ldloca, temp);
6015 ec.FreeTemporaryLocal (temp, type);
6021 ec.Emit (OpCodes.Ldsflda, spec);
6024 EmitInstance (ec, false);
6025 ec.Emit (OpCodes.Ldflda, spec);
6029 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6031 return MakeExpression (ctx);
6034 public override SLE.Expression MakeExpression (BuilderContext ctx)
6037 return base.MakeExpression (ctx);
6039 return SLE.Expression.Field (
6040 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6041 spec.GetMetaInfo ());
6045 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6047 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6053 // Expression that evaluates to a Property.
6055 // This is not an LValue because we need to re-write the expression. We
6056 // can not take data from the stack and store it.
6058 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6060 Arguments arguments;
6062 public PropertyExpr (PropertySpec spec, Location l)
6065 best_candidate = spec;
6066 type = spec.MemberType;
6071 protected override Arguments Arguments {
6080 protected override TypeSpec DeclaringType {
6082 return best_candidate.DeclaringType;
6086 public override string Name {
6088 return best_candidate.Name;
6092 public override bool IsInstance {
6098 public override bool IsStatic {
6100 return best_candidate.IsStatic;
6104 public override string KindName {
6105 get { return "property"; }
6108 public PropertySpec PropertyInfo {
6110 return best_candidate;
6116 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6118 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6121 var args_count = arguments == null ? 0 : arguments.Count;
6122 if (args_count != body.Parameters.Count && args_count == 0)
6125 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6126 mg.InstanceExpression = InstanceExpression;
6131 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6133 return new PropertyExpr (spec, loc) {
6139 public override Expression CreateExpressionTree (ResolveContext ec)
6142 if (IsSingleDimensionalArrayLength ()) {
6143 args = new Arguments (1);
6144 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6145 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6148 args = new Arguments (2);
6149 if (InstanceExpression == null)
6150 args.Add (new Argument (new NullLiteral (loc)));
6152 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6153 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6154 return CreateExpressionFactoryCall (ec, "Property", args);
6157 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6159 DoResolveLValue (rc, null);
6160 return new TypeOfMethod (Setter, loc);
6163 public override string GetSignatureForError ()
6165 return best_candidate.GetSignatureForError ();
6168 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6171 return base.MakeExpression (ctx);
6173 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6177 public override SLE.Expression MakeExpression (BuilderContext ctx)
6180 return base.MakeExpression (ctx);
6182 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6186 void Error_PropertyNotValid (ResolveContext ec)
6188 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6189 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6190 GetSignatureForError ());
6193 bool IsSingleDimensionalArrayLength ()
6195 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6198 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6199 return ac != null && ac.Rank == 1;
6202 public override void Emit (EmitContext ec, bool leave_copy)
6205 // Special case: length of single dimension array property is turned into ldlen
6207 if (IsSingleDimensionalArrayLength ()) {
6208 EmitInstance (ec, false);
6209 ec.Emit (OpCodes.Ldlen);
6210 ec.Emit (OpCodes.Conv_I4);
6214 base.Emit (ec, leave_copy);
6217 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6220 LocalTemporary await_source_arg = null;
6222 if (isCompound && !(source is DynamicExpressionStatement)) {
6223 emitting_compound_assignment = true;
6226 if (has_await_arguments) {
6227 await_source_arg = new LocalTemporary (Type);
6228 await_source_arg.Store (ec);
6230 args = new Arguments (1);
6231 args.Add (new Argument (await_source_arg));
6234 temp = await_source_arg;
6237 has_await_arguments = false;
6242 ec.Emit (OpCodes.Dup);
6243 temp = new LocalTemporary (this.Type);
6248 args = arguments ?? new Arguments (1);
6252 temp = new LocalTemporary (this.Type);
6254 args.Add (new Argument (temp));
6256 args.Add (new Argument (source));
6260 emitting_compound_assignment = false;
6262 var call = new CallEmitter ();
6263 call.InstanceExpression = InstanceExpression;
6265 call.InstanceExpressionOnStack = true;
6267 call.Emit (ec, Setter, args, loc);
6274 if (await_source_arg != null) {
6275 await_source_arg.Release (ec);
6279 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6281 eclass = ExprClass.PropertyAccess;
6283 if (best_candidate.IsNotCSharpCompatible) {
6284 Error_PropertyNotValid (rc);
6287 ResolveInstanceExpression (rc, right_side);
6289 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6290 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6291 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6293 type = p.MemberType;
6297 DoBestMemberChecks (rc, best_candidate);
6299 // Handling of com-imported properties with any number of default property parameters
6300 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6301 var p = best_candidate.Get.Parameters;
6302 arguments = new Arguments (p.Count);
6303 for (int i = 0; i < p.Count; ++i) {
6304 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6306 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6307 var p = best_candidate.Set.Parameters;
6308 arguments = new Arguments (p.Count - 1);
6309 for (int i = 0; i < p.Count - 1; ++i) {
6310 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6317 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6319 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6323 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6325 // getter and setter can be different for base calls
6326 MethodSpec getter, setter;
6327 protected T best_candidate;
6329 protected LocalTemporary temp;
6330 protected bool emitting_compound_assignment;
6331 protected bool has_await_arguments;
6333 protected PropertyOrIndexerExpr (Location l)
6340 protected abstract Arguments Arguments { get; set; }
6342 public MethodSpec Getter {
6351 public MethodSpec Setter {
6362 protected override Expression DoResolve (ResolveContext ec)
6364 if (eclass == ExprClass.Unresolved) {
6365 var expr = OverloadResolve (ec, null);
6370 return expr.Resolve (ec);
6373 if (!ResolveGetter (ec))
6379 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6381 if (right_side == EmptyExpression.OutAccess) {
6382 // TODO: best_candidate can be null at this point
6383 INamedBlockVariable variable = null;
6384 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6385 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6386 best_candidate.Name);
6388 right_side.DoResolveLValue (ec, this);
6393 if (eclass == ExprClass.Unresolved) {
6394 var expr = OverloadResolve (ec, right_side);
6399 return expr.ResolveLValue (ec, right_side);
6402 if (!ResolveSetter (ec))
6409 // Implements the IAssignMethod interface for assignments
6411 public virtual void Emit (EmitContext ec, bool leave_copy)
6413 var call = new CallEmitter ();
6414 call.InstanceExpression = InstanceExpression;
6415 if (has_await_arguments)
6416 call.HasAwaitArguments = true;
6418 call.DuplicateArguments = emitting_compound_assignment;
6420 call.Emit (ec, Getter, Arguments, loc);
6422 if (call.HasAwaitArguments) {
6423 InstanceExpression = call.InstanceExpression;
6424 Arguments = call.EmittedArguments;
6425 has_await_arguments = true;
6429 ec.Emit (OpCodes.Dup);
6430 temp = new LocalTemporary (Type);
6435 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6437 public override void Emit (EmitContext ec)
6442 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6444 has_await_arguments = true;
6449 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6451 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6453 bool ResolveGetter (ResolveContext rc)
6455 if (!best_candidate.HasGet) {
6456 if (InstanceExpression != EmptyExpression.Null) {
6457 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6458 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6459 best_candidate.GetSignatureForError ());
6462 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6463 if (best_candidate.HasDifferentAccessibility) {
6464 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6465 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6466 TypeManager.CSharpSignature (best_candidate));
6468 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6469 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6473 if (best_candidate.HasDifferentAccessibility) {
6474 CheckProtectedMemberAccess (rc, best_candidate.Get);
6477 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6481 bool ResolveSetter (ResolveContext rc)
6483 if (!best_candidate.HasSet) {
6484 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6485 GetSignatureForError ());
6489 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6490 if (best_candidate.HasDifferentAccessibility) {
6491 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6492 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6493 GetSignatureForError ());
6495 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6496 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6500 if (best_candidate.HasDifferentAccessibility)
6501 CheckProtectedMemberAccess (rc, best_candidate.Set);
6503 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6509 /// Fully resolved expression that evaluates to an Event
6511 public class EventExpr : MemberExpr, IAssignMethod
6513 readonly EventSpec spec;
6516 public EventExpr (EventSpec spec, Location loc)
6524 protected override TypeSpec DeclaringType {
6526 return spec.DeclaringType;
6530 public override string Name {
6536 public override bool IsInstance {
6538 return !spec.IsStatic;
6542 public override bool IsStatic {
6544 return spec.IsStatic;
6548 public override string KindName {
6549 get { return "event"; }
6552 public MethodSpec Operator {
6560 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6563 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6565 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6566 if (spec.BackingField != null &&
6567 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6569 spec.MemberDefinition.SetIsUsed ();
6571 if (!ec.IsObsolete) {
6572 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6574 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6577 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6578 Error_AssignmentEventOnly (ec);
6580 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6582 InstanceExpression = null;
6584 return ml.ResolveMemberAccess (ec, left, original);
6588 return base.ResolveMemberAccess (ec, left, original);
6591 public override Expression CreateExpressionTree (ResolveContext ec)
6593 throw new NotSupportedException ("ET");
6596 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6598 if (right_side == EmptyExpression.EventAddition) {
6599 op = spec.AccessorAdd;
6600 } else if (right_side == EmptyExpression.EventSubtraction) {
6601 op = spec.AccessorRemove;
6605 Error_AssignmentEventOnly (ec);
6609 op = CandidateToBaseOverride (ec, op);
6613 protected override Expression DoResolve (ResolveContext ec)
6615 eclass = ExprClass.EventAccess;
6616 type = spec.MemberType;
6618 ResolveInstanceExpression (ec, null);
6620 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6621 Error_AssignmentEventOnly (ec);
6624 DoBestMemberChecks (ec, spec);
6628 public override void Emit (EmitContext ec)
6630 throw new NotSupportedException ();
6631 //Error_CannotAssign ();
6634 #region IAssignMethod Members
6636 public void Emit (EmitContext ec, bool leave_copy)
6638 throw new NotImplementedException ();
6641 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6643 if (leave_copy || !isCompound)
6644 throw new NotImplementedException ("EventExpr::EmitAssign");
6646 Arguments args = new Arguments (1);
6647 args.Add (new Argument (source));
6649 var call = new CallEmitter ();
6650 call.InstanceExpression = InstanceExpression;
6651 call.Emit (ec, op, args, loc);
6656 void Error_AssignmentEventOnly (ResolveContext ec)
6658 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6659 ec.Report.Error (79, loc,
6660 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6661 GetSignatureForError ());
6663 ec.Report.Error (70, loc,
6664 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6665 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6669 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6671 name = name.Substring (0, name.LastIndexOf ('.'));
6672 base.Error_CannotCallAbstractBase (rc, name);
6675 public override string GetSignatureForError ()
6677 return TypeManager.CSharpSignature (spec);
6680 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6682 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6686 public class TemporaryVariableReference : VariableReference
6688 public class Declarator : Statement
6690 TemporaryVariableReference variable;
6692 public Declarator (TemporaryVariableReference variable)
6694 this.variable = variable;
6698 protected override void DoEmit (EmitContext ec)
6700 variable.li.CreateBuilder (ec);
6703 public override void Emit (EmitContext ec)
6705 // Don't create sequence point
6709 protected override void CloneTo (CloneContext clonectx, Statement target)
6717 public TemporaryVariableReference (LocalVariable li, Location loc)
6720 this.type = li.Type;
6724 public override bool IsLockedByStatement {
6732 public LocalVariable LocalInfo {
6738 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6740 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6741 return new TemporaryVariableReference (li, loc);
6744 protected override Expression DoResolve (ResolveContext ec)
6746 eclass = ExprClass.Variable;
6749 // Don't capture temporary variables except when using
6750 // state machine redirection and block yields
6752 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6753 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6754 ec.IsVariableCapturingRequired) {
6755 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6756 storey.CaptureLocalVariable (ec, li);
6762 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6764 return Resolve (ec);
6767 public override void Emit (EmitContext ec)
6769 li.CreateBuilder (ec);
6774 public void EmitAssign (EmitContext ec, Expression source)
6776 li.CreateBuilder (ec);
6778 EmitAssign (ec, source, false, false);
6781 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6783 return li.HoistedVariant;
6786 public override bool IsFixed {
6787 get { return true; }
6790 public override bool IsRef {
6791 get { return false; }
6794 public override string Name {
6795 get { throw new NotImplementedException (); }
6798 public override void SetHasAddressTaken ()
6800 throw new NotImplementedException ();
6803 protected override ILocalVariable Variable {
6807 public override VariableInfo VariableInfo {
6808 get { return null; }
6811 public override void VerifyDefiniteAssignment (ResolveContext rc)
6817 /// Handles `var' contextual keyword; var becomes a keyword only
6818 /// if no type called var exists in a variable scope
6820 class VarExpr : SimpleName
6822 public VarExpr (Location loc)
6827 public bool InferType (ResolveContext ec, Expression right_side)
6830 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6832 type = right_side.Type;
6833 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6834 ec.Report.Error (815, loc,
6835 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6836 type.GetSignatureForError ());
6840 eclass = ExprClass.Variable;
6844 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6846 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6847 base.Error_TypeOrNamespaceNotFound (ec);
6849 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");