2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public ResolveFlags ExprClassToResolveFlags {
380 case ExprClass.Namespace:
381 return ResolveFlags.Type;
383 case ExprClass.MethodGroup:
384 return ResolveFlags.MethodGroup;
386 case ExprClass.TypeParameter:
387 return ResolveFlags.TypeParameter;
389 case ExprClass.Value:
390 case ExprClass.Variable:
391 case ExprClass.PropertyAccess:
392 case ExprClass.EventAccess:
393 case ExprClass.IndexerAccess:
394 return ResolveFlags.VariableOrValue;
397 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
403 // Implements identical simple name and type-name resolution
405 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
408 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
411 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
412 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
414 if (left is MemberExpr || left is VariableReference) {
415 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
416 if (identical_type != null && identical_type.Type == left.Type)
417 return identical_type;
423 public virtual string GetSignatureForError ()
425 return type.GetDefinition ().GetSignatureForError ();
429 /// Resolves an expression and performs semantic analysis on it.
433 /// Currently Resolve wraps DoResolve to perform sanity
434 /// checking and assertion checking on what we expect from Resolve.
436 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
438 if (eclass != ExprClass.Unresolved) {
439 if ((flags & ExprClassToResolveFlags) == 0) {
440 Error_UnexpectedKind (ec, flags, loc);
454 if ((flags & e.ExprClassToResolveFlags) == 0) {
455 e.Error_UnexpectedKind (ec, flags, loc);
460 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
463 } catch (Exception ex) {
464 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
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 (c.type != InternalType.ErrorType)
530 rc.Report.Error (150, StartLocation, "A constant value is expected");
538 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
540 rc.Module.Compiler.Report.Error (182, loc,
541 "An attribute argument must be a constant expression, typeof expression or array creation expression");
545 /// Emits the code for the expression
549 /// The Emit method is invoked to generate the code
550 /// for the expression.
552 public abstract void Emit (EmitContext ec);
555 // Emit code to branch to @target if this expression is equivalent to @on_true.
556 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
557 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
558 // including the use of conditional branches. Note also that a branch MUST be emitted
559 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
562 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
565 // Emit this expression for its side effects, not for its value.
566 // The default implementation is to emit the value, and then throw it away.
567 // Subclasses can provide more efficient implementations, but those MUST be equivalent
568 public virtual void EmitSideEffect (EmitContext ec)
571 ec.Emit (OpCodes.Pop);
575 // Emits the expression into temporary field variable. The method
576 // should be used for await expressions only
578 public virtual Expression EmitToField (EmitContext ec)
581 // This is the await prepare Emit method. When emitting code like
582 // a + b we emit code like
588 // For await a + await b we have to interfere the flow to keep the
589 // stack clean because await yields from the expression. The emit
592 // a = a.EmitToField () // a is changed to temporary field access
593 // b = b.EmitToField ()
599 // The idea is to emit expression and leave the stack empty with
600 // result value still available.
602 // Expressions should override this default implementation when
603 // optimized version can be provided (e.g. FieldExpr)
606 // We can optimize for side-effect free expressions, they can be
607 // emitted out of order
609 if (IsSideEffectFree)
612 bool needs_temporary = ContainsEmitWithAwait ();
613 if (!needs_temporary)
616 // Emit original code
617 var field = EmitToFieldSource (ec);
620 // Store the result to temporary field when we
621 // cannot load `this' directly
623 field = ec.GetTemporaryField (type);
624 if (needs_temporary) {
626 // Create temporary local (we cannot load `this' before Emit)
628 var temp = ec.GetTemporaryLocal (type);
629 ec.Emit (OpCodes.Stloc, temp);
632 ec.Emit (OpCodes.Ldloc, temp);
633 field.EmitAssignFromStack (ec);
635 ec.FreeTemporaryLocal (temp, type);
637 field.EmitAssignFromStack (ec);
644 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
647 // Default implementation calls Emit method
653 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
655 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
656 bool contains_await = false;
658 for (int i = 1; i < expressions.Count; ++i) {
659 if (expressions[i].ContainsEmitWithAwait ()) {
660 contains_await = true;
665 if (contains_await) {
666 for (int i = 0; i < expressions.Count; ++i) {
667 expressions[i] = expressions[i].EmitToField (ec);
672 for (int i = 0; i < expressions.Count; ++i) {
673 expressions[i].Emit (ec);
678 /// Protected constructor. Only derivate types should
679 /// be able to be created
682 protected Expression ()
687 /// Returns a fully formed expression after a MemberLookup
690 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
692 if (spec is EventSpec)
693 return new EventExpr ((EventSpec) spec, loc);
694 if (spec is ConstSpec)
695 return new ConstantExpr ((ConstSpec) spec, loc);
696 if (spec is FieldSpec)
697 return new FieldExpr ((FieldSpec) spec, loc);
698 if (spec is PropertySpec)
699 return new PropertyExpr ((PropertySpec) spec, loc);
700 if (spec is TypeSpec)
701 return new TypeExpression (((TypeSpec) spec), loc);
706 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
708 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
710 rc.Report.SymbolRelatedToPreviousError (type);
712 // Report meaningful error for struct as they always have default ctor in C# context
713 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
715 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
716 type.GetSignatureForError ());
722 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
723 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
724 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
727 return r.ResolveMember<MethodSpec> (rc, ref args);
731 public enum MemberLookupRestrictions
740 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
741 // `qualifier_type' or null to lookup members in the current class.
743 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
745 var members = MemberCache.FindMembers (queried_type, name, false);
749 MemberSpec non_method = null;
750 MemberSpec ambig_non_method = null;
752 for (int i = 0; i < members.Count; ++i) {
753 var member = members[i];
755 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
756 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
759 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
762 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
766 if (!member.IsAccessible (rc))
770 // With runtime binder we can have a situation where queried type is inaccessible
771 // because it came via dynamic object, the check about inconsisted accessibility
772 // had no effect as the type was unknown during compilation
775 // private class N { }
777 // public dynamic Foo ()
783 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
787 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
788 if (member is MethodSpec) {
790 // Interface members that are hidden by class members are removed from the set. This
791 // step only has an effect if T is a type parameter and T has both an effective base
792 // class other than object and a non-empty effective interface set
794 var tps = queried_type as TypeParameterSpec;
795 if (tps != null && tps.HasTypeConstraint)
796 members = RemoveHiddenTypeParameterMethods (members);
798 return new MethodGroupExpr (members, queried_type, loc);
801 if (!Invocation.IsMemberInvocable (member))
805 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
807 } else if (!errorMode && !member.IsNotCSharpCompatible) {
809 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
810 // T has both an effective base class other than object and a non-empty effective interface set.
812 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
814 var tps = queried_type as TypeParameterSpec;
815 if (tps != null && tps.HasTypeConstraint) {
816 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
819 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
825 ambig_non_method = member;
829 if (non_method != null) {
830 if (ambig_non_method != null && rc != null) {
831 var report = rc.Module.Compiler.Report;
832 report.SymbolRelatedToPreviousError (non_method);
833 report.SymbolRelatedToPreviousError (ambig_non_method);
834 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
835 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
838 if (non_method is MethodSpec)
839 return new MethodGroupExpr (members, queried_type, loc);
841 return ExprClassFromMemberInfo (non_method, loc);
844 if (members[0].DeclaringType.BaseType == null)
847 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
849 } while (members != null);
854 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
856 if (members.Count < 2)
860 // If M is a method, then all non-method members declared in an interface declaration
861 // are removed from the set, and all methods with the same signature as M declared in
862 // an interface declaration are removed from the set
866 for (int i = 0; i < members.Count; ++i) {
867 var method = members[i] as MethodSpec;
868 if (method == null) {
871 members = new List<MemberSpec> (members);
874 members.RemoveAt (i--);
878 if (!method.DeclaringType.IsInterface)
881 for (int ii = 0; ii < members.Count; ++ii) {
882 var candidate = members[ii] as MethodSpec;
883 if (candidate == null || !candidate.DeclaringType.IsClass)
886 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
891 members = new List<MemberSpec> (members);
894 members.RemoveAt (i--);
902 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
904 throw new NotImplementedException ();
907 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
909 if (t == InternalType.ErrorType)
912 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
913 oper, t.GetSignatureForError ());
916 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
918 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
922 /// Returns an expression that can be used to invoke operator true
923 /// on the expression if it exists.
925 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
927 return GetOperatorTrueOrFalse (ec, e, true, loc);
931 /// Returns an expression that can be used to invoke operator false
932 /// on the expression if it exists.
934 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
936 return GetOperatorTrueOrFalse (ec, e, false, loc);
939 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
941 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
942 var methods = MemberCache.GetUserOperator (e.type, op, false);
946 Arguments arguments = new Arguments (1);
947 arguments.Add (new Argument (e));
949 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
950 var oper = res.ResolveOperator (ec, ref arguments);
955 return new UserOperatorCall (oper, arguments, null, loc);
958 public virtual string ExprClassName
962 case ExprClass.Unresolved:
964 case ExprClass.Value:
966 case ExprClass.Variable:
968 case ExprClass.Namespace:
972 case ExprClass.MethodGroup:
973 return "method group";
974 case ExprClass.PropertyAccess:
975 return "property access";
976 case ExprClass.EventAccess:
977 return "event access";
978 case ExprClass.IndexerAccess:
979 return "indexer access";
980 case ExprClass.Nothing:
982 case ExprClass.TypeParameter:
983 return "type parameter";
985 throw new Exception ("Should not happen");
990 /// Reports that we were expecting `expr' to be of class `expected'
992 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
994 var name = memberExpr.GetSignatureForError ();
996 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
999 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1001 string [] valid = new string [4];
1004 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1005 valid [count++] = "variable";
1006 valid [count++] = "value";
1009 if ((flags & ResolveFlags.Type) != 0)
1010 valid [count++] = "type";
1012 if ((flags & ResolveFlags.MethodGroup) != 0)
1013 valid [count++] = "method group";
1016 valid [count++] = "unknown";
1018 StringBuilder sb = new StringBuilder (valid [0]);
1019 for (int i = 1; i < count - 1; i++) {
1021 sb.Append (valid [i]);
1024 sb.Append ("' or `");
1025 sb.Append (valid [count - 1]);
1028 ec.Report.Error (119, loc,
1029 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1032 public static void UnsafeError (ResolveContext ec, Location loc)
1034 UnsafeError (ec.Report, loc);
1037 public static void UnsafeError (Report Report, Location loc)
1039 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1043 // Converts `source' to an int, uint, long or ulong.
1045 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1047 var btypes = ec.BuiltinTypes;
1049 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1050 Arguments args = new Arguments (1);
1051 args.Add (new Argument (source));
1052 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1055 Expression converted;
1057 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1058 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1059 if (converted == null)
1060 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1061 if (converted == null)
1062 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1063 if (converted == null)
1064 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1066 if (converted == null) {
1067 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1073 // Only positive constants are allowed at compile time
1075 Constant c = converted as Constant;
1076 if (c != null && c.IsNegative)
1077 Error_NegativeArrayIndex (ec, source.loc);
1079 // No conversion needed to array index
1080 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1083 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1087 // Derived classes implement this method by cloning the fields that
1088 // could become altered during the Resolve stage
1090 // Only expressions that are created for the parser need to implement
1093 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1095 throw new NotImplementedException (
1097 "CloneTo not implemented for expression {0}", this.GetType ()));
1101 // Clones an expression created by the parser.
1103 // We only support expressions created by the parser so far, not
1104 // expressions that have been resolved (many more classes would need
1105 // to implement CloneTo).
1107 // This infrastructure is here merely for Lambda expressions which
1108 // compile the same code using different type values for the same
1109 // arguments to find the correct overload
1111 public virtual Expression Clone (CloneContext clonectx)
1113 Expression cloned = (Expression) MemberwiseClone ();
1114 CloneTo (clonectx, cloned);
1120 // Implementation of expression to expression tree conversion
1122 public abstract Expression CreateExpressionTree (ResolveContext ec);
1124 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1126 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1129 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1131 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1134 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1136 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1139 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1141 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1145 return new TypeExpression (t, loc);
1149 // Implemented by all expressions which support conversion from
1150 // compiler expression to invokable runtime expression. Used by
1151 // dynamic C# binder.
1153 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1155 throw new NotImplementedException ("MakeExpression for " + GetType ());
1158 public virtual object Accept (StructuralVisitor visitor)
1160 return visitor.Visit (this);
1165 /// This is just a base class for expressions that can
1166 /// appear on statements (invocations, object creation,
1167 /// assignments, post/pre increment and decrement). The idea
1168 /// being that they would support an extra Emition interface that
1169 /// does not leave a result on the stack.
1171 public abstract class ExpressionStatement : Expression
1173 public ExpressionStatement ResolveStatement (BlockContext ec)
1175 Expression e = Resolve (ec);
1179 ExpressionStatement es = e as ExpressionStatement;
1181 Error_InvalidExpressionStatement (ec);
1184 // This is quite expensive warning, try to limit the damage
1186 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1187 WarningAsyncWithoutWait (ec, e);
1193 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1195 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1196 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1201 // Need to do full resolve because GetAwaiter can be extension method
1202 // available only in this context
1204 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1208 var arguments = new Arguments (0);
1209 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1214 // Use same check rules as for real await
1216 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1217 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1220 bc.Report.Warning (4014, 1, e.Location,
1221 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1225 var inv = e as Invocation;
1226 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1227 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1228 bc.Report.Warning (4014, 1, e.Location,
1229 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1235 /// Requests the expression to be emitted in a `statement'
1236 /// context. This means that no new value is left on the
1237 /// stack after invoking this method (constrasted with
1238 /// Emit that will always leave a value on the stack).
1240 public abstract void EmitStatement (EmitContext ec);
1242 public override void EmitSideEffect (EmitContext ec)
1249 /// This kind of cast is used to encapsulate the child
1250 /// whose type is child.Type into an expression that is
1251 /// reported to return "return_type". This is used to encapsulate
1252 /// expressions which have compatible types, but need to be dealt
1253 /// at higher levels with.
1255 /// For example, a "byte" expression could be encapsulated in one
1256 /// of these as an "unsigned int". The type for the expression
1257 /// would be "unsigned int".
1260 public abstract class TypeCast : Expression
1262 protected readonly Expression child;
1264 protected TypeCast (Expression child, TypeSpec return_type)
1266 eclass = child.eclass;
1267 loc = child.Location;
1272 public Expression Child {
1278 public override bool ContainsEmitWithAwait ()
1280 return child.ContainsEmitWithAwait ();
1283 public override Expression CreateExpressionTree (ResolveContext ec)
1285 Arguments args = new Arguments (2);
1286 args.Add (new Argument (child.CreateExpressionTree (ec)));
1287 args.Add (new Argument (new TypeOf (type, loc)));
1289 if (type.IsPointer || child.Type.IsPointer)
1290 Error_PointerInsideExpressionTree (ec);
1292 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1295 protected override Expression DoResolve (ResolveContext ec)
1297 // This should never be invoked, we are born in fully
1298 // initialized state.
1303 public override void Emit (EmitContext ec)
1308 public override SLE.Expression MakeExpression (BuilderContext ctx)
1311 return base.MakeExpression (ctx);
1313 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1314 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1315 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1319 protected override void CloneTo (CloneContext clonectx, Expression t)
1324 public override bool IsNull {
1325 get { return child.IsNull; }
1329 public class EmptyCast : TypeCast {
1330 EmptyCast (Expression child, TypeSpec target_type)
1331 : base (child, target_type)
1335 public static Expression Create (Expression child, TypeSpec type)
1337 Constant c = child as Constant;
1339 var enum_constant = c as EnumConstant;
1340 if (enum_constant != null)
1341 c = enum_constant.Child;
1343 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1347 var res = c.ConvertImplicitly (type);
1353 EmptyCast e = child as EmptyCast;
1355 return new EmptyCast (e.child, type);
1357 return new EmptyCast (child, type);
1360 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1362 child.EmitBranchable (ec, label, on_true);
1365 public override void EmitSideEffect (EmitContext ec)
1367 child.EmitSideEffect (ec);
1372 // Used for predefined type user operator (no obsolete check, etc.)
1374 public class OperatorCast : TypeCast
1376 readonly MethodSpec conversion_operator;
1378 public OperatorCast (Expression expr, TypeSpec target_type)
1379 : this (expr, target_type, target_type, false)
1383 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1384 : this (expr, target_type, target_type, find_explicit)
1388 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1389 : base (expr, returnType)
1391 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1392 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1395 foreach (MethodSpec oper in mi) {
1396 if (oper.ReturnType != returnType)
1399 if (oper.Parameters.Types[0] == expr.Type) {
1400 conversion_operator = oper;
1406 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1407 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1410 public override void Emit (EmitContext ec)
1413 ec.Emit (OpCodes.Call, conversion_operator);
1418 // Constant specialization of EmptyCast.
1419 // We need to special case this since an empty cast of
1420 // a constant is still a constant.
1422 public class EmptyConstantCast : Constant
1424 public readonly Constant child;
1426 public EmptyConstantCast (Constant child, TypeSpec type)
1427 : base (child.Location)
1430 throw new ArgumentNullException ("child");
1433 this.eclass = child.eclass;
1437 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1439 if (child.Type == target_type)
1442 // FIXME: check that 'type' can be converted to 'target_type' first
1443 return child.ConvertExplicitly (in_checked_context, target_type);
1446 public override Expression CreateExpressionTree (ResolveContext ec)
1448 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1449 child.CreateExpressionTree (ec),
1450 new TypeOf (type, loc));
1453 Error_PointerInsideExpressionTree (ec);
1455 return CreateExpressionFactoryCall (ec, "Convert", args);
1458 public override bool IsDefaultValue {
1459 get { return child.IsDefaultValue; }
1462 public override bool IsNegative {
1463 get { return child.IsNegative; }
1466 public override bool IsNull {
1467 get { return child.IsNull; }
1470 public override bool IsOneInteger {
1471 get { return child.IsOneInteger; }
1474 public override bool IsSideEffectFree {
1476 return child.IsSideEffectFree;
1480 public override bool IsZeroInteger {
1481 get { return child.IsZeroInteger; }
1484 public override void Emit (EmitContext ec)
1489 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1491 child.EmitBranchable (ec, label, on_true);
1493 // Only to make verifier happy
1494 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1495 ec.Emit (OpCodes.Unbox_Any, type);
1498 public override void EmitSideEffect (EmitContext ec)
1500 child.EmitSideEffect (ec);
1503 public override object GetValue ()
1505 return child.GetValue ();
1508 public override string GetValueAsLiteral ()
1510 return child.GetValueAsLiteral ();
1513 public override long GetValueAsLong ()
1515 return child.GetValueAsLong ();
1518 public override Constant ConvertImplicitly (TypeSpec target_type)
1520 if (type == target_type)
1523 // FIXME: Do we need to check user conversions?
1524 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1527 return child.ConvertImplicitly (target_type);
1532 /// This class is used to wrap literals which belong inside Enums
1534 public class EnumConstant : Constant
1536 public Constant Child;
1538 public EnumConstant (Constant child, TypeSpec enum_type)
1539 : base (child.Location)
1543 this.eclass = ExprClass.Value;
1544 this.type = enum_type;
1547 protected EnumConstant (Location loc)
1552 public override void Emit (EmitContext ec)
1557 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1559 Child.EncodeAttributeValue (rc, enc, Child.Type);
1562 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1564 Child.EmitBranchable (ec, label, on_true);
1567 public override void EmitSideEffect (EmitContext ec)
1569 Child.EmitSideEffect (ec);
1572 public override string GetSignatureForError()
1574 return Type.GetSignatureForError ();
1577 public override object GetValue ()
1579 return Child.GetValue ();
1583 public override object GetTypedValue ()
1586 // The method can be used in dynamic context only (on closed types)
1588 // System.Enum.ToObject cannot be called on dynamic types
1589 // EnumBuilder has to be used, but we cannot use EnumBuilder
1590 // because it does not properly support generics
1592 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1596 public override string GetValueAsLiteral ()
1598 return Child.GetValueAsLiteral ();
1601 public override long GetValueAsLong ()
1603 return Child.GetValueAsLong ();
1606 public EnumConstant Increment()
1608 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1611 public override bool IsDefaultValue {
1613 return Child.IsDefaultValue;
1617 public override bool IsSideEffectFree {
1619 return Child.IsSideEffectFree;
1623 public override bool IsZeroInteger {
1624 get { return Child.IsZeroInteger; }
1627 public override bool IsNegative {
1629 return Child.IsNegative;
1633 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1635 if (Child.Type == target_type)
1638 return Child.ConvertExplicitly (in_checked_context, target_type);
1641 public override Constant ConvertImplicitly (TypeSpec type)
1643 if (this.type == type) {
1647 if (!Convert.ImplicitStandardConversionExists (this, type)){
1651 return Child.ConvertImplicitly (type);
1656 /// This kind of cast is used to encapsulate Value Types in objects.
1658 /// The effect of it is to box the value type emitted by the previous
1661 public class BoxedCast : TypeCast {
1663 public BoxedCast (Expression expr, TypeSpec target_type)
1664 : base (expr, target_type)
1666 eclass = ExprClass.Value;
1669 protected override Expression DoResolve (ResolveContext ec)
1671 // This should never be invoked, we are born in fully
1672 // initialized state.
1677 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1679 // Only boxing to object type is supported
1680 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1681 base.EncodeAttributeValue (rc, enc, targetType);
1685 enc.Encode (child.Type);
1686 child.EncodeAttributeValue (rc, enc, child.Type);
1689 public override void Emit (EmitContext ec)
1693 ec.Emit (OpCodes.Box, child.Type);
1696 public override void EmitSideEffect (EmitContext ec)
1698 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1699 // so, we need to emit the box+pop instructions in most cases
1700 if (child.Type.IsStruct &&
1701 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1702 child.EmitSideEffect (ec);
1704 base.EmitSideEffect (ec);
1708 public class UnboxCast : TypeCast {
1709 public UnboxCast (Expression expr, TypeSpec return_type)
1710 : base (expr, return_type)
1714 protected override Expression DoResolve (ResolveContext ec)
1716 // This should never be invoked, we are born in fully
1717 // initialized state.
1722 public override void Emit (EmitContext ec)
1726 ec.Emit (OpCodes.Unbox_Any, type);
1731 /// This is used to perform explicit numeric conversions.
1733 /// Explicit numeric conversions might trigger exceptions in a checked
1734 /// context, so they should generate the conv.ovf opcodes instead of
1737 public class ConvCast : TypeCast {
1738 public enum Mode : byte {
1739 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1741 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1742 U2_I1, U2_U1, U2_I2, U2_CH,
1743 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1744 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1745 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1746 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1747 CH_I1, CH_U1, CH_I2,
1748 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1749 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1755 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1756 : base (child, return_type)
1761 protected override Expression DoResolve (ResolveContext ec)
1763 // This should never be invoked, we are born in fully
1764 // initialized state.
1769 public override string ToString ()
1771 return String.Format ("ConvCast ({0}, {1})", mode, child);
1774 public override void Emit (EmitContext ec)
1780 public static void Emit (EmitContext ec, Mode mode)
1782 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1784 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1785 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1786 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1787 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1788 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1790 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1791 case Mode.U1_CH: /* nothing */ break;
1793 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1794 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1795 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1796 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1797 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1798 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1800 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1801 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1802 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1803 case Mode.U2_CH: /* nothing */ break;
1805 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1806 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1807 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1808 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1809 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1810 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1811 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1813 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1814 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1815 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1816 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1817 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1818 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1820 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1821 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1822 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1823 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1825 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1826 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1827 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1830 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1831 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1832 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1833 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1834 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1835 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1836 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1837 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1838 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1840 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1841 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1842 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1844 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1845 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1846 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1847 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1848 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1849 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1850 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1851 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1852 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1854 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1855 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1856 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1857 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1858 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1859 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1860 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1861 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1862 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1863 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1865 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1869 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1870 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1871 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1872 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1873 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1875 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1876 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1878 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1879 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1880 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1881 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1882 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1883 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1885 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1886 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1887 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1888 case Mode.U2_CH: /* nothing */ break;
1890 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1891 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1892 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1893 case Mode.I4_U4: /* nothing */ break;
1894 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1895 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1896 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1898 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1899 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1900 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1901 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1902 case Mode.U4_I4: /* nothing */ break;
1903 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1905 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1906 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1907 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1908 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1909 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1910 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1911 case Mode.I8_U8: /* nothing */ break;
1912 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1913 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1915 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1916 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1917 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1918 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1919 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1920 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1921 case Mode.U8_I8: /* nothing */ break;
1922 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1925 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1926 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1927 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1929 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1930 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1931 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1932 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1933 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1934 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1935 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1936 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1937 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1939 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1940 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1941 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1942 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1943 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1944 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1945 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1946 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1947 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1950 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1956 class OpcodeCast : TypeCast
1960 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1961 : base (child, return_type)
1966 protected override Expression DoResolve (ResolveContext ec)
1968 // This should never be invoked, we are born in fully
1969 // initialized state.
1974 public override void Emit (EmitContext ec)
1980 public TypeSpec UnderlyingType {
1981 get { return child.Type; }
1986 // Opcode casts expression with 2 opcodes but only
1987 // single expression tree node
1989 class OpcodeCastDuplex : OpcodeCast
1991 readonly OpCode second;
1993 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1994 : base (child, returnType, first)
1996 this.second = second;
1999 public override void Emit (EmitContext ec)
2007 /// This kind of cast is used to encapsulate a child and cast it
2008 /// to the class requested
2010 public sealed class ClassCast : TypeCast {
2011 readonly bool forced;
2013 public ClassCast (Expression child, TypeSpec return_type)
2014 : base (child, return_type)
2018 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2019 : base (child, return_type)
2021 this.forced = forced;
2024 public override void Emit (EmitContext ec)
2028 bool gen = TypeManager.IsGenericParameter (child.Type);
2030 ec.Emit (OpCodes.Box, child.Type);
2032 if (type.IsGenericParameter) {
2033 ec.Emit (OpCodes.Unbox_Any, type);
2040 ec.Emit (OpCodes.Castclass, type);
2045 // Created during resolving pahse when an expression is wrapped or constantified
2046 // and original expression can be used later (e.g. for expression trees)
2048 public class ReducedExpression : Expression
2050 public sealed class ReducedConstantExpression : EmptyConstantCast
2052 readonly Expression orig_expr;
2054 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2055 : base (expr, expr.Type)
2057 this.orig_expr = orig_expr;
2060 public override Constant ConvertImplicitly (TypeSpec target_type)
2062 Constant c = base.ConvertImplicitly (target_type);
2064 c = new ReducedConstantExpression (c, orig_expr);
2069 public override Expression CreateExpressionTree (ResolveContext ec)
2071 return orig_expr.CreateExpressionTree (ec);
2074 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2076 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2078 c = new ReducedConstantExpression (c, orig_expr);
2082 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2085 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2087 if (orig_expr is Conditional)
2088 child.EncodeAttributeValue (rc, enc, targetType);
2090 base.EncodeAttributeValue (rc, enc, targetType);
2094 sealed class ReducedExpressionStatement : ExpressionStatement
2096 readonly Expression orig_expr;
2097 readonly ExpressionStatement stm;
2099 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2101 this.orig_expr = orig;
2103 this.eclass = stm.eclass;
2104 this.type = stm.Type;
2106 this.loc = orig.Location;
2109 public override bool ContainsEmitWithAwait ()
2111 return stm.ContainsEmitWithAwait ();
2114 public override Expression CreateExpressionTree (ResolveContext ec)
2116 return orig_expr.CreateExpressionTree (ec);
2119 protected override Expression DoResolve (ResolveContext ec)
2124 public override void Emit (EmitContext ec)
2129 public override void EmitStatement (EmitContext ec)
2131 stm.EmitStatement (ec);
2135 readonly Expression expr, orig_expr;
2137 private ReducedExpression (Expression expr, Expression orig_expr)
2140 this.eclass = expr.eclass;
2141 this.type = expr.Type;
2142 this.orig_expr = orig_expr;
2143 this.loc = orig_expr.Location;
2148 public override bool IsSideEffectFree {
2150 return expr.IsSideEffectFree;
2154 public Expression OriginalExpression {
2162 public override bool ContainsEmitWithAwait ()
2164 return expr.ContainsEmitWithAwait ();
2168 // Creates fully resolved expression switcher
2170 public static Constant Create (Constant expr, Expression original_expr)
2172 if (expr.eclass == ExprClass.Unresolved)
2173 throw new ArgumentException ("Unresolved expression");
2175 return new ReducedConstantExpression (expr, original_expr);
2178 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2180 return new ReducedExpressionStatement (s, orig);
2183 public static Expression Create (Expression expr, Expression original_expr)
2185 return Create (expr, original_expr, true);
2189 // Creates unresolved reduce expression. The original expression has to be
2190 // already resolved. Created expression is constant based based on `expr'
2191 // value unless canBeConstant is used
2193 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2195 if (canBeConstant) {
2196 Constant c = expr as Constant;
2198 return Create (c, original_expr);
2201 ExpressionStatement s = expr as ExpressionStatement;
2203 return Create (s, original_expr);
2205 if (expr.eclass == ExprClass.Unresolved)
2206 throw new ArgumentException ("Unresolved expression");
2208 return new ReducedExpression (expr, original_expr);
2211 public override Expression CreateExpressionTree (ResolveContext ec)
2213 return orig_expr.CreateExpressionTree (ec);
2216 protected override Expression DoResolve (ResolveContext ec)
2221 public override void Emit (EmitContext ec)
2226 public override Expression EmitToField (EmitContext ec)
2228 return expr.EmitToField(ec);
2231 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2233 expr.EmitBranchable (ec, target, on_true);
2236 public override SLE.Expression MakeExpression (BuilderContext ctx)
2238 return orig_expr.MakeExpression (ctx);
2243 // Standard composite pattern
2245 public abstract class CompositeExpression : Expression
2247 protected Expression expr;
2249 protected CompositeExpression (Expression expr)
2252 this.loc = expr.Location;
2255 public override bool ContainsEmitWithAwait ()
2257 return expr.ContainsEmitWithAwait ();
2260 public override Expression CreateExpressionTree (ResolveContext rc)
2262 return expr.CreateExpressionTree (rc);
2265 public Expression Child {
2266 get { return expr; }
2269 protected override Expression DoResolve (ResolveContext rc)
2271 expr = expr.Resolve (rc);
2274 eclass = expr.eclass;
2280 public override void Emit (EmitContext ec)
2285 public override bool IsNull {
2286 get { return expr.IsNull; }
2291 // Base of expressions used only to narrow resolve flow
2293 public abstract class ShimExpression : Expression
2295 protected Expression expr;
2297 protected ShimExpression (Expression expr)
2302 public Expression Expr {
2308 protected override void CloneTo (CloneContext clonectx, Expression t)
2313 ShimExpression target = (ShimExpression) t;
2314 target.expr = expr.Clone (clonectx);
2317 public override bool ContainsEmitWithAwait ()
2319 return expr.ContainsEmitWithAwait ();
2322 public override Expression CreateExpressionTree (ResolveContext ec)
2324 throw new NotSupportedException ("ET");
2327 public override void Emit (EmitContext ec)
2329 throw new InternalErrorException ("Missing Resolve call");
2335 // Unresolved type name expressions
2337 public abstract class ATypeNameExpression : FullNamedExpression
2340 protected TypeArguments targs;
2342 protected ATypeNameExpression (string name, Location l)
2348 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2355 protected ATypeNameExpression (string name, int arity, Location l)
2356 : this (name, new UnboundTypeArguments (arity), l)
2362 protected int Arity {
2364 return targs == null ? 0 : targs.Count;
2368 public bool HasTypeArguments {
2370 return targs != null && !targs.IsEmpty;
2374 public string Name {
2383 public TypeArguments TypeArguments {
2391 public override bool Equals (object obj)
2393 ATypeNameExpression atne = obj as ATypeNameExpression;
2394 return atne != null && atne.Name == Name &&
2395 (targs == null || targs.Equals (atne.targs));
2398 public override int GetHashCode ()
2400 return Name.GetHashCode ();
2403 // TODO: Move it to MemberCore
2404 public static string GetMemberType (MemberCore mc)
2410 if (mc is FieldBase)
2412 if (mc is MethodCore)
2414 if (mc is EnumMember)
2422 public override string GetSignatureForError ()
2424 if (targs != null) {
2425 return Name + "<" + targs.GetSignatureForError () + ">";
2431 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2435 /// SimpleName expressions are formed of a single word and only happen at the beginning
2436 /// of a dotted-name.
2438 public class SimpleName : ATypeNameExpression
2440 public SimpleName (string name, Location l)
2445 public SimpleName (string name, TypeArguments args, Location l)
2446 : base (name, args, l)
2450 public SimpleName (string name, int arity, Location l)
2451 : base (name, arity, l)
2455 public SimpleName GetMethodGroup ()
2457 return new SimpleName (Name, targs, loc);
2460 protected override Expression DoResolve (ResolveContext rc)
2462 var e = SimpleNameResolve (rc, null);
2464 var fe = e as FieldExpr;
2466 fe.VerifyAssignedStructField (rc, null);
2472 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2474 return SimpleNameResolve (ec, right_side);
2477 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2479 if (ctx.CurrentType != null) {
2480 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2481 if (member != null) {
2482 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2487 var report = ctx.Module.Compiler.Report;
2489 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2490 if (retval != null) {
2491 report.SymbolRelatedToPreviousError (retval.Type);
2492 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2496 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2497 if (retval != null) {
2498 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2502 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2503 if (ns_candidates != null) {
2504 if (ctx is UsingAliasNamespace.AliasContext) {
2505 report.Error (246, loc,
2506 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2507 ns_candidates[0], Name);
2509 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2510 report.Error (246, loc,
2511 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2515 report.Error (246, loc,
2516 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2521 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2523 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2526 if (fne.Type != null && Arity > 0) {
2527 if (HasTypeArguments) {
2528 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2529 if (ct.ResolveAsType (mc) == null)
2535 return new GenericOpenTypeExpr (fne.Type, loc);
2539 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2541 if (!(fne is Namespace))
2545 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2546 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2547 mc.Module.Compiler.Report.Error (1980, Location,
2548 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2549 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2552 fne = new DynamicTypeExpr (loc);
2553 fne.ResolveAsType (mc);
2559 Error_TypeOrNamespaceNotFound (mc);
2563 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2565 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2568 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2570 int lookup_arity = Arity;
2571 bool errorMode = false;
2573 Block current_block = rc.CurrentBlock;
2574 INamedBlockVariable variable = null;
2575 bool variable_found = false;
2579 // Stage 1: binding to local variables or parameters
2581 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2583 if (current_block != null && lookup_arity == 0) {
2584 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2585 if (!variable.IsDeclared) {
2586 // We found local name in accessible block but it's not
2587 // initialized yet, maybe the user wanted to bind to something else
2589 variable_found = true;
2591 e = variable.CreateReferenceExpression (rc, loc);
2594 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2603 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2605 TypeSpec member_type = rc.CurrentType;
2606 for (; member_type != null; member_type = member_type.DeclaringType) {
2607 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2611 var me = e as MemberExpr;
2613 // The name matches a type, defer to ResolveAsTypeStep
2621 if (variable != null) {
2622 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2623 rc.Report.Error (844, loc,
2624 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2625 Name, me.GetSignatureForError ());
2629 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2630 // Leave it to overload resolution to report correct error
2632 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2633 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2636 // LAMESPEC: again, ignores InvocableOnly
2637 if (variable != null) {
2638 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2639 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2643 // MemberLookup does not check accessors availability, this is actually needed for properties only
2645 var pe = me as PropertyExpr;
2648 // Break as there is no other overload available anyway
2649 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2650 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2653 pe.Getter = pe.PropertyInfo.Get;
2655 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2658 pe.Setter = pe.PropertyInfo.Set;
2663 // TODO: It's used by EventExpr -> FieldExpr transformation only
2664 // TODO: Should go to MemberAccess
2665 me = me.ResolveMemberAccess (rc, null, null);
2669 me.SetTypeArguments (rc, targs);
2676 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2678 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2679 if (IsPossibleTypeOrNamespace (rc)) {
2680 if (variable != null) {
2681 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2682 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2685 return ResolveAsTypeOrNamespace (rc);
2690 if (variable_found) {
2691 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2694 var tparams = rc.CurrentTypeParameters;
2695 if (tparams != null) {
2696 if (tparams.Find (Name) != null) {
2697 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2702 var ct = rc.CurrentType;
2704 if (ct.MemberDefinition.TypeParametersCount > 0) {
2705 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2706 if (ctp.Name == Name) {
2707 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2713 ct = ct.DeclaringType;
2714 } while (ct != null);
2717 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2718 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2720 rc.Report.SymbolRelatedToPreviousError (e.Type);
2721 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2725 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2727 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2728 return ErrorExpression.Instance;
2732 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2734 if (e.Type.Arity != Arity) {
2735 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2739 if (e is TypeExpr) {
2740 // TypeExpression does not have correct location
2741 if (e is TypeExpression)
2742 e = new TypeExpression (e.Type, loc);
2748 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2751 return ErrorExpression.Instance;
2754 if (rc.Module.Evaluator != null) {
2755 var fi = rc.Module.Evaluator.LookupField (Name);
2757 return new FieldExpr (fi.Item1, loc);
2765 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2767 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2772 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2773 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2777 if (right_side != null) {
2778 e = e.ResolveLValue (ec, right_side);
2786 public override object Accept (StructuralVisitor visitor)
2788 return visitor.Visit (this);
2793 /// Represents a namespace or a type. The name of the class was inspired by
2794 /// section 10.8.1 (Fully Qualified Names).
2796 public abstract class FullNamedExpression : Expression
2798 protected override void CloneTo (CloneContext clonectx, Expression target)
2800 // Do nothing, most unresolved type expressions cannot be
2801 // resolved to different type
2804 public override bool ContainsEmitWithAwait ()
2809 public override Expression CreateExpressionTree (ResolveContext ec)
2811 throw new NotSupportedException ("ET");
2814 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2817 // This is used to resolve the expression as a type, a null
2818 // value will be returned if the expression is not a type
2821 public override TypeSpec ResolveAsType (IMemberContext mc)
2823 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2828 TypeExpr te = fne as TypeExpr;
2830 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2838 var dep = type.GetMissingDependencies ();
2840 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2843 if (type.Kind == MemberKind.Void) {
2844 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2848 // Obsolete checks cannot be done when resolving base context as they
2849 // require type dependencies to be set but we are in process of resolving them
2851 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2852 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2853 if (obsolete_attr != null && !mc.IsObsolete) {
2854 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2862 public override void Emit (EmitContext ec)
2864 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2865 GetSignatureForError ());
2870 /// Expression that evaluates to a type
2872 public abstract class TypeExpr : FullNamedExpression
2874 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2880 protected sealed override Expression DoResolve (ResolveContext ec)
2886 public override bool Equals (object obj)
2888 TypeExpr tobj = obj as TypeExpr;
2892 return Type == tobj.Type;
2895 public override int GetHashCode ()
2897 return Type.GetHashCode ();
2902 /// Fully resolved Expression that already evaluated to a type
2904 public class TypeExpression : TypeExpr
2906 public TypeExpression (TypeSpec t, Location l)
2909 eclass = ExprClass.Type;
2913 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2920 /// This class denotes an expression which evaluates to a member
2921 /// of a struct or a class.
2923 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2926 // An instance expression associated with this member, if it's a
2927 // non-static member
2929 public Expression InstanceExpression;
2932 /// The name of this member.
2934 public abstract string Name {
2939 // When base.member is used
2941 public bool IsBase {
2942 get { return InstanceExpression is BaseThis; }
2946 /// Whether this is an instance member.
2948 public abstract bool IsInstance {
2953 /// Whether this is a static member.
2955 public abstract bool IsStatic {
2959 public abstract string KindName {
2963 protected abstract TypeSpec DeclaringType {
2967 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2969 return InstanceExpression.Type;
2974 // Converts best base candidate for virtual method starting from QueriedBaseType
2976 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2979 // Only when base.member is used and method is virtual
2985 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2986 // means for base.member access we have to find the closest match after we found best candidate
2988 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2990 // The method could already be what we are looking for
2992 TypeSpec[] targs = null;
2993 if (method.DeclaringType != InstanceExpression.Type) {
2994 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2995 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2996 if (base_override.IsGeneric)
2997 targs = method.TypeArguments;
2999 method = base_override;
3004 // When base access is used inside anonymous method/iterator/etc we need to
3005 // get back to the context of original type. We do it by emiting proxy
3006 // method in original class and rewriting base call to this compiler
3007 // generated method call which does the actual base invocation. This may
3008 // introduce redundant storey but with `this' only but it's tricky to avoid
3009 // at this stage as we don't know what expressions follow base
3011 if (rc.CurrentAnonymousMethod != null) {
3012 if (targs == null && method.IsGeneric) {
3013 targs = method.TypeArguments;
3014 method = method.GetGenericMethodDefinition ();
3017 if (method.Parameters.HasArglist)
3018 throw new NotImplementedException ("__arglist base call proxy");
3020 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3022 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3023 // get/set member expressions second call would fail to proxy because left expression
3024 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3025 // FIXME: The async check is another hack but will probably fail with mutators
3026 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3027 InstanceExpression = new This (loc).Resolve (rc);
3031 method = method.MakeGenericMethod (rc, targs);
3035 // Only base will allow this invocation to happen.
3037 if (method.IsAbstract) {
3038 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3044 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3046 if (InstanceExpression == null)
3049 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3050 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3051 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3056 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3058 if (InstanceExpression == null)
3061 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3064 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3066 var ct = rc.CurrentType;
3067 if (ct == qualifier)
3070 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3073 qualifier = qualifier.GetDefinition ();
3074 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3081 public override bool ContainsEmitWithAwait ()
3083 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3086 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3089 type = type.GetDefinition ();
3091 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3094 type = type.DeclaringType;
3095 } while (type != null);
3100 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3102 if (InstanceExpression != null) {
3103 InstanceExpression = InstanceExpression.Resolve (rc);
3104 CheckProtectedMemberAccess (rc, member);
3107 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3108 UnsafeError (rc, loc);
3111 var dep = member.GetMissingDependencies ();
3113 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3116 if (!rc.IsObsolete) {
3117 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3119 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3122 if (!(member is FieldSpec))
3123 member.MemberDefinition.SetIsUsed ();
3126 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3128 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3131 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3133 rc.Report.SymbolRelatedToPreviousError (member);
3134 rc.Report.Error (1540, loc,
3135 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3136 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3139 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3141 if (!ResolveInstanceExpressionCore (rc, rhs))
3145 // Check intermediate value modification which won't have any effect
3147 if (rhs != null && InstanceExpression.Type.IsStruct &&
3148 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3150 if (rc.CurrentInitializerVariable != null) {
3151 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3152 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3154 rc.Report.Error (1612, loc,
3155 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3156 InstanceExpression.GetSignatureForError ());
3163 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3166 if (InstanceExpression != null) {
3167 if (InstanceExpression is TypeExpr) {
3168 var t = InstanceExpression.Type;
3170 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3171 if (oa != null && !rc.IsObsolete) {
3172 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3175 t = t.DeclaringType;
3176 } while (t != null);
3178 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3179 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3180 rc.Report.Error (176, loc,
3181 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3182 GetSignatureForError ());
3186 InstanceExpression = null;
3192 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3193 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3194 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3195 rc.Report.Error (236, loc,
3196 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3197 GetSignatureForError ());
3199 rc.Report.Error (120, loc,
3200 "An object reference is required to access non-static member `{0}'",
3201 GetSignatureForError ());
3203 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3207 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3208 rc.Report.Error (38, loc,
3209 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3210 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3213 InstanceExpression = new This (loc);
3214 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3215 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3216 InstanceExpression = InstanceExpression.Resolve (rc);
3219 InstanceExpression = InstanceExpression.Resolve (rc);
3225 var me = InstanceExpression as MemberExpr;
3227 me.ResolveInstanceExpressionCore (rc, rhs);
3229 // Using this check to detect probing instance expression resolve
3230 if (!rc.OmitStructFlowAnalysis) {
3231 var fe = me as FieldExpr;
3232 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3233 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3234 rc.Report.Warning (1690, 1, loc,
3235 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3236 me.GetSignatureForError ());
3244 // Run member-access postponed check once we know that
3245 // the expression is not field expression which is the only
3246 // expression which can use uninitialized this
3248 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3249 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3253 // Additional checks for l-value member access
3256 if (InstanceExpression is UnboxCast) {
3257 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3264 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3266 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3267 ec.Report.Warning (1720, 1, left.Location,
3268 "Expression will always cause a `{0}'", "System.NullReferenceException");
3271 InstanceExpression = left;
3275 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3277 TypeSpec instance_type = InstanceExpression.Type;
3278 if (TypeSpec.IsValueType (instance_type)) {
3279 if (InstanceExpression is IMemoryLocation) {
3280 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3282 // Cannot release the temporary variable when its address
3283 // is required to be on stack for any parent
3284 LocalTemporary t = new LocalTemporary (instance_type);
3285 InstanceExpression.Emit (ec);
3287 t.AddressOf (ec, AddressOp.Store);
3290 InstanceExpression.Emit (ec);
3292 // Only to make verifier happy
3293 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3294 ec.Emit (OpCodes.Box, instance_type);
3297 if (prepare_for_load)
3298 ec.Emit (OpCodes.Dup);
3301 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3304 public class ExtensionMethodCandidates
3306 readonly NamespaceContainer container;
3307 readonly IList<MethodSpec> methods;
3309 readonly IMemberContext context;
3311 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3313 this.context = context;
3314 this.methods = methods;
3315 this.container = nsContainer;
3316 this.index = lookupIndex;
3319 public NamespaceContainer Container {
3325 public IMemberContext Context {
3331 public int LookupIndex {
3337 public IList<MethodSpec> Methods {
3345 // Represents a group of extension method candidates for whole namespace
3347 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3349 ExtensionMethodCandidates candidates;
3350 public Expression ExtensionExpression;
3352 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3353 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3355 this.candidates = candidates;
3356 this.ExtensionExpression = extensionExpr;
3359 public override bool IsStatic {
3360 get { return true; }
3364 // For extension methodgroup we are not looking for base members but parent
3365 // namespace extension methods
3367 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3369 // TODO: candidates are null only when doing error reporting, that's
3370 // incorrect. We have to discover same extension methods in error mode
3371 if (candidates == null)
3374 int arity = type_arguments == null ? 0 : type_arguments.Count;
3376 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3377 if (candidates == null)
3380 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3383 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3385 // We are already here
3389 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3391 if (arguments == null)
3392 arguments = new Arguments (1);
3394 ExtensionExpression = ExtensionExpression.Resolve (ec);
3395 if (ExtensionExpression == null)
3398 var cand = candidates;
3399 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3400 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3402 // Restore candidates in case we are running in probing mode
3405 // Store resolved argument and restore original arguments
3407 // Clean-up modified arguments for error reporting
3408 arguments.RemoveAt (0);
3412 var me = ExtensionExpression as MemberExpr;
3414 me.ResolveInstanceExpression (ec, null);
3415 var fe = me as FieldExpr;
3417 fe.Spec.MemberDefinition.SetIsUsed ();
3420 InstanceExpression = null;
3424 #region IErrorHandler Members
3426 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3431 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3433 rc.Report.SymbolRelatedToPreviousError (best);
3434 rc.Report.Error (1928, loc,
3435 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3436 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3439 rc.Report.Error (1929, loc,
3440 "Extension method instance type `{0}' cannot be converted to `{1}'",
3441 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3447 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3452 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3461 /// MethodGroupExpr represents a group of method candidates which
3462 /// can be resolved to the best method overload
3464 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3466 protected IList<MemberSpec> Methods;
3467 MethodSpec best_candidate;
3468 TypeSpec best_candidate_return;
3469 protected TypeArguments type_arguments;
3471 SimpleName simple_name;
3472 protected TypeSpec queried_type;
3474 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3478 this.type = InternalType.MethodGroup;
3480 eclass = ExprClass.MethodGroup;
3481 queried_type = type;
3484 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3485 : this (new MemberSpec[] { m }, type, loc)
3491 public MethodSpec BestCandidate {
3493 return best_candidate;
3497 public TypeSpec BestCandidateReturnType {
3499 return best_candidate_return;
3503 public IList<MemberSpec> Candidates {
3509 protected override TypeSpec DeclaringType {
3511 return queried_type;
3515 public override bool IsInstance {
3517 if (best_candidate != null)
3518 return !best_candidate.IsStatic;
3524 public override bool IsStatic {
3526 if (best_candidate != null)
3527 return best_candidate.IsStatic;
3533 public override string KindName {
3534 get { return "method"; }
3537 public override string Name {
3539 if (best_candidate != null)
3540 return best_candidate.Name;
3543 return Methods.First ().Name;
3550 // When best candidate is already know this factory can be used
3551 // to avoid expensive overload resolution to be called
3553 // NOTE: InstanceExpression has to be set manually
3555 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3557 return new MethodGroupExpr (best, queriedType, loc) {
3558 best_candidate = best,
3559 best_candidate_return = best.ReturnType
3563 public override string GetSignatureForError ()
3565 if (best_candidate != null)
3566 return best_candidate.GetSignatureForError ();
3568 return Methods.First ().GetSignatureForError ();
3571 public override Expression CreateExpressionTree (ResolveContext ec)
3573 if (best_candidate == null) {
3574 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3578 if (best_candidate.IsConditionallyExcluded (ec, loc))
3579 ec.Report.Error (765, loc,
3580 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3582 return new TypeOfMethod (best_candidate, loc);
3585 protected override Expression DoResolve (ResolveContext ec)
3587 this.eclass = ExprClass.MethodGroup;
3589 if (InstanceExpression != null) {
3590 InstanceExpression = InstanceExpression.Resolve (ec);
3591 if (InstanceExpression == null)
3598 public override void Emit (EmitContext ec)
3600 throw new NotSupportedException ();
3603 public void EmitCall (EmitContext ec, Arguments arguments)
3605 var call = new CallEmitter ();
3606 call.InstanceExpression = InstanceExpression;
3607 call.Emit (ec, best_candidate, arguments, loc);
3610 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3612 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3613 Name, target.GetSignatureForError ());
3616 public static bool IsExtensionMethodArgument (Expression expr)
3619 // LAMESPEC: No details about which expressions are not allowed
3621 return !(expr is TypeExpr) && !(expr is BaseThis);
3625 /// Find the Applicable Function Members (7.4.2.1)
3627 /// me: Method Group expression with the members to select.
3628 /// it might contain constructors or methods (or anything
3629 /// that maps to a method).
3631 /// Arguments: ArrayList containing resolved Argument objects.
3633 /// loc: The location if we want an error to be reported, or a Null
3634 /// location for "probing" purposes.
3636 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3637 /// that is the best match of me on Arguments.
3640 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3642 // TODO: causes issues with probing mode, remove explicit Kind check
3643 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3646 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3647 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3648 r.BaseMembersProvider = this;
3649 r.InstanceQualifier = this;
3652 if (cerrors != null)
3653 r.CustomErrors = cerrors;
3655 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3656 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3657 if (best_candidate == null)
3658 return r.BestCandidateIsDynamic ? this : null;
3660 // Overload resolver had to create a new method group, all checks bellow have already been executed
3661 if (r.BestCandidateNewMethodGroup != null)
3662 return r.BestCandidateNewMethodGroup;
3664 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3665 if (InstanceExpression != null) {
3666 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3667 InstanceExpression = null;
3669 if (best_candidate.IsStatic && simple_name != null) {
3670 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3673 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3677 ResolveInstanceExpression (ec, null);
3680 var base_override = CandidateToBaseOverride (ec, best_candidate);
3681 if (base_override == best_candidate) {
3682 best_candidate_return = r.BestCandidateReturnType;
3684 best_candidate = base_override;
3685 best_candidate_return = best_candidate.ReturnType;
3688 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3689 ConstraintChecker cc = new ConstraintChecker (ec);
3690 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3694 // Additional check for possible imported base override method which
3695 // could not be done during IsOverrideMethodBaseTypeAccessible
3697 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3698 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3699 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3700 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3706 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3708 var fe = left as FieldExpr;
3711 // Using method-group on struct fields makes the struct assigned. I am not sure
3712 // why but that's what .net does
3714 fe.Spec.MemberDefinition.SetIsAssigned ();
3717 simple_name = original;
3718 return base.ResolveMemberAccess (ec, left, original);
3721 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3723 type_arguments = ta;
3726 #region IBaseMembersProvider Members
3728 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3730 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3733 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3735 if (queried_type == member.DeclaringType)
3738 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3739 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3743 // Extension methods lookup after ordinary methods candidates failed to apply
3745 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3747 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3750 InstanceExpression = InstanceExpression.Resolve (rc);
3751 if (!IsExtensionMethodArgument (InstanceExpression))
3754 int arity = type_arguments == null ? 0 : type_arguments.Count;
3755 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3756 if (methods == null)
3759 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3760 emg.SetTypeArguments (rc, type_arguments);
3767 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3769 public ConstructorInstanceQualifier (TypeSpec type)
3772 InstanceType = type;
3775 public TypeSpec InstanceType { get; private set; }
3777 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3779 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3783 public struct OverloadResolver
3786 public enum Restrictions
3790 ProbingOnly = 1 << 1,
3791 CovariantDelegate = 1 << 2,
3792 NoBaseMembers = 1 << 3,
3793 BaseMembersIncluded = 1 << 4
3796 public interface IBaseMembersProvider
3798 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3799 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3800 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3803 public interface IErrorHandler
3805 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3806 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3807 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3808 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3811 public interface IInstanceQualifier
3813 TypeSpec InstanceType { get; }
3814 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3817 sealed class NoBaseMembers : IBaseMembersProvider
3819 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3821 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3826 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3831 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3837 struct AmbiguousCandidate
3839 public readonly MemberSpec Member;
3840 public readonly bool Expanded;
3841 public readonly AParametersCollection Parameters;
3843 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3846 Parameters = parameters;
3847 Expanded = expanded;
3852 IList<MemberSpec> members;
3853 TypeArguments type_arguments;
3854 IBaseMembersProvider base_provider;
3855 IErrorHandler custom_errors;
3856 IInstanceQualifier instance_qualifier;
3857 Restrictions restrictions;
3858 MethodGroupExpr best_candidate_extension_group;
3859 TypeSpec best_candidate_return_type;
3861 SessionReportPrinter lambda_conv_msgs;
3863 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3864 : this (members, null, restrictions, loc)
3868 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3871 if (members == null || members.Count == 0)
3872 throw new ArgumentException ("empty members set");
3874 this.members = members;
3876 type_arguments = targs;
3877 this.restrictions = restrictions;
3878 if (IsDelegateInvoke)
3879 this.restrictions |= Restrictions.NoBaseMembers;
3881 base_provider = NoBaseMembers.Instance;
3886 public IBaseMembersProvider BaseMembersProvider {
3888 return base_provider;
3891 base_provider = value;
3895 public bool BestCandidateIsDynamic { get; set; }
3898 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3900 public MethodGroupExpr BestCandidateNewMethodGroup {
3902 return best_candidate_extension_group;
3907 // Return type can be different between best candidate and closest override
3909 public TypeSpec BestCandidateReturnType {
3911 return best_candidate_return_type;
3915 public IErrorHandler CustomErrors {
3917 return custom_errors;
3920 custom_errors = value;
3924 TypeSpec DelegateType {
3926 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3927 throw new InternalErrorException ("Not running in delegate mode", loc);
3929 return members [0].DeclaringType;
3933 public IInstanceQualifier InstanceQualifier {
3935 return instance_qualifier;
3938 instance_qualifier = value;
3942 bool IsProbingOnly {
3944 return (restrictions & Restrictions.ProbingOnly) != 0;
3948 bool IsDelegateInvoke {
3950 return (restrictions & Restrictions.DelegateInvoke) != 0;
3957 // 7.4.3.3 Better conversion from expression
3958 // Returns : 1 if a->p is better,
3959 // 2 if a->q is better,
3960 // 0 if neither is better
3962 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3964 TypeSpec argument_type = a.Type;
3967 // If argument is an anonymous function
3969 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3971 // p and q are delegate types or expression tree types
3973 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3974 if (q.MemberDefinition != p.MemberDefinition) {
3979 // Uwrap delegate from Expression<T>
3981 q = TypeManager.GetTypeArguments (q)[0];
3982 p = TypeManager.GetTypeArguments (p)[0];
3985 var p_m = Delegate.GetInvokeMethod (p);
3986 var q_m = Delegate.GetInvokeMethod (q);
3989 // With identical parameter lists
3991 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4000 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4002 if (p.Kind == MemberKind.Void) {
4003 return q.Kind != MemberKind.Void ? 2 : 0;
4007 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4009 if (q.Kind == MemberKind.Void) {
4010 return p.Kind != MemberKind.Void ? 1: 0;
4013 var am = (AnonymousMethodExpression) a.Expr;
4016 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4017 // better conversion is performed between underlying types Y1 and Y2
4019 if (p.IsGenericTask || q.IsGenericTask) {
4020 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4021 q = q.TypeArguments[0];
4022 p = p.TypeArguments[0];
4024 } else if (q != p) {
4026 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4028 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4029 var am_rt = am.InferReturnType (ec, null, orig_q);
4030 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4032 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4033 var am_rt = am.InferReturnType (ec, null, orig_p);
4034 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4040 // The parameters are identicial and return type is not void, use better type conversion
4041 // on return type to determine better one
4044 if (argument_type == p)
4047 if (argument_type == q)
4051 return BetterTypeConversion (ec, p, q);
4055 // 7.4.3.4 Better conversion from type
4057 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4059 if (p == null || q == null)
4060 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4062 switch (p.BuiltinType) {
4063 case BuiltinTypeSpec.Type.Int:
4064 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4067 case BuiltinTypeSpec.Type.Long:
4068 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4071 case BuiltinTypeSpec.Type.SByte:
4072 switch (q.BuiltinType) {
4073 case BuiltinTypeSpec.Type.Byte:
4074 case BuiltinTypeSpec.Type.UShort:
4075 case BuiltinTypeSpec.Type.UInt:
4076 case BuiltinTypeSpec.Type.ULong:
4080 case BuiltinTypeSpec.Type.Short:
4081 switch (q.BuiltinType) {
4082 case BuiltinTypeSpec.Type.UShort:
4083 case BuiltinTypeSpec.Type.UInt:
4084 case BuiltinTypeSpec.Type.ULong:
4088 case BuiltinTypeSpec.Type.Dynamic:
4089 // Dynamic is never better
4093 switch (q.BuiltinType) {
4094 case BuiltinTypeSpec.Type.Int:
4095 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4098 case BuiltinTypeSpec.Type.Long:
4099 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4102 case BuiltinTypeSpec.Type.SByte:
4103 switch (p.BuiltinType) {
4104 case BuiltinTypeSpec.Type.Byte:
4105 case BuiltinTypeSpec.Type.UShort:
4106 case BuiltinTypeSpec.Type.UInt:
4107 case BuiltinTypeSpec.Type.ULong:
4111 case BuiltinTypeSpec.Type.Short:
4112 switch (p.BuiltinType) {
4113 case BuiltinTypeSpec.Type.UShort:
4114 case BuiltinTypeSpec.Type.UInt:
4115 case BuiltinTypeSpec.Type.ULong:
4119 case BuiltinTypeSpec.Type.Dynamic:
4120 // Dynamic is never better
4124 // FIXME: handle lifted operators
4126 // TODO: this is expensive
4127 Expression p_tmp = new EmptyExpression (p);
4128 Expression q_tmp = new EmptyExpression (q);
4130 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4131 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4133 if (p_to_q && !q_to_p)
4136 if (q_to_p && !p_to_q)
4143 /// Determines "Better function" between candidate
4144 /// and the current best match
4147 /// Returns a boolean indicating :
4148 /// false if candidate ain't better
4149 /// true if candidate is better than the current best match
4151 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4152 MemberSpec best, AParametersCollection bparam, bool best_params)
4154 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4155 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4157 bool better_at_least_one = false;
4159 int args_count = args == null ? 0 : args.Count;
4163 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4166 // Default arguments are ignored for better decision
4167 if (a.IsDefaultArgument)
4171 // When comparing named argument the parameter type index has to be looked up
4172 // in original parameter set (override version for virtual members)
4174 NamedArgument na = a as NamedArgument;
4176 int idx = cparam.GetParameterIndexByName (na.Name);
4177 ct = candidate_pd.Types[idx];
4178 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4179 ct = TypeManager.GetElementType (ct);
4181 idx = bparam.GetParameterIndexByName (na.Name);
4182 bt = best_pd.Types[idx];
4183 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4184 bt = TypeManager.GetElementType (bt);
4186 ct = candidate_pd.Types[c_idx];
4187 bt = best_pd.Types[b_idx];
4189 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4190 ct = TypeManager.GetElementType (ct);
4194 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4195 bt = TypeManager.GetElementType (bt);
4200 if (TypeSpecComparer.IsEqual (ct, bt))
4204 int result = BetterExpressionConversion (ec, a, ct, bt);
4206 // for each argument, the conversion to 'ct' should be no worse than
4207 // the conversion to 'bt'.
4211 // for at least one argument, the conversion to 'ct' should be better than
4212 // the conversion to 'bt'.
4214 better_at_least_one = true;
4217 if (better_at_least_one)
4221 // This handles the case
4223 // Add (float f1, float f2, float f3);
4224 // Add (params decimal [] foo);
4226 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4227 // first candidate would've chosen as better.
4229 if (!same && !a.IsDefaultArgument)
4233 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4237 // This handles the following cases:
4239 // Foo (int i) is better than Foo (int i, long l = 0)
4240 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4241 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4243 // Prefer non-optional version
4245 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4247 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4248 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4251 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4254 return candidate_pd.Count >= best_pd.Count;
4258 // One is a non-generic method and second is a generic method, then non-generic is better
4260 if (best.IsGeneric != candidate.IsGeneric)
4261 return best.IsGeneric;
4264 // This handles the following cases:
4266 // Trim () is better than Trim (params char[] chars)
4267 // Concat (string s1, string s2, string s3) is better than
4268 // Concat (string s1, params string [] srest)
4269 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4271 // Prefer non-expanded version
4273 if (candidate_params != best_params)
4276 int candidate_param_count = candidate_pd.Count;
4277 int best_param_count = best_pd.Count;
4279 if (candidate_param_count != best_param_count)
4280 // can only happen if (candidate_params && best_params)
4281 return candidate_param_count > best_param_count && best_pd.HasParams;
4284 // Both methods have the same number of parameters, and the parameters have equal types
4285 // Pick the "more specific" signature using rules over original (non-inflated) types
4287 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4288 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4290 bool specific_at_least_once = false;
4291 for (j = 0; j < args_count; ++j) {
4292 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4294 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4295 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4297 ct = candidate_def_pd.Types[j];
4298 bt = best_def_pd.Types[j];
4303 TypeSpec specific = MoreSpecific (ct, bt);
4307 specific_at_least_once = true;
4310 if (specific_at_least_once)
4316 static bool CheckInflatedArguments (MethodSpec ms)
4318 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4321 // Setup constraint checker for probing only
4322 ConstraintChecker cc = new ConstraintChecker (null);
4324 var mp = ms.Parameters.Types;
4325 for (int i = 0; i < mp.Length; ++i) {
4326 var type = mp[i] as InflatedTypeSpec;
4330 var targs = type.TypeArguments;
4331 if (targs.Length == 0)
4334 // TODO: Checking inflated MVAR arguments should be enough
4335 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4342 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4344 rc.Report.Error (1729, loc,
4345 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4346 type.GetSignatureForError (), argCount.ToString ());
4350 // Determines if the candidate method is applicable to the given set of arguments
4351 // There could be two different set of parameters for same candidate where one
4352 // is the closest override for default values and named arguments checks and second
4353 // one being the virtual base for the parameter types and modifiers.
4355 // A return value rates candidate method compatibility,
4356 // 0 = the best, int.MaxValue = the worst
4359 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)
4361 // Parameters of most-derived type used mainly for named and optional parameters
4362 var pd = pm.Parameters;
4364 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4365 // params modifier instead of most-derived type
4366 var cpd = ((IParametersMember) candidate).Parameters;
4367 int param_count = pd.Count;
4368 int optional_count = 0;
4370 Arguments orig_args = arguments;
4372 if (arg_count != param_count) {
4374 // No arguments expansion when doing exact match for delegates
4376 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4377 for (int i = 0; i < pd.Count; ++i) {
4378 if (pd.FixedParameters[i].HasDefaultValue) {
4379 optional_count = pd.Count - i;
4385 if (optional_count != 0) {
4386 // Readjust expected number when params used
4387 if (cpd.HasParams) {
4389 if (arg_count < param_count)
4391 } else if (arg_count > param_count) {
4392 int args_gap = System.Math.Abs (arg_count - param_count);
4393 return int.MaxValue - 10000 + args_gap;
4394 } else if (arg_count < param_count - optional_count) {
4395 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4396 return int.MaxValue - 10000 + args_gap;
4398 } else if (arg_count != param_count) {
4399 int args_gap = System.Math.Abs (arg_count - param_count);
4401 return int.MaxValue - 10000 + args_gap;
4402 if (arg_count < param_count - 1)
4403 return int.MaxValue - 10000 + args_gap;
4406 // Resize to fit optional arguments
4407 if (optional_count != 0) {
4408 if (arguments == null) {
4409 arguments = new Arguments (optional_count);
4411 // Have to create a new container, so the next run can do same
4412 var resized = new Arguments (param_count);
4413 resized.AddRange (arguments);
4414 arguments = resized;
4417 for (int i = arg_count; i < param_count; ++i)
4418 arguments.Add (null);
4422 if (arg_count > 0) {
4424 // Shuffle named arguments to the right positions if there are any
4426 if (arguments[arg_count - 1] is NamedArgument) {
4427 arg_count = arguments.Count;
4429 for (int i = 0; i < arg_count; ++i) {
4430 bool arg_moved = false;
4432 NamedArgument na = arguments[i] as NamedArgument;
4436 int index = pd.GetParameterIndexByName (na.Name);
4438 // Named parameter not found
4442 // already reordered
4447 if (index >= param_count) {
4448 // When using parameters which should not be available to the user
4449 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4452 arguments.Add (null);
4456 temp = arguments[index];
4458 // The slot has been taken by positional argument
4459 if (temp != null && !(temp is NamedArgument))
4464 arguments = arguments.MarkOrderedArgument (na);
4468 if (arguments == orig_args) {
4469 arguments = new Arguments (orig_args.Count);
4470 arguments.AddRange (orig_args);
4473 arguments[index] = arguments[i];
4474 arguments[i] = temp;
4481 arg_count = arguments.Count;
4483 } else if (arguments != null) {
4484 arg_count = arguments.Count;
4488 // Don't do any expensive checks when the candidate cannot succeed
4490 if (arg_count != param_count && !cpd.HasParams)
4491 return (param_count - arg_count) * 2 + 1;
4493 var dep = candidate.GetMissingDependencies ();
4495 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4500 // 1. Handle generic method using type arguments when specified or type inference
4503 var ms = candidate as MethodSpec;
4504 if (ms != null && ms.IsGeneric) {
4505 if (type_arguments != null) {
4506 var g_args_count = ms.Arity;
4507 if (g_args_count != type_arguments.Count)
4508 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4510 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4513 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4514 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4515 // candidate was found use the set to report more details about what was wrong with lambda body.
4516 // The general idea is to distinguish between code errors and errors caused by
4517 // trial-and-error type inference
4519 if (lambda_conv_msgs == null) {
4520 for (int i = 0; i < arg_count; i++) {
4521 Argument a = arguments[i];
4525 var am = a.Expr as AnonymousMethodExpression;
4527 if (lambda_conv_msgs == null)
4528 lambda_conv_msgs = new SessionReportPrinter ();
4530 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4535 var ti = new TypeInference (arguments);
4536 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4539 return ti.InferenceScore - 20000;
4542 // Clear any error messages when the result was success
4544 if (lambda_conv_msgs != null)
4545 lambda_conv_msgs.ClearSession ();
4547 if (i_args.Length != 0) {
4548 ms = ms.MakeGenericMethod (ec, i_args);
4553 // Type arguments constraints have to match for the method to be applicable
4555 if (!CheckInflatedArguments (ms)) {
4557 return int.MaxValue - 25000;
4561 // We have a generic return type and at same time the method is override which
4562 // means we have to also inflate override return type in case the candidate is
4563 // best candidate and override return type is different to base return type.
4565 // virtual Foo<T, object> with override Foo<T, dynamic>
4567 if (candidate != pm) {
4568 MethodSpec override_ms = (MethodSpec) pm;
4569 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4570 returnType = inflator.Inflate (returnType);
4572 returnType = ms.ReturnType;
4579 if (type_arguments != null)
4580 return int.MaxValue - 15000;
4586 // 2. Each argument has to be implicitly convertible to method parameter
4588 Parameter.Modifier p_mod = 0;
4591 for (int i = 0; i < arg_count; i++) {
4592 Argument a = arguments[i];
4594 var fp = pd.FixedParameters[i];
4595 if (!fp.HasDefaultValue) {
4596 arguments = orig_args;
4597 return arg_count * 2 + 2;
4601 // Get the default value expression, we can use the same expression
4602 // if the type matches
4604 Expression e = fp.DefaultValue;
4606 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4608 // Restore for possible error reporting
4609 for (int ii = i; ii < arg_count; ++ii)
4610 arguments.RemoveAt (i);
4612 return (arg_count - i) * 2 + 1;
4616 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4618 // LAMESPEC: Attributes can be mixed together with build-in priority
4620 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4621 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4622 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4623 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4624 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4625 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4629 arguments[i] = new Argument (e, Argument.AType.Default);
4633 if (p_mod != Parameter.Modifier.PARAMS) {
4634 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4636 } else if (!params_expanded_form) {
4637 params_expanded_form = true;
4638 pt = ((ElementTypeSpec) pt).Element;
4644 if (!params_expanded_form) {
4645 if (a.ArgType == Argument.AType.ExtensionType) {
4647 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4649 // LAMESPEC: or implicit type parameter conversion
4652 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4653 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4654 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4659 score = IsArgumentCompatible (ec, a, p_mod, pt);
4662 dynamicArgument = true;
4667 // It can be applicable in expanded form (when not doing exact match like for delegates)
4669 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4670 if (!params_expanded_form) {
4671 pt = ((ElementTypeSpec) pt).Element;
4675 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4678 params_expanded_form = true;
4679 dynamicArgument = true;
4680 } else if (score == 0 || arg_count > pd.Count) {
4681 params_expanded_form = true;
4686 if (params_expanded_form)
4688 return (arg_count - i) * 2 + score;
4693 // When params parameter has no argument it will be provided later if the method is the best candidate
4695 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4696 params_expanded_form = true;
4699 // Restore original arguments for dynamic binder to keep the intention of original source code
4701 if (dynamicArgument)
4702 arguments = orig_args;
4707 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4709 if (e is Constant && e.Type == ptype)
4713 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4715 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4716 e = new MemberAccess (new MemberAccess (new MemberAccess (
4717 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4718 } else if (e is Constant) {
4720 // Handles int to int? conversions, DefaultParameterValue check
4722 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4726 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4729 return e.Resolve (ec);
4733 // Tests argument compatibility with the parameter
4734 // The possible return values are
4736 // 1 - modifier mismatch
4737 // 2 - type mismatch
4738 // -1 - dynamic binding required
4740 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4743 // Types have to be identical when ref or out modifer
4744 // is used and argument is not of dynamic type
4746 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4747 if (argument.Type != parameter) {
4749 // Do full equality check after quick path
4751 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4753 // Using dynamic for ref/out parameter can still succeed at runtime
4755 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4762 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4764 // Using dynamic for ref/out parameter can still succeed at runtime
4766 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4773 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4777 // Use implicit conversion in all modes to return same candidates when the expression
4778 // is used as argument or delegate conversion
4780 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4781 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4788 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4790 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4792 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4795 var ac_p = p as ArrayContainer;
4797 var ac_q = q as ArrayContainer;
4801 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4802 if (specific == ac_p.Element)
4804 if (specific == ac_q.Element)
4806 } else if (p.IsGeneric && q.IsGeneric) {
4807 var pargs = TypeManager.GetTypeArguments (p);
4808 var qargs = TypeManager.GetTypeArguments (q);
4810 bool p_specific_at_least_once = false;
4811 bool q_specific_at_least_once = false;
4813 for (int i = 0; i < pargs.Length; i++) {
4814 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4815 if (specific == pargs[i])
4816 p_specific_at_least_once = true;
4817 if (specific == qargs[i])
4818 q_specific_at_least_once = true;
4821 if (p_specific_at_least_once && !q_specific_at_least_once)
4823 if (!p_specific_at_least_once && q_specific_at_least_once)
4831 // Find the best method from candidate list
4833 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4835 List<AmbiguousCandidate> ambiguous_candidates = null;
4837 MemberSpec best_candidate;
4838 Arguments best_candidate_args = null;
4839 bool best_candidate_params = false;
4840 bool best_candidate_dynamic = false;
4841 int best_candidate_rate;
4842 IParametersMember best_parameter_member = null;
4844 int args_count = args != null ? args.Count : 0;
4846 Arguments candidate_args = args;
4847 bool error_mode = false;
4848 MemberSpec invocable_member = null;
4851 best_candidate = null;
4852 best_candidate_rate = int.MaxValue;
4854 var type_members = members;
4856 for (int i = 0; i < type_members.Count; ++i) {
4857 var member = type_members[i];
4860 // Methods in a base class are not candidates if any method in a derived
4861 // class is applicable
4863 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4867 if (!member.IsAccessible (rc))
4870 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4873 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4874 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4879 IParametersMember pm = member as IParametersMember;
4882 // Will use it later to report ambiguity between best method and invocable member
4884 if (Invocation.IsMemberInvocable (member))
4885 invocable_member = member;
4891 // Overload resolution is looking for base member but using parameter names
4892 // and default values from the closest member. That means to do expensive lookup
4893 // for the closest override for virtual or abstract members
4895 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4896 var override_params = base_provider.GetOverrideMemberParameters (member);
4897 if (override_params != null)
4898 pm = override_params;
4902 // Check if the member candidate is applicable
4904 bool params_expanded_form = false;
4905 bool dynamic_argument = false;
4906 TypeSpec rt = pm.MemberType;
4907 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4909 if (lambda_conv_msgs != null)
4910 lambda_conv_msgs.EndSession ();
4913 // How does it score compare to others
4915 if (candidate_rate < best_candidate_rate) {
4917 // Fatal error (missing dependency), cannot continue
4918 if (candidate_rate < 0)
4921 best_candidate_rate = candidate_rate;
4922 best_candidate = member;
4923 best_candidate_args = candidate_args;
4924 best_candidate_params = params_expanded_form;
4925 best_candidate_dynamic = dynamic_argument;
4926 best_parameter_member = pm;
4927 best_candidate_return_type = rt;
4928 } else if (candidate_rate == 0) {
4930 // The member look is done per type for most operations but sometimes
4931 // it's not possible like for binary operators overload because they
4932 // are unioned between 2 sides
4934 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4935 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4940 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4942 // We pack all interface members into top level type which makes the overload resolution
4943 // more complicated for interfaces. We compensate it by removing methods with same
4944 // signature when building the cache hence this path should not really be hit often
4947 // interface IA { void Foo (int arg); }
4948 // interface IB : IA { void Foo (params int[] args); }
4950 // IB::Foo is the best overload when calling IB.Foo (1)
4953 if (ambiguous_candidates != null) {
4954 foreach (var amb_cand in ambiguous_candidates) {
4955 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4964 ambiguous_candidates = null;
4967 // Is the new candidate better
4968 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4972 best_candidate = member;
4973 best_candidate_args = candidate_args;
4974 best_candidate_params = params_expanded_form;
4975 best_candidate_dynamic = dynamic_argument;
4976 best_parameter_member = pm;
4977 best_candidate_return_type = rt;
4979 // It's not better but any other found later could be but we are not sure yet
4980 if (ambiguous_candidates == null)
4981 ambiguous_candidates = new List<AmbiguousCandidate> ();
4983 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4987 // Restore expanded arguments
4988 if (candidate_args != args)
4989 candidate_args = args;
4991 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4994 // We've found exact match
4996 if (best_candidate_rate == 0)
5000 // Try extension methods lookup when no ordinary method match was found and provider enables it
5003 var emg = base_provider.LookupExtensionMethod (rc);
5005 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5007 best_candidate_extension_group = emg;
5008 return (T) (MemberSpec) emg.BestCandidate;
5013 // Don't run expensive error reporting mode for probing
5020 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5023 lambda_conv_msgs = null;
5028 // No best member match found, report an error
5030 if (best_candidate_rate != 0 || error_mode) {
5031 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5035 if (best_candidate_dynamic) {
5036 if (args[0].ArgType == Argument.AType.ExtensionType) {
5037 rc.Report.Error (1973, loc,
5038 "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",
5039 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5043 // Check type constraints only when explicit type arguments are used
5045 if (best_candidate.IsGeneric && type_arguments != null) {
5046 MethodSpec bc = best_candidate as MethodSpec;
5047 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5048 ConstraintChecker cc = new ConstraintChecker (rc);
5049 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5053 BestCandidateIsDynamic = true;
5058 // These flags indicates we are running delegate probing conversion. No need to
5059 // do more expensive checks
5061 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5062 return (T) best_candidate;
5064 if (ambiguous_candidates != null) {
5066 // Now check that there are no ambiguities i.e the selected method
5067 // should be better than all the others
5069 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5070 var candidate = ambiguous_candidates [ix];
5072 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5073 var ambiguous = candidate.Member;
5074 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5075 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5076 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5077 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5078 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5081 return (T) best_candidate;
5086 if (invocable_member != null && !IsProbingOnly) {
5087 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5088 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5089 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5090 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5094 // And now check if the arguments are all
5095 // compatible, perform conversions if
5096 // necessary etc. and return if everything is
5099 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5102 if (best_candidate == null)
5106 // Don't run possibly expensive checks in probing mode
5108 if (!IsProbingOnly && !rc.IsInProbingMode) {
5110 // Check ObsoleteAttribute on the best method
5112 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5113 if (oa != null && !rc.IsObsolete)
5114 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5116 best_candidate.MemberDefinition.SetIsUsed ();
5119 args = best_candidate_args;
5120 return (T) best_candidate;
5123 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5125 return ResolveMember<MethodSpec> (rc, ref args);
5128 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5129 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5131 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5134 if (a.Type == InternalType.ErrorType)
5137 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5138 ec.Report.SymbolRelatedToPreviousError (method);
5139 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5140 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5141 TypeManager.CSharpSignature (method));
5144 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5145 TypeManager.CSharpSignature (method));
5146 } else if (IsDelegateInvoke) {
5147 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5148 DelegateType.GetSignatureForError ());
5150 ec.Report.SymbolRelatedToPreviousError (method);
5151 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5152 method.GetSignatureForError ());
5155 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5157 string index = (idx + 1).ToString ();
5158 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5159 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5160 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5161 index, Parameter.GetModifierSignature (a.Modifier));
5163 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5164 index, Parameter.GetModifierSignature (mod));
5166 string p1 = a.GetSignatureForError ();
5167 string p2 = paramType.GetSignatureForError ();
5170 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5171 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5174 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5175 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5176 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5179 ec.Report.Error (1503, a.Expr.Location,
5180 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5185 // We have failed to find exact match so we return error info about the closest match
5187 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5189 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5190 int arg_count = args == null ? 0 : args.Count;
5192 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5193 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5194 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5198 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5203 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5204 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5205 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5209 // For candidates which match on parameters count report more details about incorrect arguments
5212 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5213 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5214 // Reject any inaccessible member
5215 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5216 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5217 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5221 var ms = best_candidate as MethodSpec;
5222 if (ms != null && ms.IsGeneric) {
5223 bool constr_ok = true;
5224 if (ms.TypeArguments != null)
5225 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5227 if (ta_count == 0) {
5228 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5232 rc.Report.Error (411, loc,
5233 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5234 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5241 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5247 // We failed to find any method with correct argument count, report best candidate
5249 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5252 if (best_candidate.Kind == MemberKind.Constructor) {
5253 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5254 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5255 } else if (IsDelegateInvoke) {
5256 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5257 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5258 DelegateType.GetSignatureForError (), arg_count.ToString ());
5260 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5261 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5262 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5263 name, arg_count.ToString ());
5267 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5269 var pd = pm.Parameters;
5270 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5272 Parameter.Modifier p_mod = 0;
5274 int a_idx = 0, a_pos = 0;
5276 ArrayInitializer params_initializers = null;
5277 bool has_unsafe_arg = pm.MemberType.IsPointer;
5278 int arg_count = args == null ? 0 : args.Count;
5280 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5282 if (p_mod != Parameter.Modifier.PARAMS) {
5283 p_mod = pd.FixedParameters[a_idx].ModFlags;
5285 has_unsafe_arg |= pt.IsPointer;
5287 if (p_mod == Parameter.Modifier.PARAMS) {
5288 if (chose_params_expanded) {
5289 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5290 pt = TypeManager.GetElementType (pt);
5296 // Types have to be identical when ref or out modifer is used
5298 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5299 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5302 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5308 NamedArgument na = a as NamedArgument;
5310 int name_index = pd.GetParameterIndexByName (na.Name);
5311 if (name_index < 0 || name_index >= pd.Count) {
5312 if (IsDelegateInvoke) {
5313 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5314 ec.Report.Error (1746, na.Location,
5315 "The delegate `{0}' does not contain a parameter named `{1}'",
5316 DelegateType.GetSignatureForError (), na.Name);
5318 ec.Report.SymbolRelatedToPreviousError (member);
5319 ec.Report.Error (1739, na.Location,
5320 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5321 TypeManager.CSharpSignature (member), na.Name);
5323 } else if (args[name_index] != a) {
5324 if (IsDelegateInvoke)
5325 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5327 ec.Report.SymbolRelatedToPreviousError (member);
5329 ec.Report.Error (1744, na.Location,
5330 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5335 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5338 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5339 custom_errors.NoArgumentMatch (ec, member);
5343 Expression conv = null;
5344 if (a.ArgType == Argument.AType.ExtensionType) {
5345 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5348 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5350 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5353 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5360 // Convert params arguments to an array initializer
5362 if (params_initializers != null) {
5363 // we choose to use 'a.Expr' rather than 'conv' so that
5364 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5365 params_initializers.Add (a.Expr);
5366 args.RemoveAt (a_idx--);
5371 // Update the argument with the implicit conversion
5375 if (a_idx != arg_count) {
5376 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5381 // Fill not provided arguments required by params modifier
5383 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5385 args = new Arguments (1);
5387 pt = ptypes[pd.Count - 1];
5388 pt = TypeManager.GetElementType (pt);
5389 has_unsafe_arg |= pt.IsPointer;
5390 params_initializers = new ArrayInitializer (0, loc);
5394 // Append an array argument with all params arguments
5396 if (params_initializers != null) {
5397 args.Add (new Argument (
5398 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5402 if (has_unsafe_arg && !ec.IsUnsafe) {
5403 Expression.UnsafeError (ec, loc);
5407 // We could infer inaccesible type arguments
5409 if (type_arguments == null && member.IsGeneric) {
5410 var ms = (MethodSpec) member;
5411 foreach (var ta in ms.TypeArguments) {
5412 if (!ta.IsAccessible (ec)) {
5413 ec.Report.SymbolRelatedToPreviousError (ta);
5414 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5424 public class ConstantExpr : MemberExpr
5426 readonly ConstSpec constant;
5428 public ConstantExpr (ConstSpec constant, Location loc)
5430 this.constant = constant;
5434 public override string Name {
5435 get { throw new NotImplementedException (); }
5438 public override string KindName {
5439 get { return "constant"; }
5442 public override bool IsInstance {
5443 get { return !IsStatic; }
5446 public override bool IsStatic {
5447 get { return true; }
5450 protected override TypeSpec DeclaringType {
5451 get { return constant.DeclaringType; }
5454 public override Expression CreateExpressionTree (ResolveContext ec)
5456 throw new NotSupportedException ("ET");
5459 protected override Expression DoResolve (ResolveContext rc)
5461 ResolveInstanceExpression (rc, null);
5462 DoBestMemberChecks (rc, constant);
5464 var c = constant.GetConstant (rc);
5466 // Creates reference expression to the constant value
5467 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5470 public override void Emit (EmitContext ec)
5472 throw new NotSupportedException ();
5475 public override string GetSignatureForError ()
5477 return constant.GetSignatureForError ();
5480 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5482 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5487 // Fully resolved expression that references a Field
5489 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5491 protected FieldSpec spec;
5492 VariableInfo variable_info;
5494 LocalTemporary temp;
5497 protected FieldExpr (Location l)
5502 public FieldExpr (FieldSpec spec, Location loc)
5507 type = spec.MemberType;
5510 public FieldExpr (FieldBase fi, Location l)
5517 public override string Name {
5523 public bool IsHoisted {
5525 IVariableReference hv = InstanceExpression as IVariableReference;
5526 return hv != null && hv.IsHoisted;
5530 public override bool IsInstance {
5532 return !spec.IsStatic;
5536 public override bool IsStatic {
5538 return spec.IsStatic;
5542 public override string KindName {
5543 get { return "field"; }
5546 public FieldSpec Spec {
5552 protected override TypeSpec DeclaringType {
5554 return spec.DeclaringType;
5558 public VariableInfo VariableInfo {
5560 return variable_info;
5566 public override string GetSignatureForError ()
5568 return spec.GetSignatureForError ();
5571 public bool IsMarshalByRefAccess (ResolveContext rc)
5573 // Checks possible ldflda of field access expression
5574 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5575 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5576 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5579 public void SetHasAddressTaken ()
5581 IVariableReference vr = InstanceExpression as IVariableReference;
5583 vr.SetHasAddressTaken ();
5587 public override Expression CreateExpressionTree (ResolveContext ec)
5589 return CreateExpressionTree (ec, true);
5592 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5595 Expression instance;
5597 if (InstanceExpression == null) {
5598 instance = new NullLiteral (loc);
5599 } else if (convertInstance) {
5600 instance = InstanceExpression.CreateExpressionTree (ec);
5602 args = new Arguments (1);
5603 args.Add (new Argument (InstanceExpression));
5604 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5607 args = Arguments.CreateForExpressionTree (ec, null,
5609 CreateTypeOfExpression ());
5611 return CreateExpressionFactoryCall (ec, "Field", args);
5614 public Expression CreateTypeOfExpression ()
5616 return new TypeOfField (spec, loc);
5619 protected override Expression DoResolve (ResolveContext ec)
5621 spec.MemberDefinition.SetIsUsed ();
5623 return DoResolve (ec, null);
5626 Expression DoResolve (ResolveContext ec, Expression rhs)
5628 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5631 if (ResolveInstanceExpression (ec, rhs)) {
5632 // Resolve the field's instance expression while flow analysis is turned
5633 // off: when accessing a field "a.b", we must check whether the field
5634 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5636 if (lvalue_instance) {
5637 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5638 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5640 Expression right_side =
5641 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5643 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5646 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5647 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5651 if (InstanceExpression == null)
5655 DoBestMemberChecks (ec, spec);
5658 var fb = spec as FixedFieldSpec;
5659 IVariableReference var = InstanceExpression as IVariableReference;
5661 if (lvalue_instance && var != null && var.VariableInfo != null) {
5662 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5666 IFixedExpression fe = InstanceExpression as IFixedExpression;
5667 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5668 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5671 if (InstanceExpression.eclass != ExprClass.Variable) {
5672 ec.Report.SymbolRelatedToPreviousError (spec);
5673 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5674 TypeManager.GetFullNameSignature (spec));
5675 } else if (var != null && var.IsHoisted) {
5676 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5679 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5683 // Set flow-analysis variable info for struct member access. It will be check later
5684 // for precise error reporting
5686 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5687 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5688 if (rhs != null && variable_info != null)
5689 variable_info.SetStructFieldAssigned (ec, Name);
5692 eclass = ExprClass.Variable;
5696 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5701 var var = fe.InstanceExpression as IVariableReference;
5703 var vi = var.VariableInfo;
5705 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5707 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5709 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5716 fe = fe.InstanceExpression as FieldExpr;
5718 } while (fe != null);
5721 static readonly int [] codes = {
5722 191, // instance, write access
5723 192, // instance, out access
5724 198, // static, write access
5725 199, // static, out access
5726 1648, // member of value instance, write access
5727 1649, // member of value instance, out access
5728 1650, // member of value static, write access
5729 1651 // member of value static, out access
5732 static readonly string [] msgs = {
5733 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5734 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5735 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5736 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5737 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5738 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5739 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5740 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5743 // The return value is always null. Returning a value simplifies calling code.
5744 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5747 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5751 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5753 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5758 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5760 if (spec is FixedFieldSpec) {
5761 // It could be much better error message but we want to be error compatible
5762 Error_ValueAssignment (ec, right_side);
5765 Expression e = DoResolve (ec, right_side);
5770 spec.MemberDefinition.SetIsAssigned ();
5772 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5773 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5774 ec.Report.Warning (420, 1, loc,
5775 "`{0}': A volatile field references will not be treated as volatile",
5776 spec.GetSignatureForError ());
5779 if (spec.IsReadOnly) {
5780 // InitOnly fields can only be assigned in constructors or initializers
5781 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5782 return Report_AssignToReadonly (ec, right_side);
5784 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5786 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5787 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5788 return Report_AssignToReadonly (ec, right_side);
5789 // static InitOnly fields cannot be assigned-to in an instance constructor
5790 if (IsStatic && !ec.IsStatic)
5791 return Report_AssignToReadonly (ec, right_side);
5792 // instance constructors can't modify InitOnly fields of other instances of the same type
5793 if (!IsStatic && !(InstanceExpression is This))
5794 return Report_AssignToReadonly (ec, right_side);
5798 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5799 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5800 ec.Report.Warning (197, 1, loc,
5801 "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",
5802 GetSignatureForError ());
5805 eclass = ExprClass.Variable;
5809 public override int GetHashCode ()
5811 return spec.GetHashCode ();
5814 public bool IsFixed {
5817 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5819 IVariableReference variable = InstanceExpression as IVariableReference;
5820 if (variable != null)
5821 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5823 IFixedExpression fe = InstanceExpression as IFixedExpression;
5824 return fe != null && fe.IsFixed;
5828 public override bool Equals (object obj)
5830 FieldExpr fe = obj as FieldExpr;
5834 if (spec != fe.spec)
5837 if (InstanceExpression == null || fe.InstanceExpression == null)
5840 return InstanceExpression.Equals (fe.InstanceExpression);
5843 public void Emit (EmitContext ec, bool leave_copy)
5845 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5849 ec.Emit (OpCodes.Volatile);
5851 ec.Emit (OpCodes.Ldsfld, spec);
5854 EmitInstance (ec, false);
5856 // Optimization for build-in types
5857 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5858 ec.EmitLoadFromPtr (type);
5860 var ff = spec as FixedFieldSpec;
5862 ec.Emit (OpCodes.Ldflda, spec);
5863 ec.Emit (OpCodes.Ldflda, ff.Element);
5866 ec.Emit (OpCodes.Volatile);
5868 ec.Emit (OpCodes.Ldfld, spec);
5874 ec.Emit (OpCodes.Dup);
5876 temp = new LocalTemporary (this.Type);
5882 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5884 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5885 if (isCompound && !(source is DynamicExpressionStatement)) {
5886 if (has_await_source) {
5888 InstanceExpression = InstanceExpression.EmitToField (ec);
5895 if (has_await_source)
5896 source = source.EmitToField (ec);
5898 EmitInstance (ec, prepared);
5904 ec.Emit (OpCodes.Dup);
5906 temp = new LocalTemporary (this.Type);
5911 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5912 ec.Emit (OpCodes.Volatile);
5914 spec.MemberDefinition.SetIsAssigned ();
5917 ec.Emit (OpCodes.Stsfld, spec);
5919 ec.Emit (OpCodes.Stfld, spec);
5929 // Emits store to field with prepared values on stack
5931 public void EmitAssignFromStack (EmitContext ec)
5934 ec.Emit (OpCodes.Stsfld, spec);
5936 ec.Emit (OpCodes.Stfld, spec);
5940 public override void Emit (EmitContext ec)
5945 public override void EmitSideEffect (EmitContext ec)
5947 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5949 if (is_volatile) // || is_marshal_by_ref ())
5950 base.EmitSideEffect (ec);
5953 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5955 if ((mode & AddressOp.Store) != 0)
5956 spec.MemberDefinition.SetIsAssigned ();
5957 if ((mode & AddressOp.Load) != 0)
5958 spec.MemberDefinition.SetIsUsed ();
5961 // Handle initonly fields specially: make a copy and then
5962 // get the address of the copy.
5965 if (spec.IsReadOnly){
5967 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5979 var temp = ec.GetTemporaryLocal (type);
5980 ec.Emit (OpCodes.Stloc, temp);
5981 ec.Emit (OpCodes.Ldloca, temp);
5982 ec.FreeTemporaryLocal (temp, type);
5988 ec.Emit (OpCodes.Ldsflda, spec);
5991 EmitInstance (ec, false);
5992 ec.Emit (OpCodes.Ldflda, spec);
5996 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5998 return MakeExpression (ctx);
6001 public override SLE.Expression MakeExpression (BuilderContext ctx)
6004 return base.MakeExpression (ctx);
6006 return SLE.Expression.Field (
6007 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6008 spec.GetMetaInfo ());
6012 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6014 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6020 // Expression that evaluates to a Property.
6022 // This is not an LValue because we need to re-write the expression. We
6023 // can not take data from the stack and store it.
6025 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6027 Arguments arguments;
6029 public PropertyExpr (PropertySpec spec, Location l)
6032 best_candidate = spec;
6033 type = spec.MemberType;
6038 protected override Arguments Arguments {
6047 protected override TypeSpec DeclaringType {
6049 return best_candidate.DeclaringType;
6053 public override string Name {
6055 return best_candidate.Name;
6059 public override bool IsInstance {
6065 public override bool IsStatic {
6067 return best_candidate.IsStatic;
6071 public override string KindName {
6072 get { return "property"; }
6075 public PropertySpec PropertyInfo {
6077 return best_candidate;
6083 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6085 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6088 var args_count = arguments == null ? 0 : arguments.Count;
6089 if (args_count != body.Parameters.Count && args_count == 0)
6092 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6093 mg.InstanceExpression = InstanceExpression;
6098 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6100 return new PropertyExpr (spec, loc) {
6106 public override Expression CreateExpressionTree (ResolveContext ec)
6109 if (IsSingleDimensionalArrayLength ()) {
6110 args = new Arguments (1);
6111 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6112 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6115 args = new Arguments (2);
6116 if (InstanceExpression == null)
6117 args.Add (new Argument (new NullLiteral (loc)));
6119 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6120 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6121 return CreateExpressionFactoryCall (ec, "Property", args);
6124 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6126 DoResolveLValue (rc, null);
6127 return new TypeOfMethod (Setter, loc);
6130 public override string GetSignatureForError ()
6132 return best_candidate.GetSignatureForError ();
6135 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6138 return base.MakeExpression (ctx);
6140 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6144 public override SLE.Expression MakeExpression (BuilderContext ctx)
6147 return base.MakeExpression (ctx);
6149 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6153 void Error_PropertyNotValid (ResolveContext ec)
6155 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6156 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6157 GetSignatureForError ());
6160 bool IsSingleDimensionalArrayLength ()
6162 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6165 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6166 return ac != null && ac.Rank == 1;
6169 public override void Emit (EmitContext ec, bool leave_copy)
6172 // Special case: length of single dimension array property is turned into ldlen
6174 if (IsSingleDimensionalArrayLength ()) {
6175 EmitInstance (ec, false);
6176 ec.Emit (OpCodes.Ldlen);
6177 ec.Emit (OpCodes.Conv_I4);
6181 base.Emit (ec, leave_copy);
6184 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6187 LocalTemporary await_source_arg = null;
6189 if (isCompound && !(source is DynamicExpressionStatement)) {
6190 emitting_compound_assignment = true;
6193 if (has_await_arguments) {
6194 await_source_arg = new LocalTemporary (Type);
6195 await_source_arg.Store (ec);
6197 args = new Arguments (1);
6198 args.Add (new Argument (await_source_arg));
6201 temp = await_source_arg;
6204 has_await_arguments = false;
6209 ec.Emit (OpCodes.Dup);
6210 temp = new LocalTemporary (this.Type);
6215 args = arguments == null ? new Arguments (1) : arguments;
6219 temp = new LocalTemporary (this.Type);
6221 args.Add (new Argument (temp));
6223 args.Add (new Argument (source));
6227 emitting_compound_assignment = false;
6229 var call = new CallEmitter ();
6230 call.InstanceExpression = InstanceExpression;
6232 call.InstanceExpressionOnStack = true;
6234 call.Emit (ec, Setter, args, loc);
6241 if (await_source_arg != null) {
6242 await_source_arg.Release (ec);
6246 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6248 eclass = ExprClass.PropertyAccess;
6250 if (best_candidate.IsNotCSharpCompatible) {
6251 Error_PropertyNotValid (rc);
6254 ResolveInstanceExpression (rc, right_side);
6256 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6257 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6258 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6260 type = p.MemberType;
6264 DoBestMemberChecks (rc, best_candidate);
6266 // Handling of com-imported properties with any number of default property parameters
6267 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6268 var p = best_candidate.Get.Parameters;
6269 arguments = new Arguments (p.Count);
6270 for (int i = 0; i < p.Count; ++i) {
6271 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6273 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6274 var p = best_candidate.Set.Parameters;
6275 arguments = new Arguments (p.Count - 1);
6276 for (int i = 0; i < p.Count - 1; ++i) {
6277 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6284 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6286 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6290 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6292 // getter and setter can be different for base calls
6293 MethodSpec getter, setter;
6294 protected T best_candidate;
6296 protected LocalTemporary temp;
6297 protected bool emitting_compound_assignment;
6298 protected bool has_await_arguments;
6300 protected PropertyOrIndexerExpr (Location l)
6307 protected abstract Arguments Arguments { get; set; }
6309 public MethodSpec Getter {
6318 public MethodSpec Setter {
6329 protected override Expression DoResolve (ResolveContext ec)
6331 if (eclass == ExprClass.Unresolved) {
6332 var expr = OverloadResolve (ec, null);
6337 return expr.Resolve (ec);
6340 if (!ResolveGetter (ec))
6346 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6348 if (right_side == EmptyExpression.OutAccess) {
6349 // TODO: best_candidate can be null at this point
6350 INamedBlockVariable variable = null;
6351 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6352 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6353 best_candidate.Name);
6355 right_side.DoResolveLValue (ec, this);
6360 if (eclass == ExprClass.Unresolved) {
6361 var expr = OverloadResolve (ec, right_side);
6366 return expr.ResolveLValue (ec, right_side);
6369 if (!ResolveSetter (ec))
6376 // Implements the IAssignMethod interface for assignments
6378 public virtual void Emit (EmitContext ec, bool leave_copy)
6380 var call = new CallEmitter ();
6381 call.InstanceExpression = InstanceExpression;
6382 if (has_await_arguments)
6383 call.HasAwaitArguments = true;
6385 call.DuplicateArguments = emitting_compound_assignment;
6387 call.Emit (ec, Getter, Arguments, loc);
6389 if (call.HasAwaitArguments) {
6390 InstanceExpression = call.InstanceExpression;
6391 Arguments = call.EmittedArguments;
6392 has_await_arguments = true;
6396 ec.Emit (OpCodes.Dup);
6397 temp = new LocalTemporary (Type);
6402 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6404 public override void Emit (EmitContext ec)
6409 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6411 has_await_arguments = true;
6416 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6418 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6420 bool ResolveGetter (ResolveContext rc)
6422 if (!best_candidate.HasGet) {
6423 if (InstanceExpression != EmptyExpression.Null) {
6424 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6425 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6426 best_candidate.GetSignatureForError ());
6429 } else if (!best_candidate.Get.IsAccessible (rc)) {
6430 if (best_candidate.HasDifferentAccessibility) {
6431 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6432 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6433 TypeManager.CSharpSignature (best_candidate));
6435 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6436 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6440 if (best_candidate.HasDifferentAccessibility) {
6441 CheckProtectedMemberAccess (rc, best_candidate.Get);
6444 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6448 bool ResolveSetter (ResolveContext rc)
6450 if (!best_candidate.HasSet) {
6451 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6452 GetSignatureForError ());
6456 if (!best_candidate.Set.IsAccessible (rc)) {
6457 if (best_candidate.HasDifferentAccessibility) {
6458 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6459 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6460 GetSignatureForError ());
6462 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6463 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6467 if (best_candidate.HasDifferentAccessibility)
6468 CheckProtectedMemberAccess (rc, best_candidate.Set);
6470 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6476 /// Fully resolved expression that evaluates to an Event
6478 public class EventExpr : MemberExpr, IAssignMethod
6480 readonly EventSpec spec;
6483 public EventExpr (EventSpec spec, Location loc)
6491 protected override TypeSpec DeclaringType {
6493 return spec.DeclaringType;
6497 public override string Name {
6503 public override bool IsInstance {
6505 return !spec.IsStatic;
6509 public override bool IsStatic {
6511 return spec.IsStatic;
6515 public override string KindName {
6516 get { return "event"; }
6519 public MethodSpec Operator {
6527 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6530 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6532 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6533 if (spec.BackingField != null &&
6534 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6536 spec.MemberDefinition.SetIsUsed ();
6538 if (!ec.IsObsolete) {
6539 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6541 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6544 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6545 Error_AssignmentEventOnly (ec);
6547 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6549 InstanceExpression = null;
6551 return ml.ResolveMemberAccess (ec, left, original);
6555 return base.ResolveMemberAccess (ec, left, original);
6558 public override Expression CreateExpressionTree (ResolveContext ec)
6560 throw new NotSupportedException ("ET");
6563 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6565 if (right_side == EmptyExpression.EventAddition) {
6566 op = spec.AccessorAdd;
6567 } else if (right_side == EmptyExpression.EventSubtraction) {
6568 op = spec.AccessorRemove;
6572 Error_AssignmentEventOnly (ec);
6576 op = CandidateToBaseOverride (ec, op);
6580 protected override Expression DoResolve (ResolveContext ec)
6582 eclass = ExprClass.EventAccess;
6583 type = spec.MemberType;
6585 ResolveInstanceExpression (ec, null);
6587 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6588 Error_AssignmentEventOnly (ec);
6591 DoBestMemberChecks (ec, spec);
6595 public override void Emit (EmitContext ec)
6597 throw new NotSupportedException ();
6598 //Error_CannotAssign ();
6601 #region IAssignMethod Members
6603 public void Emit (EmitContext ec, bool leave_copy)
6605 throw new NotImplementedException ();
6608 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6610 if (leave_copy || !isCompound)
6611 throw new NotImplementedException ("EventExpr::EmitAssign");
6613 Arguments args = new Arguments (1);
6614 args.Add (new Argument (source));
6616 var call = new CallEmitter ();
6617 call.InstanceExpression = InstanceExpression;
6618 call.Emit (ec, op, args, loc);
6623 void Error_AssignmentEventOnly (ResolveContext ec)
6625 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6626 ec.Report.Error (79, loc,
6627 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6628 GetSignatureForError ());
6630 ec.Report.Error (70, loc,
6631 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6632 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6636 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6638 name = name.Substring (0, name.LastIndexOf ('.'));
6639 base.Error_CannotCallAbstractBase (rc, name);
6642 public override string GetSignatureForError ()
6644 return TypeManager.CSharpSignature (spec);
6647 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6649 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6653 public class TemporaryVariableReference : VariableReference
6655 public class Declarator : Statement
6657 TemporaryVariableReference variable;
6659 public Declarator (TemporaryVariableReference variable)
6661 this.variable = variable;
6665 protected override void DoEmit (EmitContext ec)
6667 variable.li.CreateBuilder (ec);
6670 public override void Emit (EmitContext ec)
6672 // Don't create sequence point
6676 protected override void CloneTo (CloneContext clonectx, Statement target)
6684 public TemporaryVariableReference (LocalVariable li, Location loc)
6687 this.type = li.Type;
6691 public override bool IsLockedByStatement {
6699 public LocalVariable LocalInfo {
6705 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6707 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6708 return new TemporaryVariableReference (li, loc);
6711 protected override Expression DoResolve (ResolveContext ec)
6713 eclass = ExprClass.Variable;
6716 // Don't capture temporary variables except when using
6717 // state machine redirection and block yields
6719 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6720 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6721 ec.IsVariableCapturingRequired) {
6722 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6723 storey.CaptureLocalVariable (ec, li);
6729 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6731 return Resolve (ec);
6734 public override void Emit (EmitContext ec)
6736 li.CreateBuilder (ec);
6741 public void EmitAssign (EmitContext ec, Expression source)
6743 li.CreateBuilder (ec);
6745 EmitAssign (ec, source, false, false);
6748 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6750 return li.HoistedVariant;
6753 public override bool IsFixed {
6754 get { return true; }
6757 public override bool IsRef {
6758 get { return false; }
6761 public override string Name {
6762 get { throw new NotImplementedException (); }
6765 public override void SetHasAddressTaken ()
6767 throw new NotImplementedException ();
6770 protected override ILocalVariable Variable {
6774 public override VariableInfo VariableInfo {
6775 get { return null; }
6778 public override void VerifyAssigned (ResolveContext rc)
6784 /// Handles `var' contextual keyword; var becomes a keyword only
6785 /// if no type called var exists in a variable scope
6787 class VarExpr : SimpleName
6789 public VarExpr (Location loc)
6794 public bool InferType (ResolveContext ec, Expression right_side)
6797 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6799 type = right_side.Type;
6800 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6801 ec.Report.Error (815, loc,
6802 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6803 type.GetSignatureForError ());
6807 eclass = ExprClass.Variable;
6811 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6813 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6814 base.Error_TypeOrNamespaceNotFound (ec);
6816 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");