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
131 public ExprClass eclass;
132 protected TypeSpec type;
133 protected Location loc;
135 public TypeSpec Type {
137 set { type = value; }
140 public virtual bool IsSideEffectFree {
146 public Location Location {
150 public virtual bool IsNull {
157 // Used to workaround parser limitation where we cannot get
158 // start of statement expression location
160 public virtual Location StartLocation {
166 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
169 // Return method-group expression when the expression can be used as
170 // lambda replacement. A good example is array sorting where instead of
173 // Array.Sort (s, (a, b) => String.Compare (a, b));
175 // we can use method group directly
177 // Array.Sort (s, String.Compare);
179 // Correct overload will be used because we do the reduction after
180 // best candidate was found.
186 // Returns true when the expression during Emit phase breaks stack
187 // by using await expression
189 public virtual bool ContainsEmitWithAwait ()
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 protected abstract Expression DoResolve (ResolveContext rc);
223 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
234 var rc = mc as ResolveContext ?? new ResolveContext (mc);
235 Expression e = Resolve (rc);
237 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
242 protected void CheckExpressionVariable (ResolveContext rc)
244 if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
245 rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
246 } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
247 rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
251 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
253 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
256 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
258 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
261 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
263 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
264 name, type.GetSignatureForError ());
267 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
269 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
272 public void Error_InvalidExpressionStatement (BlockContext bc)
274 Error_InvalidExpressionStatement (bc.Report, loc);
277 public void Error_InvalidExpressionStatement (Report report)
279 Error_InvalidExpressionStatement (report, loc);
282 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
284 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
287 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
289 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
292 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
294 // The error was already reported as CS1660
295 if (type == InternalType.AnonymousMethod)
298 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
301 if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
302 target.MemberDefinition.DeclaringAssembly.IsMissing)
305 string from_type = type.GetSignatureForError ();
306 string to_type = target.GetSignatureForError ();
307 if (from_type == to_type) {
308 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
309 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
313 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
318 ec.Report.DisableReporting ();
319 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
320 ec.Report.EnableReporting ();
323 ec.Report.Error (266, loc,
324 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
327 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
332 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
334 // Better message for possible generic expressions
335 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
336 var report = context.Module.Compiler.Report;
337 report.SymbolRelatedToPreviousError (member);
338 if (member is TypeSpec)
339 member = ((TypeSpec) member).GetDefinition ();
341 member = ((MethodSpec) member).GetGenericMethodDefinition ();
343 string name = member.Kind == MemberKind.Method ? "method" : "type";
344 if (member.IsGeneric) {
345 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
346 name, member.GetSignatureForError (), member.Arity.ToString ());
348 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
349 name, member.GetSignatureForError ());
352 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
356 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
358 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
362 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
364 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
367 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
369 ec.Report.SymbolRelatedToPreviousError (type);
370 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
371 type.GetSignatureForError (), name);
374 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
376 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
377 // Already reported as CS1612
378 } else if (rhs == EmptyExpression.OutAccess) {
379 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
381 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
385 protected void Error_VoidPointerOperation (ResolveContext rc)
387 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
390 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
392 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
395 public ResolveFlags ExprClassToResolveFlags {
399 case ExprClass.Namespace:
400 return ResolveFlags.Type;
402 case ExprClass.MethodGroup:
403 return ResolveFlags.MethodGroup;
405 case ExprClass.TypeParameter:
406 return ResolveFlags.TypeParameter;
408 case ExprClass.Value:
409 case ExprClass.Variable:
410 case ExprClass.PropertyAccess:
411 case ExprClass.EventAccess:
412 case ExprClass.IndexerAccess:
413 return ResolveFlags.VariableOrValue;
416 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
422 // Implements identical simple name and type-name resolution
424 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
427 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
430 // 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
431 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
433 if (left is MemberExpr || left is VariableReference) {
434 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
435 if (identical_type != null && identical_type.Type == left.Type)
436 return identical_type;
442 public virtual string GetSignatureForError ()
444 return type.GetDefinition ().GetSignatureForError ();
447 public static bool IsNeverNull (Expression expr)
449 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
452 var c = expr as Constant;
456 var tc = expr as TypeCast;
458 return IsNeverNull (tc.Child);
463 protected static bool IsNullPropagatingValid (TypeSpec type)
466 case MemberKind.Struct:
467 return type.IsNullableType;
468 case MemberKind.Enum:
469 case MemberKind.Void:
470 case MemberKind.PointerType:
472 case MemberKind.InternalCompilerType:
473 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
474 case MemberKind.TypeParameter:
475 return !((TypeParameterSpec) type).IsValueType;
481 public virtual bool HasConditionalAccess ()
486 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
488 var tps = type as TypeParameterSpec;
489 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
490 Error_OperatorCannotBeApplied (rc, loc, "?", type);
493 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
494 Nullable.NullableInfo.MakeType (rc.Module, type) :
499 /// Resolves an expression and performs semantic analysis on it.
503 /// Currently Resolve wraps DoResolve to perform sanity
504 /// checking and assertion checking on what we expect from Resolve.
506 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
508 if (eclass != ExprClass.Unresolved) {
509 if ((flags & ExprClassToResolveFlags) == 0) {
510 Error_UnexpectedKind (ec, flags, loc);
524 if ((flags & e.ExprClassToResolveFlags) == 0) {
525 e.Error_UnexpectedKind (ec, flags, loc);
530 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
533 } catch (Exception ex) {
534 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
535 ec.Report.Printer is NullReportPrinter)
538 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
539 return ErrorExpression.Instance; // TODO: Add location
544 /// Resolves an expression and performs semantic analysis on it.
546 public Expression Resolve (ResolveContext rc)
548 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
552 /// Resolves an expression for LValue assignment
556 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
557 /// checking and assertion checking on what we expect from Resolve
559 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
561 int errors = ec.Report.Errors;
562 bool out_access = right_side == EmptyExpression.OutAccess;
564 Expression e = DoResolveLValue (ec, right_side);
566 if (e != null && out_access && !(e is IMemoryLocation)) {
567 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
568 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
570 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
571 // e.GetType () + " " + e.GetSignatureForError ());
576 if (errors == ec.Report.Errors) {
577 Error_ValueAssignment (ec, right_side);
582 if (e.eclass == ExprClass.Unresolved)
583 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
585 if ((e.type == null) && !(e is GenericTypeExpr))
586 throw new Exception ("Expression " + e + " did not set its type after Resolve");
591 public Constant ResolveLabelConstant (ResolveContext rc)
593 var expr = Resolve (rc);
597 Constant c = expr as Constant;
599 if (expr.type != InternalType.ErrorType)
600 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
608 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
610 if (Attribute.IsValidArgumentType (parameterType)) {
611 rc.Module.Compiler.Report.Error (182, loc,
612 "An attribute argument must be a constant expression, typeof expression or array creation expression");
614 rc.Module.Compiler.Report.Error (181, loc,
615 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
616 targetType.GetSignatureForError ());
621 /// Emits the code for the expression
625 /// The Emit method is invoked to generate the code
626 /// for the expression.
628 public abstract void Emit (EmitContext ec);
631 // Emit code to branch to @target if this expression is equivalent to @on_true.
632 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
633 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
634 // including the use of conditional branches. Note also that a branch MUST be emitted
635 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
638 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
641 // Emit this expression for its side effects, not for its value.
642 // The default implementation is to emit the value, and then throw it away.
643 // Subclasses can provide more efficient implementations, but those MUST be equivalent
644 public virtual void EmitSideEffect (EmitContext ec)
647 ec.Emit (OpCodes.Pop);
650 public virtual void EmitPrepare (EmitContext ec)
655 // Emits the expression into temporary field variable. The method
656 // should be used for await expressions only
658 public virtual Expression EmitToField (EmitContext ec)
661 // This is the await prepare Emit method. When emitting code like
662 // a + b we emit code like
668 // For await a + await b we have to interfere the flow to keep the
669 // stack clean because await yields from the expression. The emit
672 // a = a.EmitToField () // a is changed to temporary field access
673 // b = b.EmitToField ()
679 // The idea is to emit expression and leave the stack empty with
680 // result value still available.
682 // Expressions should override this default implementation when
683 // optimized version can be provided (e.g. FieldExpr)
686 // We can optimize for side-effect free expressions, they can be
687 // emitted out of order
689 if (IsSideEffectFree)
692 bool needs_temporary = ContainsEmitWithAwait ();
693 if (!needs_temporary)
696 // Emit original code
697 var field = EmitToFieldSource (ec);
700 // Store the result to temporary field when we
701 // cannot load `this' directly
703 field = ec.GetTemporaryField (type);
704 if (needs_temporary) {
706 // Create temporary local (we cannot load `this' before Emit)
708 var temp = ec.GetTemporaryLocal (type);
709 ec.Emit (OpCodes.Stloc, temp);
712 ec.Emit (OpCodes.Ldloc, temp);
713 field.EmitAssignFromStack (ec);
715 ec.FreeTemporaryLocal (temp, type);
717 field.EmitAssignFromStack (ec);
724 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
727 // Default implementation calls Emit method
733 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
735 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
736 bool contains_await = false;
738 for (int i = 1; i < expressions.Count; ++i) {
739 if (expressions[i].ContainsEmitWithAwait ()) {
740 contains_await = true;
745 if (contains_await) {
746 for (int i = 0; i < expressions.Count; ++i) {
747 expressions[i] = expressions[i].EmitToField (ec);
752 for (int i = 0; i < expressions.Count; ++i) {
753 expressions[i].Emit (ec);
758 /// Protected constructor. Only derivate types should
759 /// be able to be created
762 protected Expression ()
767 /// Returns a fully formed expression after a MemberLookup
770 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
772 if (spec is EventSpec)
773 return new EventExpr ((EventSpec) spec, loc);
774 if (spec is ConstSpec)
775 return new ConstantExpr ((ConstSpec) spec, loc);
776 if (spec is FieldSpec)
777 return new FieldExpr ((FieldSpec) spec, loc);
778 if (spec is PropertySpec)
779 return new PropertyExpr ((PropertySpec) spec, loc);
780 if (spec is TypeSpec)
781 return new TypeExpression (((TypeSpec) spec), loc);
786 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
788 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
791 case MemberKind.Struct:
792 // Every struct has implicit default constructor if not provided by user
796 rc.Report.SymbolRelatedToPreviousError (type);
797 // Report meaningful error for struct as they always have default ctor in C# context
798 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
800 case MemberKind.MissingType:
801 case MemberKind.InternalCompilerType:
802 // LAMESPEC: dynamic is not really object
803 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
807 rc.Report.SymbolRelatedToPreviousError (type);
808 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
809 type.GetSignatureForError ());
816 if (args == null && type.IsStruct) {
817 bool includes_empty = false;
818 foreach (MethodSpec ctor in ctors) {
819 if (ctor.Parameters.IsEmpty) {
820 includes_empty = true;
828 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
829 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
830 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
833 return r.ResolveMember<MethodSpec> (rc, ref args);
837 public enum MemberLookupRestrictions
843 EmptyArguments = 1 << 4,
844 IgnoreArity = 1 << 5,
845 IgnoreAmbiguity = 1 << 6,
846 NameOfExcluded = 1 << 7,
847 DontSetConditionalAccess = 1 << 8
851 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
852 // `qualifier_type' or null to lookup members in the current class.
854 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
856 var members = MemberCache.FindMembers (queried_type, name, false);
858 if (members != null) {
861 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
865 if (members [0].DeclaringType.BaseType == null)
868 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
869 } while (members != null);
872 var tps = queried_type as TypeParameterSpec;
874 members = MemberCache.FindInterfaceMembers (tps, name);
876 return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
879 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
880 var ntuple = queried_type as NamedTupleSpec;
881 if (ntuple != null) {
882 var ms = ntuple.FindElement (rc, name, loc);
884 return ExprClassFromMemberInfo (ms, loc);
891 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
893 MemberSpec non_method = null;
894 MemberSpec ambig_non_method = null;
896 for (int i = 0; i < members.Count; ++i) {
897 var member = members [i];
899 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
900 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
903 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
906 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
910 if (!member.IsAccessible (rc))
914 // With runtime binder we can have a situation where queried type is inaccessible
915 // because it came via dynamic object, the check about inconsisted accessibility
916 // had no effect as the type was unknown during compilation
919 // private class N { }
921 // public dynamic Foo ()
927 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
931 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
932 if (member is MethodSpec) {
933 return new MethodGroupExpr (members, queried_type, loc);
936 if (!Invocation.IsMemberInvocable (member))
940 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
942 } else if (!errorMode && !member.IsNotCSharpCompatible) {
944 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
945 // T has both an effective base class other than object and a non-empty effective interface set.
947 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
949 var tps = queried_type as TypeParameterSpec;
950 if (tps != null && tps.HasTypeConstraint) {
951 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
954 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
960 ambig_non_method = member;
964 if (non_method != null) {
965 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
966 var report = rc.Module.Compiler.Report;
967 report.SymbolRelatedToPreviousError (non_method);
968 report.SymbolRelatedToPreviousError (ambig_non_method);
969 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
970 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
973 if (non_method is MethodSpec)
974 return new MethodGroupExpr (members, queried_type, loc);
976 return ExprClassFromMemberInfo (non_method, loc);
982 protected static void Error_NamedArgument (NamedArgument na, Report Report)
984 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
987 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
989 throw new NotImplementedException ();
992 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
994 if (t == InternalType.ErrorType)
997 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
998 oper, t.GetSignatureForError ());
1001 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1003 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1006 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1008 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1011 protected void Error_NullPropagatingLValue (ResolveContext rc)
1013 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1016 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1020 public virtual Reachability MarkReachable (Reachability rc)
1026 // Special version of flow analysis for expressions which can return different
1027 // on-true and on-false result. Used by &&, ||, ?: expressions
1029 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1032 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1036 /// Returns an expression that can be used to invoke operator true
1037 /// on the expression if it exists.
1039 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1041 return GetOperatorTrueOrFalse (ec, e, true, loc);
1045 /// Returns an expression that can be used to invoke operator false
1046 /// on the expression if it exists.
1048 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1050 return GetOperatorTrueOrFalse (ec, e, false, loc);
1053 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1055 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1057 if (type.IsNullableType)
1058 type = Nullable.NullableInfo.GetUnderlyingType (type);
1060 var methods = MemberCache.GetUserOperator (type, op, false);
1061 if (methods == null)
1064 Arguments arguments = new Arguments (1);
1065 arguments.Add (new Argument (e));
1067 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1068 var oper = res.ResolveOperator (ec, ref arguments);
1073 return new UserOperatorCall (oper, arguments, null, loc);
1076 public virtual string ExprClassName
1080 case ExprClass.Unresolved:
1081 return "Unresolved";
1082 case ExprClass.Value:
1084 case ExprClass.Variable:
1086 case ExprClass.Namespace:
1088 case ExprClass.Type:
1090 case ExprClass.MethodGroup:
1091 return "method group";
1092 case ExprClass.PropertyAccess:
1093 return "property access";
1094 case ExprClass.EventAccess:
1095 return "event access";
1096 case ExprClass.IndexerAccess:
1097 return "indexer access";
1098 case ExprClass.Nothing:
1100 case ExprClass.TypeParameter:
1101 return "type parameter";
1103 throw new Exception ("Should not happen");
1108 /// Reports that we were expecting `expr' to be of class `expected'
1110 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1112 var name = memberExpr.GetSignatureForError ();
1114 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1117 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1119 string [] valid = new string [4];
1122 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1123 valid [count++] = "variable";
1124 valid [count++] = "value";
1127 if ((flags & ResolveFlags.Type) != 0)
1128 valid [count++] = "type";
1130 if ((flags & ResolveFlags.MethodGroup) != 0)
1131 valid [count++] = "method group";
1134 valid [count++] = "unknown";
1136 StringBuilder sb = new StringBuilder (valid [0]);
1137 for (int i = 1; i < count - 1; i++) {
1139 sb.Append (valid [i]);
1142 sb.Append ("' or `");
1143 sb.Append (valid [count - 1]);
1146 ec.Report.Error (119, loc,
1147 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1150 public static void UnsafeError (ResolveContext ec, Location loc)
1152 UnsafeError (ec.Report, loc);
1155 public static void UnsafeError (Report Report, Location loc)
1157 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1160 public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
1162 UnsafeInsideIteratorError (rc.Report, loc);
1165 public static void UnsafeInsideIteratorError (Report report, Location loc)
1167 report.Error (1629, loc, "Unsafe code may not appear in iterators");
1171 // Converts `source' to an int, uint, long or ulong.
1173 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1175 var btypes = ec.BuiltinTypes;
1177 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1178 Arguments args = new Arguments (1);
1179 args.Add (new Argument (source));
1180 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1183 Expression converted;
1185 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1186 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1187 if (converted == null)
1188 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1189 if (converted == null)
1190 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1191 if (converted == null)
1192 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1194 if (converted == null) {
1195 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1204 // Only positive constants are allowed at compile time
1206 Constant c = converted as Constant;
1207 if (c != null && c.IsNegative)
1208 Error_NegativeArrayIndex (ec, source.loc);
1210 // No conversion needed to array index
1211 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1214 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1217 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1219 if (args.Count != 1){
1220 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1225 if (arg is NamedArgument)
1226 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1228 var index = arg.Expr.Resolve (rc);
1232 index = ConvertExpressionToArrayIndex (rc, index, true);
1234 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1235 return new Indirection (p, loc);
1239 // Derived classes implement this method by cloning the fields that
1240 // could become altered during the Resolve stage
1242 // Only expressions that are created for the parser need to implement
1245 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1247 throw new NotImplementedException (
1249 "CloneTo not implemented for expression {0}", this.GetType ()));
1253 // Clones an expression created by the parser.
1255 // We only support expressions created by the parser so far, not
1256 // expressions that have been resolved (many more classes would need
1257 // to implement CloneTo).
1259 // This infrastructure is here merely for Lambda expressions which
1260 // compile the same code using different type values for the same
1261 // arguments to find the correct overload
1263 public virtual Expression Clone (CloneContext clonectx)
1265 Expression cloned = (Expression) MemberwiseClone ();
1266 CloneTo (clonectx, cloned);
1272 // Implementation of expression to expression tree conversion
1274 public abstract Expression CreateExpressionTree (ResolveContext ec);
1276 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1278 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1281 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1283 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1286 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1288 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1291 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1293 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1297 return new TypeExpression (t, loc);
1301 // Implemented by all expressions which support conversion from
1302 // compiler expression to invokable runtime expression. Used by
1303 // dynamic C# binder.
1305 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1307 throw new NotImplementedException ("MakeExpression for " + GetType ());
1310 public virtual object Accept (StructuralVisitor visitor)
1312 return visitor.Visit (this);
1317 /// This is just a base class for expressions that can
1318 /// appear on statements (invocations, object creation,
1319 /// assignments, post/pre increment and decrement). The idea
1320 /// being that they would support an extra Emition interface that
1321 /// does not leave a result on the stack.
1323 public abstract class ExpressionStatement : Expression
1325 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1327 Expression e = Resolve (ec);
1331 ExpressionStatement es = e as ExpressionStatement;
1332 if (es == null || e is AnonymousMethodBody) {
1333 var reduced = e as IReducedExpressionStatement;
1334 if (reduced != null) {
1335 return EmptyExpressionStatement.Instance;
1338 Error_InvalidExpressionStatement (ec);
1342 // This is quite expensive warning, try to limit the damage
1344 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1345 WarningAsyncWithoutWait (ec, e);
1351 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1353 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1354 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1359 // Need to do full resolve because GetAwaiter can be extension method
1360 // available only in this context
1362 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1366 var arguments = new Arguments (0);
1367 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1372 // Use same check rules as for real await
1374 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1375 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1378 bc.Report.Warning (4014, 1, e.Location,
1379 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1383 var inv = e as Invocation;
1384 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1385 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1386 bc.Report.Warning (4014, 1, e.Location,
1387 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1393 /// Requests the expression to be emitted in a `statement'
1394 /// context. This means that no new value is left on the
1395 /// stack after invoking this method (constrasted with
1396 /// Emit that will always leave a value on the stack).
1398 public abstract void EmitStatement (EmitContext ec);
1400 public override void EmitSideEffect (EmitContext ec)
1406 interface IReducedExpressionStatement
1411 /// This kind of cast is used to encapsulate the child
1412 /// whose type is child.Type into an expression that is
1413 /// reported to return "return_type". This is used to encapsulate
1414 /// expressions which have compatible types, but need to be dealt
1415 /// at higher levels with.
1417 /// For example, a "byte" expression could be encapsulated in one
1418 /// of these as an "unsigned int". The type for the expression
1419 /// would be "unsigned int".
1422 public abstract class TypeCast : Expression
1424 protected readonly Expression child;
1426 protected TypeCast (Expression child, TypeSpec return_type)
1428 eclass = child.eclass;
1429 loc = child.Location;
1434 public Expression Child {
1440 public override bool ContainsEmitWithAwait ()
1442 return child.ContainsEmitWithAwait ();
1445 public override Expression CreateExpressionTree (ResolveContext ec)
1447 Arguments args = new Arguments (2);
1448 args.Add (new Argument (child.CreateExpressionTree (ec)));
1449 args.Add (new Argument (new TypeOf (type, loc)));
1451 if (type.IsPointer || child.Type.IsPointer)
1452 Error_PointerInsideExpressionTree (ec);
1454 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1457 protected override Expression DoResolve (ResolveContext ec)
1459 // This should never be invoked, we are born in fully
1460 // initialized state.
1465 public override void Emit (EmitContext ec)
1470 public override void FlowAnalysis (FlowAnalysisContext fc)
1472 child.FlowAnalysis (fc);
1475 public override SLE.Expression MakeExpression (BuilderContext ctx)
1478 return base.MakeExpression (ctx);
1480 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1481 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1482 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1486 public override Reachability MarkReachable (Reachability rc)
1488 return child.MarkReachable (rc);
1491 protected override void CloneTo (CloneContext clonectx, Expression t)
1496 public override bool IsNull {
1497 get { return child.IsNull; }
1501 public class EmptyCast : TypeCast {
1502 EmptyCast (Expression child, TypeSpec target_type)
1503 : base (child, target_type)
1507 public static Expression Create (Expression child, TypeSpec type)
1509 Constant c = child as Constant;
1511 var enum_constant = c as EnumConstant;
1512 if (enum_constant != null)
1513 c = enum_constant.Child;
1515 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1519 var res = c.ConvertImplicitly (type);
1525 EmptyCast e = child as EmptyCast;
1527 return new EmptyCast (e.child, type);
1529 return new EmptyCast (child, type);
1532 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1534 child.EmitBranchable (ec, label, on_true);
1537 public override void EmitSideEffect (EmitContext ec)
1539 child.EmitSideEffect (ec);
1544 // Used for predefined type user operator (no obsolete check, etc.)
1546 public class OperatorCast : TypeCast
1548 readonly MethodSpec conversion_operator;
1550 public OperatorCast (Expression expr, TypeSpec target_type)
1551 : this (expr, target_type, target_type, false)
1555 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1556 : this (expr, target_type, target_type, find_explicit)
1560 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1561 : base (expr, returnType)
1563 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1564 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1567 foreach (MethodSpec oper in mi) {
1568 if (oper.ReturnType != returnType)
1571 if (oper.Parameters.Types[0] == expr.Type) {
1572 conversion_operator = oper;
1578 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1579 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1582 public override void Emit (EmitContext ec)
1585 ec.Emit (OpCodes.Call, conversion_operator);
1590 // Constant specialization of EmptyCast.
1591 // We need to special case this since an empty cast of
1592 // a constant is still a constant.
1594 public class EmptyConstantCast : Constant
1596 public readonly Constant child;
1598 public EmptyConstantCast (Constant child, TypeSpec type)
1599 : base (child.Location)
1602 throw new ArgumentNullException ("child");
1605 this.eclass = child.eclass;
1609 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1611 if (child.Type == target_type)
1614 // FIXME: check that 'type' can be converted to 'target_type' first
1615 return child.ConvertExplicitly (in_checked_context, target_type);
1618 public override Expression CreateExpressionTree (ResolveContext ec)
1620 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1621 child.CreateExpressionTree (ec),
1622 new TypeOf (type, loc));
1625 Error_PointerInsideExpressionTree (ec);
1627 return CreateExpressionFactoryCall (ec, "Convert", args);
1630 public override bool IsDefaultValue {
1631 get { return child.IsDefaultValue; }
1634 public override bool IsNegative {
1635 get { return child.IsNegative; }
1638 public override bool IsNull {
1639 get { return child.IsNull; }
1642 public override bool IsOneInteger {
1643 get { return child.IsOneInteger; }
1646 public override bool IsSideEffectFree {
1648 return child.IsSideEffectFree;
1652 public override bool IsZeroInteger {
1653 get { return child.IsZeroInteger; }
1656 public override void Emit (EmitContext ec)
1661 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1663 child.EmitBranchable (ec, label, on_true);
1665 // Only to make verifier happy
1666 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1667 ec.Emit (OpCodes.Unbox_Any, type);
1670 public override void EmitSideEffect (EmitContext ec)
1672 child.EmitSideEffect (ec);
1675 public override object GetValue ()
1677 return child.GetValue ();
1680 public override string GetValueAsLiteral ()
1682 return child.GetValueAsLiteral ();
1685 public override long GetValueAsLong ()
1687 return child.GetValueAsLong ();
1690 public override Constant ConvertImplicitly (TypeSpec target_type)
1692 if (type == target_type)
1695 // FIXME: Do we need to check user conversions?
1696 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1699 return child.ConvertImplicitly (target_type);
1704 /// This class is used to wrap literals which belong inside Enums
1706 public class EnumConstant : Constant
1708 public Constant Child;
1710 public EnumConstant (Constant child, TypeSpec enum_type)
1711 : base (child.Location)
1715 this.eclass = ExprClass.Value;
1716 this.type = enum_type;
1719 protected EnumConstant (Location loc)
1724 public override void Emit (EmitContext ec)
1729 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1731 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1734 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1736 Child.EmitBranchable (ec, label, on_true);
1739 public override void EmitSideEffect (EmitContext ec)
1741 Child.EmitSideEffect (ec);
1744 public override string GetSignatureForError()
1746 return Type.GetSignatureForError ();
1749 public override object GetValue ()
1751 return Child.GetValue ();
1755 public override object GetTypedValue ()
1758 // The method can be used in dynamic context only (on closed types)
1760 // System.Enum.ToObject cannot be called on dynamic types
1761 // EnumBuilder has to be used, but we cannot use EnumBuilder
1762 // because it does not properly support generics
1764 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1768 public override string GetValueAsLiteral ()
1770 return Child.GetValueAsLiteral ();
1773 public override long GetValueAsLong ()
1775 return Child.GetValueAsLong ();
1778 public EnumConstant Increment()
1780 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1783 public override bool IsDefaultValue {
1785 return Child.IsDefaultValue;
1789 public override bool IsSideEffectFree {
1791 return Child.IsSideEffectFree;
1795 public override bool IsZeroInteger {
1796 get { return Child.IsZeroInteger; }
1799 public override bool IsNegative {
1801 return Child.IsNegative;
1805 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1807 if (Child.Type == target_type)
1810 return Child.ConvertExplicitly (in_checked_context, target_type);
1813 public override Constant ConvertImplicitly (TypeSpec type)
1815 if (this.type == type) {
1819 if (!Convert.ImplicitStandardConversionExists (this, type)){
1823 return Child.ConvertImplicitly (type);
1828 /// This kind of cast is used to encapsulate Value Types in objects.
1830 /// The effect of it is to box the value type emitted by the previous
1833 public class BoxedCast : TypeCast {
1835 public BoxedCast (Expression expr, TypeSpec target_type)
1836 : base (expr, target_type)
1838 eclass = ExprClass.Value;
1841 protected override Expression DoResolve (ResolveContext ec)
1843 // This should never be invoked, we are born in fully
1844 // initialized state.
1849 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1851 // Only boxing to object type is supported
1852 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1853 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1857 enc.Encode (child.Type);
1858 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1861 public override void Emit (EmitContext ec)
1865 ec.Emit (OpCodes.Box, child.Type);
1868 public override void EmitSideEffect (EmitContext ec)
1870 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1871 // so, we need to emit the box+pop instructions in most cases
1872 if (child.Type.IsStruct &&
1873 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1874 child.EmitSideEffect (ec);
1876 base.EmitSideEffect (ec);
1880 public class UnboxCast : TypeCast {
1881 public UnboxCast (Expression expr, TypeSpec return_type)
1882 : base (expr, return_type)
1886 protected override Expression DoResolve (ResolveContext ec)
1888 // This should never be invoked, we are born in fully
1889 // initialized state.
1894 public override void Emit (EmitContext ec)
1898 ec.Emit (OpCodes.Unbox_Any, type);
1903 /// This is used to perform explicit numeric conversions.
1905 /// Explicit numeric conversions might trigger exceptions in a checked
1906 /// context, so they should generate the conv.ovf opcodes instead of
1909 public class ConvCast : TypeCast {
1910 public enum Mode : byte {
1911 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1913 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1914 U2_I1, U2_U1, U2_I2, U2_CH,
1915 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1916 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1917 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1918 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1919 CH_I1, CH_U1, CH_I2,
1920 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1921 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1927 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1928 : base (child, return_type)
1933 protected override Expression DoResolve (ResolveContext ec)
1935 // This should never be invoked, we are born in fully
1936 // initialized state.
1941 public override string ToString ()
1943 return String.Format ("ConvCast ({0}, {1})", mode, child);
1946 public override void Emit (EmitContext ec)
1952 public static void Emit (EmitContext ec, Mode mode)
1954 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1956 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1957 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1958 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1959 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1960 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1963 case Mode.U1_CH: /* nothing */ break;
1965 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1966 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1967 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1968 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1969 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1974 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1975 case Mode.U2_CH: /* nothing */ break;
1977 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1978 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1979 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1980 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1981 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1982 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1983 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1986 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1987 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1988 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1989 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1990 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1992 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1993 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1994 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1995 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1996 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1997 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1998 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1999 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2002 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2003 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2004 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2005 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2006 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2007 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2008 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2009 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2010 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2012 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2013 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2014 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2016 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2017 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2018 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2019 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2021 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2022 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2023 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2024 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2026 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2027 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2028 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2029 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2030 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2031 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2032 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2033 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2034 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2035 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2037 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2041 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2042 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2044 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2045 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2048 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2050 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2051 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2052 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2053 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2054 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2055 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2058 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2059 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2060 case Mode.U2_CH: /* nothing */ break;
2062 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2063 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2064 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2065 case Mode.I4_U4: /* nothing */ break;
2066 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2067 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2068 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2070 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2071 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2072 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2073 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2074 case Mode.U4_I4: /* nothing */ break;
2075 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2077 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2078 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2079 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2080 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2081 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2082 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2083 case Mode.I8_U8: /* nothing */ break;
2084 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2085 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2087 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2088 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2089 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2090 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2091 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2092 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2093 case Mode.U8_I8: /* nothing */ break;
2094 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2095 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2097 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2098 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2099 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2101 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2102 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2103 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2104 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2106 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2107 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2108 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2109 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2111 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2112 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2113 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2114 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2115 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2116 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2117 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2118 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2119 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2120 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2122 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2128 class OpcodeCast : TypeCast
2132 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2133 : base (child, return_type)
2138 protected override Expression DoResolve (ResolveContext ec)
2140 // This should never be invoked, we are born in fully
2141 // initialized state.
2146 public override void Emit (EmitContext ec)
2152 public TypeSpec UnderlyingType {
2153 get { return child.Type; }
2158 // Opcode casts expression with 2 opcodes but only
2159 // single expression tree node
2161 class OpcodeCastDuplex : OpcodeCast
2163 readonly OpCode second;
2165 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2166 : base (child, returnType, first)
2168 this.second = second;
2171 public override void Emit (EmitContext ec)
2179 /// This kind of cast is used to encapsulate a child and cast it
2180 /// to the class requested
2182 public sealed class ClassCast : TypeCast {
2183 readonly bool forced;
2185 public ClassCast (Expression child, TypeSpec return_type)
2186 : base (child, return_type)
2190 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2191 : base (child, return_type)
2193 this.forced = forced;
2196 public override void Emit (EmitContext ec)
2200 bool gen = TypeManager.IsGenericParameter (child.Type);
2202 ec.Emit (OpCodes.Box, child.Type);
2204 if (type.IsGenericParameter) {
2205 ec.Emit (OpCodes.Unbox_Any, type);
2212 ec.Emit (OpCodes.Castclass, type);
2217 // Created during resolving pahse when an expression is wrapped or constantified
2218 // and original expression can be used later (e.g. for expression trees)
2220 public class ReducedExpression : Expression
2222 public class ReducedConstantExpression : EmptyConstantCast
2224 readonly Expression orig_expr;
2226 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2227 : base (expr, expr.Type)
2229 this.orig_expr = orig_expr;
2232 public Expression OriginalExpression {
2238 public override Constant ConvertImplicitly (TypeSpec target_type)
2240 Constant c = base.ConvertImplicitly (target_type);
2242 c = new ReducedConstantExpression (c, orig_expr);
2247 public override Expression CreateExpressionTree (ResolveContext ec)
2249 return orig_expr.CreateExpressionTree (ec);
2252 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2254 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2256 c = new ReducedConstantExpression (c, orig_expr);
2260 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2263 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2265 if (orig_expr is Conditional)
2266 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2268 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2272 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2274 public ReducedConstantStatement (Constant expr, Expression origExpr)
2275 : base (expr, origExpr)
2280 sealed class ReducedExpressionStatement : ExpressionStatement
2282 readonly Expression orig_expr;
2283 readonly ExpressionStatement stm;
2285 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2287 this.orig_expr = orig;
2289 this.eclass = stm.eclass;
2290 this.type = stm.Type;
2292 this.loc = orig.Location;
2295 public override bool ContainsEmitWithAwait ()
2297 return stm.ContainsEmitWithAwait ();
2300 public override Expression CreateExpressionTree (ResolveContext ec)
2302 return orig_expr.CreateExpressionTree (ec);
2305 protected override Expression DoResolve (ResolveContext ec)
2310 public override void Emit (EmitContext ec)
2315 public override void EmitStatement (EmitContext ec)
2317 stm.EmitStatement (ec);
2320 public override void FlowAnalysis (FlowAnalysisContext fc)
2322 stm.FlowAnalysis (fc);
2326 readonly Expression expr, orig_expr;
2328 private ReducedExpression (Expression expr, Expression orig_expr)
2331 this.eclass = expr.eclass;
2332 this.type = expr.Type;
2333 this.orig_expr = orig_expr;
2334 this.loc = orig_expr.Location;
2339 public override bool IsSideEffectFree {
2341 return expr.IsSideEffectFree;
2345 public Expression OriginalExpression {
2353 public override bool ContainsEmitWithAwait ()
2355 return expr.ContainsEmitWithAwait ();
2359 // Creates fully resolved expression switcher
2361 public static Constant Create (Constant expr, Expression originalExpr)
2363 if (expr.eclass == ExprClass.Unresolved)
2364 throw new ArgumentException ("Unresolved expression");
2366 if (originalExpr is ExpressionStatement)
2367 return new ReducedConstantStatement (expr, originalExpr);
2369 return new ReducedConstantExpression (expr, originalExpr);
2372 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2374 return new ReducedExpressionStatement (s, orig);
2377 public static Expression Create (Expression expr, Expression original_expr)
2379 return Create (expr, original_expr, true);
2383 // Creates unresolved reduce expression. The original expression has to be
2384 // already resolved. Created expression is constant based based on `expr'
2385 // value unless canBeConstant is used
2387 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2389 if (canBeConstant) {
2390 Constant c = expr as Constant;
2392 return Create (c, original_expr);
2395 ExpressionStatement s = expr as ExpressionStatement;
2397 return Create (s, original_expr);
2399 if (expr.eclass == ExprClass.Unresolved)
2400 throw new ArgumentException ("Unresolved expression");
2402 return new ReducedExpression (expr, original_expr);
2405 public override Expression CreateExpressionTree (ResolveContext ec)
2407 return orig_expr.CreateExpressionTree (ec);
2410 protected override Expression DoResolve (ResolveContext ec)
2415 public override void Emit (EmitContext ec)
2420 public override Expression EmitToField (EmitContext ec)
2422 return expr.EmitToField(ec);
2425 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2427 expr.EmitBranchable (ec, target, on_true);
2430 public override void FlowAnalysis (FlowAnalysisContext fc)
2432 orig_expr.FlowAnalysis (fc);
2435 public override void FlowAnalysisConditional (FlowAnalysisContext fc)
2437 orig_expr.FlowAnalysisConditional (fc);
2440 public override SLE.Expression MakeExpression (BuilderContext ctx)
2442 return orig_expr.MakeExpression (ctx);
2445 public override Reachability MarkReachable (Reachability rc)
2447 return expr.MarkReachable (rc);
2452 // Standard composite pattern
2454 public abstract class CompositeExpression : Expression
2456 protected Expression expr;
2458 protected CompositeExpression (Expression expr)
2461 this.loc = expr.Location;
2464 public override bool ContainsEmitWithAwait ()
2466 return expr.ContainsEmitWithAwait ();
2469 public override Expression CreateExpressionTree (ResolveContext rc)
2471 return expr.CreateExpressionTree (rc);
2474 public Expression Child {
2475 get { return expr; }
2478 protected override Expression DoResolve (ResolveContext rc)
2480 expr = expr.Resolve (rc);
2485 eclass = expr.eclass;
2489 public override void Emit (EmitContext ec)
2494 public override bool IsNull {
2495 get { return expr.IsNull; }
2500 // Base of expressions used only to narrow resolve flow
2502 public abstract class ShimExpression : Expression
2504 protected Expression expr;
2506 protected ShimExpression (Expression expr)
2511 public Expression Expr {
2517 protected override void CloneTo (CloneContext clonectx, Expression t)
2522 ShimExpression target = (ShimExpression) t;
2523 target.expr = expr.Clone (clonectx);
2526 public override bool ContainsEmitWithAwait ()
2528 return expr.ContainsEmitWithAwait ();
2531 public override Expression CreateExpressionTree (ResolveContext ec)
2533 throw new NotSupportedException ("ET");
2536 public override void Emit (EmitContext ec)
2538 throw new InternalErrorException ("Missing Resolve call");
2542 public class UnreachableExpression : Expression
2544 public UnreachableExpression (Expression expr)
2546 this.loc = expr.Location;
2549 public override Expression CreateExpressionTree (ResolveContext ec)
2552 throw new NotImplementedException ();
2555 protected override Expression DoResolve (ResolveContext rc)
2557 throw new NotSupportedException ();
2560 public override void FlowAnalysis (FlowAnalysisContext fc)
2562 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2565 public override void Emit (EmitContext ec)
2569 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2575 // Unresolved type name expressions
2577 public abstract class ATypeNameExpression : FullNamedExpression
2580 protected TypeArguments targs;
2582 protected ATypeNameExpression (string name, Location l)
2588 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2595 protected ATypeNameExpression (string name, int arity, Location l)
2596 : this (name, new UnboundTypeArguments (arity, l), l)
2604 return targs == null ? 0 : targs.Count;
2608 public bool HasTypeArguments {
2610 return targs != null && !targs.IsEmpty;
2614 public string Name {
2623 public TypeArguments TypeArguments {
2631 public override bool Equals (object obj)
2633 ATypeNameExpression atne = obj as ATypeNameExpression;
2634 return atne != null && atne.Name == Name &&
2635 (targs == null || targs.Equals (atne.targs));
2638 public override int GetHashCode ()
2640 return Name.GetHashCode ();
2643 // TODO: Move it to MemberCore
2644 public static string GetMemberType (MemberCore mc)
2650 if (mc is FieldBase)
2652 if (mc is MethodCore)
2654 if (mc is EnumMember)
2662 public override string GetSignatureForError ()
2664 if (targs != null) {
2665 return Name + "<" + targs.GetSignatureForError () + ">";
2671 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2675 /// SimpleName expressions are formed of a single word and only happen at the beginning
2676 /// of a dotted-name.
2678 public class SimpleName : ATypeNameExpression
2680 public SimpleName (string name, Location l)
2685 public SimpleName (string name, TypeArguments args, Location l)
2686 : base (name, args, l)
2690 public SimpleName (string name, int arity, Location l)
2691 : base (name, arity, l)
2695 public SimpleName GetMethodGroup ()
2697 return new SimpleName (Name, targs, loc);
2700 protected override Expression DoResolve (ResolveContext rc)
2702 return SimpleNameResolve (rc, null);
2705 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2707 return SimpleNameResolve (ec, right_side);
2710 public void Error_NameDoesNotExist (ResolveContext rc)
2712 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2715 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2717 if (ctx.CurrentType != null) {
2718 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2719 if (member != null) {
2720 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2725 var report = ctx.Module.Compiler.Report;
2727 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2728 if (retval != null) {
2729 report.SymbolRelatedToPreviousError (retval.Type);
2730 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2734 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2735 if (retval != null) {
2736 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2740 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2741 if (ns_candidates != null) {
2742 if (ctx is UsingAliasNamespace.AliasContext) {
2743 report.Error (246, loc,
2744 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2745 ns_candidates[0], Name);
2747 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2748 report.Error (246, loc,
2749 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2753 report.Error (246, loc,
2754 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2759 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2761 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2764 if (fne.Type != null && Arity > 0) {
2765 if (HasTypeArguments) {
2766 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2767 if (ct.ResolveAsType (mc) == null)
2773 targs.Resolve (mc, allowUnboundTypeArguments);
2775 return new GenericOpenTypeExpr (fne.Type, loc);
2779 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2781 if (!(fne is NamespaceExpression))
2785 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2786 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2787 mc.Module.Compiler.Report.Error (1980, Location,
2788 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2789 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2792 fne = new DynamicTypeExpr (loc);
2793 fne.ResolveAsType (mc);
2799 Error_TypeOrNamespaceNotFound (mc);
2803 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2806 // Has to ignore static usings because we are looking for any member not just type
2809 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2812 public bool IsPossibleType (IMemberContext mc)
2814 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2817 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2819 int lookup_arity = Arity;
2820 bool errorMode = false;
2822 Block current_block = rc.CurrentBlock;
2823 INamedBlockVariable variable = null;
2824 bool variable_found = false;
2828 // Stage 1: binding to local variables or parameters
2830 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2832 if (current_block != null && lookup_arity == 0) {
2833 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2834 if (!variable.IsDeclared) {
2835 // We found local name in accessible block but it's not
2836 // initialized yet, maybe the user wanted to bind to something else
2838 variable_found = true;
2840 e = variable.CreateReferenceExpression (rc, loc);
2843 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2852 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2854 TypeSpec member_type = rc.CurrentType;
2855 for (; member_type != null; member_type = member_type.DeclaringType) {
2856 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2860 var me = e as MemberExpr;
2862 // The name matches a type, defer to ResolveAsTypeStep
2870 if (variable != null) {
2871 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2872 rc.Report.Error (844, loc,
2873 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2874 Name, me.GetSignatureForError ());
2878 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2879 // Leave it to overload resolution to report correct error
2881 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2882 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2886 // MemberLookup does not check accessors availability, this is actually needed for properties only
2888 var pe = me as PropertyExpr;
2891 // Break as there is no other overload available anyway
2892 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2893 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2896 pe.Getter = pe.PropertyInfo.Get;
2898 if (!pe.PropertyInfo.HasSet) {
2899 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2900 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2901 var p = (Property) pe.PropertyInfo.MemberDefinition;
2902 return new FieldExpr (p.BackingField, loc);
2905 variable_found = true;
2909 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2910 variable_found = true;
2914 pe.Setter = pe.PropertyInfo.Set;
2919 // TODO: It's used by EventExpr -> FieldExpr transformation only
2920 // TODO: Should go to MemberAccess
2921 me = me.ResolveMemberAccess (rc, null, null);
2924 targs.Resolve (rc, false);
2925 me.SetTypeArguments (rc, targs);
2932 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2934 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2935 if (IsPossibleTypeOrNamespace (rc)) {
2936 return ResolveAsTypeOrNamespace (rc, false);
2940 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2943 targs.Resolve (rc, false);
2945 var me = expr as MemberExpr;
2947 me.SetTypeArguments (rc, targs);
2952 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2953 return new NameOf (this);
2956 if (variable_found) {
2957 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2960 var tparams = rc.CurrentTypeParameters;
2961 if (tparams != null) {
2962 if (tparams.Find (Name) != null) {
2963 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2968 var ct = rc.CurrentType;
2970 if (ct.MemberDefinition.TypeParametersCount > 0) {
2971 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2972 if (ctp.Name == Name) {
2973 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2979 ct = ct.DeclaringType;
2980 } while (ct != null);
2983 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2984 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2986 rc.Report.SymbolRelatedToPreviousError (e.Type);
2987 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2991 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2993 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2994 return ErrorExpression.Instance;
2998 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
3000 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
3001 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
3005 if (e is TypeExpr) {
3006 // TypeExpression does not have correct location
3007 if (e is TypeExpression)
3008 e = new TypeExpression (e.Type, loc);
3014 Error_NameDoesNotExist (rc);
3017 return ErrorExpression.Instance;
3020 if (rc.Module.Evaluator != null) {
3021 var fi = rc.Module.Evaluator.LookupField (Name);
3023 return new FieldExpr (fi.Item1, loc);
3031 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3033 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3038 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3039 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3043 if (right_side != null) {
3044 e = e.ResolveLValue (ec, right_side);
3052 public override object Accept (StructuralVisitor visitor)
3054 return visitor.Visit (this);
3059 /// Represents a namespace or a type. The name of the class was inspired by
3060 /// section 10.8.1 (Fully Qualified Names).
3062 public abstract class FullNamedExpression : Expression
3064 protected override void CloneTo (CloneContext clonectx, Expression target)
3066 // Do nothing, most unresolved type expressions cannot be
3067 // resolved to different type
3070 public override bool ContainsEmitWithAwait ()
3075 public override Expression CreateExpressionTree (ResolveContext ec)
3077 throw new NotSupportedException ("ET");
3080 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3083 // This is used to resolve the expression as a type, a null
3084 // value will be returned if the expression is not a type
3087 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3089 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3094 TypeExpr te = fne as TypeExpr;
3096 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3104 var dep = type.GetMissingDependencies ();
3106 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3109 if (type.Kind == MemberKind.Void) {
3110 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3114 // Obsolete checks cannot be done when resolving base context as they
3115 // require type dependencies to be set but we are in process of resolving them
3117 if (mc is ResolveContext) {
3118 var oa = type.GetAttributeObsolete ();
3119 if (oa != null && !mc.IsObsolete)
3120 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3127 public override void Emit (EmitContext ec)
3129 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3130 GetSignatureForError ());
3135 /// Expression that evaluates to a type
3137 public abstract class TypeExpr : FullNamedExpression
3139 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3145 protected sealed override Expression DoResolve (ResolveContext ec)
3151 public override bool Equals (object obj)
3153 TypeExpr tobj = obj as TypeExpr;
3157 return Type == tobj.Type;
3160 public override int GetHashCode ()
3162 return Type.GetHashCode ();
3167 /// Fully resolved Expression that already evaluated to a type
3169 public class TypeExpression : TypeExpr
3171 public TypeExpression (TypeSpec t, Location l)
3174 eclass = ExprClass.Type;
3178 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3184 public class NamespaceExpression : FullNamedExpression
3186 readonly Namespace ns;
3188 public NamespaceExpression (Namespace ns, Location loc)
3191 this.Type = InternalType.Namespace;
3192 this.eclass = ExprClass.Namespace;
3196 public Namespace Namespace {
3202 protected override Expression DoResolve (ResolveContext rc)
3204 throw new NotImplementedException ();
3207 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3212 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3214 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3215 if (retval != null) {
3216 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3217 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3221 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3222 if (retval != null) {
3223 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3228 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3229 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3233 string assembly = null;
3234 string possible_name = Namespace.GetSignatureForError () + "." + name;
3236 // Only assembly unique name should be added
3237 switch (possible_name) {
3238 case "System.Drawing":
3239 case "System.Web.Services":
3242 case "System.Configuration":
3243 case "System.Data.Services":
3244 case "System.DirectoryServices":
3246 case "System.Net.Http":
3247 case "System.Numerics":
3248 case "System.Runtime.Caching":
3249 case "System.ServiceModel":
3250 case "System.Transactions":
3251 case "System.Web.Routing":
3252 case "System.Xml.Linq":
3254 assembly = possible_name;
3258 case "System.Linq.Expressions":
3259 assembly = "System.Core";
3262 case "System.Windows.Forms":
3263 case "System.Windows.Forms.Layout":
3264 assembly = "System.Windows.Forms";
3268 assembly = assembly == null ? "an" : "`" + assembly + "'";
3270 if (Namespace is GlobalRootNamespace) {
3271 ctx.Module.Compiler.Report.Error (400, loc,
3272 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3275 ctx.Module.Compiler.Report.Error (234, loc,
3276 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3277 name, GetSignatureForError (), assembly);
3281 public override string GetSignatureForError ()
3283 return ns.GetSignatureForError ();
3286 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3288 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3291 public override string ToString ()
3293 return Namespace.Name;
3298 /// This class denotes an expression which evaluates to a member
3299 /// of a struct or a class.
3301 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3303 protected bool conditional_access_receiver;
3306 // An instance expression associated with this member, if it's a
3307 // non-static member
3309 public Expression InstanceExpression;
3312 /// The name of this member.
3314 public abstract string Name {
3319 // When base.member is used
3321 public bool IsBase {
3322 get { return InstanceExpression is BaseThis; }
3326 /// Whether this is an instance member.
3328 public abstract bool IsInstance {
3333 /// Whether this is a static member.
3335 public abstract bool IsStatic {
3339 public abstract string KindName {
3343 public bool ConditionalAccess { get; set; }
3345 protected abstract TypeSpec DeclaringType {
3349 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3351 return InstanceExpression.Type;
3356 // Converts best base candidate for virtual method starting from QueriedBaseType
3358 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3361 // Only when base.member is used and method is virtual
3367 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3368 // means for base.member access we have to find the closest match after we found best candidate
3370 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3372 // The method could already be what we are looking for
3374 TypeSpec[] targs = null;
3375 if (method.DeclaringType != InstanceExpression.Type) {
3377 // Candidate can have inflated MVAR parameters and we need to find
3378 // base match for original definition not inflated parameter types
3380 var parameters = method.Parameters;
3381 if (method.Arity > 0) {
3382 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3383 var inflated = method.DeclaringType as InflatedTypeSpec;
3384 if (inflated != null) {
3385 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3389 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3390 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3391 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3392 if (base_override.IsGeneric)
3393 targs = method.TypeArguments;
3395 method = base_override;
3400 // When base access is used inside anonymous method/iterator/etc we need to
3401 // get back to the context of original type. We do it by emiting proxy
3402 // method in original class and rewriting base call to this compiler
3403 // generated method call which does the actual base invocation. This may
3404 // introduce redundant storey but with `this' only but it's tricky to avoid
3405 // at this stage as we don't know what expressions follow base
3407 // TODO: It's needed only when the method with base call is moved to a storey
3409 if (rc.CurrentAnonymousMethod != null) {
3410 if (targs == null && method.IsGeneric) {
3411 targs = method.TypeArguments;
3412 method = method.GetGenericMethodDefinition ();
3415 if (method.Parameters.HasArglist)
3416 throw new NotImplementedException ("__arglist base call proxy");
3418 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3420 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3421 // get/set member expressions second call would fail to proxy because left expression
3422 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3423 // FIXME: The async check is another hack but will probably fail with mutators
3424 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3425 InstanceExpression = new This (loc).Resolve (rc);
3429 method = method.MakeGenericMethod (rc, targs);
3433 // Only base will allow this invocation to happen.
3435 if (method.IsAbstract) {
3436 rc.Report.SymbolRelatedToPreviousError (method);
3437 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3443 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3445 if (InstanceExpression == null)
3448 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3449 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3450 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3455 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3457 if (InstanceExpression == null)
3460 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3463 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3465 var ct = rc.CurrentType;
3466 if (ct == qualifier)
3469 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3472 qualifier = qualifier.GetDefinition ();
3473 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3480 public override bool ContainsEmitWithAwait ()
3482 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3485 public override bool HasConditionalAccess ()
3487 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3490 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3493 type = type.GetDefinition ();
3495 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3498 type = type.DeclaringType;
3499 } while (type != null);
3504 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3506 if (InstanceExpression != null) {
3507 InstanceExpression = InstanceExpression.Resolve (rc);
3508 CheckProtectedMemberAccess (rc, member);
3511 if (member.MemberType.IsPointer) {
3512 if (rc.CurrentIterator != null) {
3513 UnsafeInsideIteratorError (rc, loc);
3514 } else if (!rc.IsUnsafe) {
3515 UnsafeError (rc, loc);
3519 var dep = member.GetMissingDependencies ();
3521 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3524 member.CheckObsoleteness (rc, loc);
3526 if (!(member is FieldSpec))
3527 member.MemberDefinition.SetIsUsed ();
3530 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3532 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3535 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3537 rc.Report.SymbolRelatedToPreviousError (member);
3538 rc.Report.Error (1540, loc,
3539 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3540 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3543 public override void FlowAnalysis (FlowAnalysisContext fc)
3545 if (InstanceExpression != null) {
3546 InstanceExpression.FlowAnalysis (fc);
3550 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3552 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3553 conditional_access_receiver = true;
3557 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3559 if (!ResolveInstanceExpressionCore (rc, rhs))
3563 // Check intermediate value modification which won't have any effect
3565 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3566 var fexpr = InstanceExpression as FieldExpr;
3567 if (fexpr != null) {
3568 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3571 if (fexpr.IsStatic) {
3572 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3573 fexpr.GetSignatureForError ());
3575 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3576 fexpr.GetSignatureForError ());
3582 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3583 if (rc.CurrentInitializerVariable != null) {
3584 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3585 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3587 rc.Report.Error (1612, loc,
3588 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3589 InstanceExpression.GetSignatureForError ());
3595 var lvr = InstanceExpression as LocalVariableReference;
3598 if (!lvr.local_info.IsReadonly)
3601 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3602 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3609 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3612 if (InstanceExpression != null) {
3613 if (InstanceExpression is TypeExpr) {
3614 var t = InstanceExpression.Type;
3616 t.CheckObsoleteness (rc, loc);
3618 t = t.DeclaringType;
3619 } while (t != null);
3621 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3622 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3623 rc.Report.Error (176, loc,
3624 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3625 GetSignatureForError ());
3629 InstanceExpression = null;
3635 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3636 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3637 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3638 rc.Report.Error (236, loc,
3639 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3640 GetSignatureForError ());
3642 var fe = this as FieldExpr;
3643 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3644 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3645 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3647 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3651 rc.Report.Error (120, loc,
3652 "An object reference is required to access non-static member `{0}'",
3653 GetSignatureForError ());
3657 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3661 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3662 rc.Report.Error (38, loc,
3663 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3664 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3667 InstanceExpression = new This (loc).Resolve (rc);
3671 var me = InstanceExpression as MemberExpr;
3673 me.ResolveInstanceExpressionCore (rc, rhs);
3675 var fe = me as FieldExpr;
3676 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3677 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3678 rc.Report.Warning (1690, 1, loc,
3679 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3680 me.GetSignatureForError ());
3687 // Additional checks for l-value member access
3690 if (InstanceExpression is UnboxCast) {
3691 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3698 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3700 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3701 ec.Report.Warning (1720, 1, left.Location,
3702 "Expression will always cause a `{0}'", "System.NullReferenceException");
3705 InstanceExpression = left;
3709 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3714 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3716 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3717 inst.Emit (ec, ConditionalAccess);
3719 if (prepare_for_load)
3720 ec.Emit (OpCodes.Dup);
3723 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3726 public class ExtensionMethodCandidates
3728 readonly NamespaceContainer container;
3729 readonly IList<MethodSpec> methods;
3731 readonly IMemberContext context;
3733 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3735 this.context = context;
3736 this.methods = methods;
3737 this.container = nsContainer;
3738 this.index = lookupIndex;
3741 public NamespaceContainer Container {
3747 public IMemberContext Context {
3753 public int LookupIndex {
3759 public IList<MethodSpec> Methods {
3767 // Represents a group of extension method candidates for whole namespace
3769 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3771 ExtensionMethodCandidates candidates;
3772 public Expression ExtensionExpression;
3774 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3775 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3777 this.candidates = candidates;
3778 this.ExtensionExpression = extensionExpr;
3781 public override bool IsStatic {
3782 get { return true; }
3786 // For extension methodgroup we are not looking for base members but parent
3787 // namespace extension methods
3789 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3791 // TODO: candidates are null only when doing error reporting, that's
3792 // incorrect. We have to discover same extension methods in error mode
3793 if (candidates == null)
3796 int arity = type_arguments == null ? 0 : type_arguments.Count;
3798 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3799 if (candidates == null)
3802 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3805 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3808 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3810 // LAMESPEC: or implicit type parameter conversion
3812 return argType == extensionType ||
3813 TypeSpecComparer.IsEqual (argType, extensionType) ||
3814 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3815 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3818 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3820 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3823 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3825 // We are already here
3829 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3831 if (arguments == null)
3832 arguments = new Arguments (1);
3834 ExtensionExpression = ExtensionExpression.Resolve (ec);
3835 if (ExtensionExpression == null)
3838 var cand = candidates;
3839 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3840 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3841 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3843 // Restore candidates in case we are running in probing mode
3846 // Store resolved argument and restore original arguments
3848 // Clean-up modified arguments for error reporting
3849 arguments.RemoveAt (0);
3853 var me = ExtensionExpression as MemberExpr;
3855 me.ResolveInstanceExpression (ec, null);
3856 var fe = me as FieldExpr;
3858 fe.Spec.MemberDefinition.SetIsUsed ();
3861 InstanceExpression = null;
3865 #region IErrorHandler Members
3867 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3872 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3874 rc.Report.SymbolRelatedToPreviousError (best);
3877 rc.Report.Error (1929, loc,
3878 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3879 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3881 rc.Report.Error (1928, loc,
3882 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3883 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3889 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3894 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3903 /// MethodGroupExpr represents a group of method candidates which
3904 /// can be resolved to the best method overload
3906 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3908 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3910 protected IList<MemberSpec> Methods;
3911 MethodSpec best_candidate;
3912 TypeSpec best_candidate_return;
3913 protected TypeArguments type_arguments;
3915 SimpleName simple_name;
3916 protected TypeSpec queried_type;
3918 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3922 this.type = InternalType.MethodGroup;
3924 eclass = ExprClass.MethodGroup;
3925 queried_type = type;
3928 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3929 : this (new MemberSpec[] { m }, type, loc)
3935 public MethodSpec BestCandidate {
3937 return best_candidate;
3941 public TypeSpec BestCandidateReturnType {
3943 return best_candidate_return;
3947 public IList<MemberSpec> Candidates {
3953 protected override TypeSpec DeclaringType {
3955 return queried_type;
3959 public bool IsConditionallyExcluded {
3961 return Methods == Excluded;
3965 public override bool IsInstance {
3967 if (best_candidate != null)
3968 return !best_candidate.IsStatic;
3974 public override bool IsSideEffectFree {
3976 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3980 public override bool IsStatic {
3982 if (best_candidate != null)
3983 return best_candidate.IsStatic;
3989 public override string KindName {
3990 get { return "method"; }
3993 public override string Name {
3995 if (best_candidate != null)
3996 return best_candidate.Name;
3999 return Methods.First ().Name;
4006 // When best candidate is already know this factory can be used
4007 // to avoid expensive overload resolution to be called
4009 // NOTE: InstanceExpression has to be set manually
4011 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4013 return new MethodGroupExpr (best, queriedType, loc) {
4014 best_candidate = best,
4015 best_candidate_return = best.ReturnType
4019 public override string GetSignatureForError ()
4021 if (best_candidate != null)
4022 return best_candidate.GetSignatureForError ();
4024 return Methods.First ().GetSignatureForError ();
4027 public override Expression CreateExpressionTree (ResolveContext ec)
4029 if (best_candidate == null) {
4030 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4034 if (IsConditionallyExcluded)
4035 ec.Report.Error (765, loc,
4036 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4038 if (ConditionalAccess)
4039 Error_NullShortCircuitInsideExpressionTree (ec);
4041 return new TypeOfMethod (best_candidate, loc);
4044 protected override Expression DoResolve (ResolveContext ec)
4046 this.eclass = ExprClass.MethodGroup;
4048 if (InstanceExpression != null) {
4049 InstanceExpression = InstanceExpression.Resolve (ec);
4050 if (InstanceExpression == null)
4057 public override void Emit (EmitContext ec)
4059 throw new NotSupportedException ();
4062 public override void EmitPrepare (EmitContext ec)
4064 InstanceExpression?.EmitPrepare (ec);
4067 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4069 var call = new CallEmitter ();
4070 call.InstanceExpression = InstanceExpression;
4071 call.ConditionalAccess = ConditionalAccess;
4074 call.EmitStatement (ec, best_candidate, arguments, loc);
4076 call.Emit (ec, best_candidate, arguments, loc);
4079 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4081 var ca = ec.ConditionalAccess;
4082 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4083 Statement = statement
4086 EmitCall (ec, arguments, statement);
4088 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4089 ec.ConditionalAccess = ca;
4092 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4094 if (target != InternalType.ErrorType) {
4095 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4096 Name, target.GetSignatureForError ());
4100 public bool HasAccessibleCandidate (ResolveContext rc)
4102 foreach (var candidate in Candidates) {
4103 if (candidate.IsAccessible (rc))
4110 public static bool IsExtensionMethodArgument (Expression expr)
4113 // LAMESPEC: No details about which expressions are not allowed
4115 return !(expr is TypeExpr) && !(expr is BaseThis);
4119 /// Find the Applicable Function Members (7.4.2.1)
4121 /// me: Method Group expression with the members to select.
4122 /// it might contain constructors or methods (or anything
4123 /// that maps to a method).
4125 /// Arguments: ArrayList containing resolved Argument objects.
4127 /// loc: The location if we want an error to be reported, or a Null
4128 /// location for "probing" purposes.
4130 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4131 /// that is the best match of me on Arguments.
4134 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4136 // TODO: causes issues with probing mode, remove explicit Kind check
4137 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4140 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4141 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4142 r.BaseMembersProvider = this;
4143 r.InstanceQualifier = this;
4146 if (cerrors != null)
4147 r.CustomErrors = cerrors;
4149 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4150 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4151 if (best_candidate == null) {
4152 if (!r.BestCandidateIsDynamic)
4155 if (simple_name != null && ec.IsStatic)
4156 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4161 // Overload resolver had to create a new method group, all checks bellow have already been executed
4162 if (r.BestCandidateNewMethodGroup != null)
4163 return r.BestCandidateNewMethodGroup;
4165 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4166 if (InstanceExpression != null) {
4167 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4168 InstanceExpression = null;
4170 if (simple_name != null && best_candidate.IsStatic) {
4171 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4174 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4178 ResolveInstanceExpression (ec, null);
4181 var base_override = CandidateToBaseOverride (ec, best_candidate);
4182 if (base_override == best_candidate) {
4183 best_candidate_return = r.BestCandidateReturnType;
4185 best_candidate = base_override;
4186 best_candidate_return = best_candidate.ReturnType;
4189 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4190 ConstraintChecker cc = new ConstraintChecker (ec);
4191 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4195 // Additional check for possible imported base override method which
4196 // could not be done during IsOverrideMethodBaseTypeAccessible
4198 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4199 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4200 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4201 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4204 // Speed up the check by not doing it on disallowed targets
4205 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4211 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4213 var fe = left as FieldExpr;
4216 // Using method-group on struct fields makes the struct assigned. I am not sure
4217 // why but that's what .net does
4219 fe.Spec.MemberDefinition.SetIsAssigned ();
4222 simple_name = original;
4223 return base.ResolveMemberAccess (ec, left, original);
4226 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4228 if (!HasAccessibleCandidate (rc)) {
4229 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4232 if (expr.HasTypeArguments) {
4233 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4237 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4239 type_arguments = ta;
4242 #region IBaseMembersProvider Members
4244 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4246 var baseType = type.BaseType;
4248 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4250 if (members == null && !type.IsInterface) {
4251 var tps = queried_type as TypeParameterSpec;
4253 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4259 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4261 if (queried_type == member.DeclaringType)
4264 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4265 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4269 // Extension methods lookup after ordinary methods candidates failed to apply
4271 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4273 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4276 if (!IsExtensionMethodArgument (InstanceExpression))
4279 int arity = type_arguments == null ? 0 : type_arguments.Count;
4280 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4281 if (methods == null)
4284 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4285 emg.SetTypeArguments (rc, type_arguments);
4286 emg.ConditionalAccess = ConditionalAccess;
4293 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4295 public ConstructorInstanceQualifier (TypeSpec type)
4298 InstanceType = type;
4301 public TypeSpec InstanceType { get; private set; }
4303 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4305 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4309 public struct OverloadResolver
4312 public enum Restrictions
4316 ProbingOnly = 1 << 1,
4317 CovariantDelegate = 1 << 2,
4318 NoBaseMembers = 1 << 3,
4319 BaseMembersIncluded = 1 << 4,
4320 GetEnumeratorLookup = 1 << 5
4323 public interface IBaseMembersProvider
4325 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4326 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4327 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4330 public interface IErrorHandler
4332 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4333 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4334 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4335 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4338 public interface IInstanceQualifier
4340 TypeSpec InstanceType { get; }
4341 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4344 sealed class NoBaseMembers : IBaseMembersProvider
4346 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4348 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4353 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4358 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4364 struct AmbiguousCandidate
4366 public readonly MemberSpec Member;
4367 public readonly bool Expanded;
4368 public readonly AParametersCollection Parameters;
4370 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4373 Parameters = parameters;
4374 Expanded = expanded;
4379 IList<MemberSpec> members;
4380 TypeArguments type_arguments;
4381 IBaseMembersProvider base_provider;
4382 IErrorHandler custom_errors;
4383 IInstanceQualifier instance_qualifier;
4384 Restrictions restrictions;
4385 MethodGroupExpr best_candidate_extension_group;
4386 TypeSpec best_candidate_return_type;
4388 SessionReportPrinter lambda_conv_msgs;
4390 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4391 : this (members, null, restrictions, loc)
4395 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4398 if (members == null || members.Count == 0)
4399 throw new ArgumentException ("empty members set");
4401 this.members = members;
4403 type_arguments = targs;
4404 this.restrictions = restrictions;
4405 if (IsDelegateInvoke)
4406 this.restrictions |= Restrictions.NoBaseMembers;
4408 base_provider = NoBaseMembers.Instance;
4413 public IBaseMembersProvider BaseMembersProvider {
4415 return base_provider;
4418 base_provider = value;
4422 public bool BestCandidateIsDynamic { get; set; }
4425 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4427 public MethodGroupExpr BestCandidateNewMethodGroup {
4429 return best_candidate_extension_group;
4434 // Return type can be different between best candidate and closest override
4436 public TypeSpec BestCandidateReturnType {
4438 return best_candidate_return_type;
4442 public IErrorHandler CustomErrors {
4444 return custom_errors;
4447 custom_errors = value;
4451 TypeSpec DelegateType {
4453 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4454 throw new InternalErrorException ("Not running in delegate mode", loc);
4456 return members [0].DeclaringType;
4460 public IInstanceQualifier InstanceQualifier {
4462 return instance_qualifier;
4465 instance_qualifier = value;
4469 bool IsProbingOnly {
4471 return (restrictions & Restrictions.ProbingOnly) != 0;
4475 bool IsDelegateInvoke {
4477 return (restrictions & Restrictions.DelegateInvoke) != 0;
4484 // 7.4.3.3 Better conversion from expression
4485 // Returns : 1 if a->p is better,
4486 // 2 if a->q is better,
4487 // 0 if neither is better
4489 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4491 TypeSpec argument_type = a.Type;
4494 // Exactly matching Expression phase
4498 // If argument is an anonymous function
4500 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4502 // p and q are delegate types or expression tree types
4504 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4505 if (q.MemberDefinition != p.MemberDefinition) {
4510 // Uwrap delegate from Expression<T>
4512 q = TypeManager.GetTypeArguments (q) [0];
4513 p = TypeManager.GetTypeArguments (p) [0];
4516 var p_m = Delegate.GetInvokeMethod (p);
4517 var q_m = Delegate.GetInvokeMethod (q);
4520 // With identical parameter lists
4522 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4530 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4532 if (p.Kind == MemberKind.Void) {
4533 return q.Kind != MemberKind.Void ? 2 : 0;
4537 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4539 if (q.Kind == MemberKind.Void) {
4540 return p.Kind != MemberKind.Void ? 1 : 0;
4543 var am = (AnonymousMethodExpression)a.Expr;
4546 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4547 // better conversion is performed between underlying types Y1 and Y2
4549 if (p.IsGenericTask || q.IsGenericTask) {
4550 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4551 q = q.TypeArguments [0];
4552 p = p.TypeArguments [0];
4558 // An inferred return type X exists for E in the context of the parameter list, and
4559 // an identity conversion exists from X to the return type of D
4561 var inferred_type = am.InferReturnType (ec, null, orig_q);
4562 if (inferred_type != null) {
4563 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4564 inferred_type = ec.BuiltinTypes.Object;
4566 if (inferred_type == p)
4569 if (inferred_type == q)
4575 if (argument_type == p)
4578 if (argument_type == q)
4581 return IsBetterConversionTarget (ec, p, q);
4584 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4586 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4588 if (p.Kind != MemberKind.Delegate) {
4589 p = TypeManager.GetTypeArguments (p) [0];
4592 if (q.Kind != MemberKind.Delegate) {
4593 q = TypeManager.GetTypeArguments (q) [0];
4596 var p_m = Delegate.GetInvokeMethod (p);
4597 var q_m = Delegate.GetInvokeMethod (q);
4603 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4605 if (p.Kind == MemberKind.Void) {
4606 return q.Kind != MemberKind.Void ? 2 : 0;
4610 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4612 if (q.Kind == MemberKind.Void) {
4613 return p.Kind != MemberKind.Void ? 1 : 0;
4616 return IsBetterConversionTarget (rc, p, q);
4619 if (p.IsGenericTask && q.IsGenericTask) {
4620 q = q.TypeArguments [0];
4621 p = p.TypeArguments [0];
4622 return IsBetterConversionTarget (rc, p, q);
4626 if (p.IsNullableType) {
4627 p = Nullable.NullableInfo.GetUnderlyingType (p);
4628 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4629 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4632 // Spec expects implicit conversion check between p and q, q and p
4633 // to be done before nullable unwrapping but that's expensive operation.
4635 // Extra manual tweak is needed because BetterTypeConversion works on
4643 if (q.IsNullableType) {
4644 q = Nullable.NullableInfo.GetUnderlyingType (q);
4645 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4646 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4652 return BetterTypeConversion (rc, p, q);
4656 // 7.4.3.4 Better conversion from type
4658 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4660 if (p == null || q == null)
4661 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4663 switch (p.BuiltinType) {
4664 case BuiltinTypeSpec.Type.Int:
4665 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4668 case BuiltinTypeSpec.Type.Long:
4669 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4672 case BuiltinTypeSpec.Type.SByte:
4673 switch (q.BuiltinType) {
4674 case BuiltinTypeSpec.Type.Byte:
4675 case BuiltinTypeSpec.Type.UShort:
4676 case BuiltinTypeSpec.Type.UInt:
4677 case BuiltinTypeSpec.Type.ULong:
4681 case BuiltinTypeSpec.Type.Short:
4682 switch (q.BuiltinType) {
4683 case BuiltinTypeSpec.Type.UShort:
4684 case BuiltinTypeSpec.Type.UInt:
4685 case BuiltinTypeSpec.Type.ULong:
4689 case BuiltinTypeSpec.Type.Dynamic:
4690 // LAMESPEC: Dynamic conversions is not considered
4691 p = ec.Module.Compiler.BuiltinTypes.Object;
4695 switch (q.BuiltinType) {
4696 case BuiltinTypeSpec.Type.Int:
4697 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4700 case BuiltinTypeSpec.Type.Long:
4701 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4704 case BuiltinTypeSpec.Type.SByte:
4705 switch (p.BuiltinType) {
4706 case BuiltinTypeSpec.Type.Byte:
4707 case BuiltinTypeSpec.Type.UShort:
4708 case BuiltinTypeSpec.Type.UInt:
4709 case BuiltinTypeSpec.Type.ULong:
4713 case BuiltinTypeSpec.Type.Short:
4714 switch (p.BuiltinType) {
4715 case BuiltinTypeSpec.Type.UShort:
4716 case BuiltinTypeSpec.Type.UInt:
4717 case BuiltinTypeSpec.Type.ULong:
4721 case BuiltinTypeSpec.Type.Dynamic:
4722 // LAMESPEC: Dynamic conversions is not considered
4723 q = ec.Module.Compiler.BuiltinTypes.Object;
4727 return BetterTypeConversionImplicitConversion (ec, p, q);
4730 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4732 // TODO: this is expensive
4733 Expression p_tmp = new EmptyExpression (p);
4734 Expression q_tmp = new EmptyExpression (q);
4736 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4737 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4739 if (p_to_q && !q_to_p)
4742 if (q_to_p && !p_to_q)
4749 /// Determines "Better function" between candidate
4750 /// and the current best match
4753 /// Returns a boolean indicating :
4754 /// false if candidate ain't better
4755 /// true if candidate is better than the current best match
4757 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4758 MemberSpec best, AParametersCollection bparam, bool best_params)
4760 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4761 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4763 int candidate_better_count = 0;
4764 int best_better_count = 0;
4766 bool are_equivalent = true;
4767 int args_count = args == null ? 0 : args.Count;
4771 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4774 // Default arguments are ignored for better decision
4775 if (a.IsDefaultArgument)
4779 // When comparing named argument the parameter type index has to be looked up
4780 // in original parameter set (override version for virtual members)
4782 NamedArgument na = a as NamedArgument;
4784 int idx = cparam.GetParameterIndexByName (na.Name);
4785 ct = candidate_pd.Types[idx];
4786 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4787 ct = TypeManager.GetElementType (ct);
4789 idx = bparam.GetParameterIndexByName (na.Name);
4790 bt = best_pd.Types[idx];
4791 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4792 bt = TypeManager.GetElementType (bt);
4794 ct = candidate_pd.Types[c_idx];
4795 bt = best_pd.Types[b_idx];
4797 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4798 ct = TypeManager.GetElementType (ct);
4802 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4803 bt = TypeManager.GetElementType (bt);
4808 if (TypeSpecComparer.IsEqual (ct, bt))
4811 are_equivalent = false;
4812 int result = BetterExpressionConversion (ec, a, ct, bt);
4814 // for each argument, the conversion to 'ct' should be no worse than
4815 // the conversion to 'bt'.
4818 // No optional parameters tie breaking rules for delegates overload resolution
4820 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4823 ++best_better_count;
4827 // for at least one argument, the conversion to 'ct' should be better than
4828 // the conversion to 'bt'.
4830 ++candidate_better_count;
4833 if (candidate_better_count != 0 && best_better_count == 0)
4836 if (best_better_count > 0 && candidate_better_count == 0)
4840 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4842 if (!are_equivalent) {
4843 while (j < args_count && !args [j++].IsDefaultArgument) ;
4846 // A candidate with no default parameters is still better when there
4847 // is no better expression conversion and does not have more parameters
4849 if (candidate_pd.Count < best_pd.Count) {
4850 if (candidate_params)
4853 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4856 if (best_pd.FixedParameters [j].HasDefaultValue)
4859 } else if (candidate_pd.Count == best_pd.Count) {
4860 if (candidate_params)
4863 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4866 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4874 // If candidate is applicable in its normal form and best has a params array and is applicable
4875 // only in its expanded form, then candidate is better
4877 if (candidate_params != best_params)
4878 return !candidate_params;
4881 // We have not reached end of parameters list due to params or used default parameters
4883 bool defaults_ambiguity = false;
4884 while (j < candidate_pd.Count && j < best_pd.Count) {
4885 var cand_param = candidate_pd.FixedParameters [j];
4886 var best_param = best_pd.FixedParameters [j];
4888 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4889 return cand_param.HasDefaultValue;
4891 defaults_ambiguity = true;
4892 if (candidate_pd.Count == best_pd.Count) {
4896 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4897 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4899 if (cand_param.HasDefaultValue) {
4908 // Neither is better when not all arguments are provided
4910 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4911 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4912 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4917 if (candidate_pd.Count != best_pd.Count) {
4918 if (defaults_ambiguity && best_pd.Count - 1 == j)
4919 return best_pd.HasParams;
4921 return candidate_pd.Count < best_pd.Count;
4925 // One is a non-generic method and second is a generic method, then non-generic is better
4927 if (best.IsGeneric != candidate.IsGeneric)
4928 return best.IsGeneric;
4931 // Both methods have the same number of parameters, and the parameters have equal types
4932 // Pick the "more specific" signature using rules over original (non-inflated) types
4934 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4935 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4937 bool specific_at_least_once = false;
4938 for (j = 0; j < args_count; ++j) {
4939 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4941 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4942 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4944 ct = candidate_def_pd.Types[j];
4945 bt = best_def_pd.Types[j];
4950 TypeSpec specific = MoreSpecific (ct, bt);
4954 specific_at_least_once = true;
4957 if (specific_at_least_once)
4963 static bool CheckInflatedArguments (MethodSpec ms)
4965 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4968 // Setup constraint checker for probing only
4969 ConstraintChecker cc = new ConstraintChecker (null);
4971 var mp = ms.Parameters.Types;
4972 for (int i = 0; i < mp.Length; ++i) {
4973 var type = mp[i] as InflatedTypeSpec;
4977 var targs = type.TypeArguments;
4978 if (targs.Length == 0)
4981 // TODO: Checking inflated MVAR arguments should be enough
4982 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4989 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4991 rc.Report.Error (1729, loc,
4992 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4993 type.GetSignatureForError (), argCount.ToString ());
4997 // Determines if the candidate method is applicable to the given set of arguments
4998 // There could be two different set of parameters for same candidate where one
4999 // is the closest override for default values and named arguments checks and second
5000 // one being the virtual base for the parameter types and modifiers.
5002 // A return value rates candidate method compatibility,
5004 // 0 = the best, int.MaxValue = the worst
5006 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, bool errorMode)
5009 // Each step has allocated 10 values, it can overflow for
5010 // more than 10 arguments but that's ok as it's used for
5011 // better error reporting only
5013 const int ArgumentCountMismatch = 1000000000;
5014 const int NamedArgumentsMismatch = 100000000;
5015 const int DefaultArgumentMismatch = 10000000;
5016 const int UnexpectedTypeArguments = 1000000;
5017 const int TypeArgumentsMismatch = 100000;
5018 const int InflatedTypesMismatch = 10000;
5020 // Parameters of most-derived type used mainly for named and optional parameters
5021 var pd = pm.Parameters;
5023 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
5024 // params modifier instead of most-derived type
5025 var cpd = ((IParametersMember) candidate).Parameters;
5026 int param_count = pd.Count;
5027 int optional_count = 0;
5029 Arguments orig_args = arguments;
5031 if (arg_count != param_count) {
5033 // No arguments expansion when doing exact match for delegates
5035 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5036 for (int i = 0; i < pd.Count; ++i) {
5037 if (pd.FixedParameters[i].HasDefaultValue) {
5038 optional_count = pd.Count - i;
5044 if (optional_count != 0) {
5045 // Readjust expected number when params used
5046 if (cpd.HasParams) {
5048 if (arg_count < param_count)
5050 } else if (arg_count > param_count) {
5051 int args_gap = System.Math.Abs (arg_count - param_count);
5052 return ArgumentCountMismatch + args_gap;
5053 } else if (arg_count < param_count - optional_count) {
5054 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5055 return ArgumentCountMismatch + args_gap;
5057 } else if (arg_count != param_count) {
5058 int args_gap = System.Math.Abs (arg_count - param_count);
5060 return ArgumentCountMismatch + args_gap;
5061 if (arg_count < param_count - 1)
5062 return ArgumentCountMismatch + args_gap;
5065 // Resize to fit optional arguments
5066 if (optional_count != 0) {
5067 if (arguments == null) {
5068 arguments = new Arguments (optional_count);
5070 // Have to create a new container, so the next run can do same
5071 var resized = new Arguments (param_count);
5072 resized.AddRange (arguments);
5073 arguments = resized;
5076 for (int i = arg_count; i < param_count; ++i)
5077 arguments.Add (null);
5081 if (arg_count > 0) {
5083 // Shuffle named arguments to the right positions if there are any
5085 if (arguments[arg_count - 1] is NamedArgument) {
5086 arg_count = arguments.Count;
5088 for (int i = 0; i < arg_count; ++i) {
5089 bool arg_moved = false;
5091 NamedArgument na = arguments[i] as NamedArgument;
5095 int index = pd.GetParameterIndexByName (na.Name);
5097 // Named parameter not found
5099 return NamedArgumentsMismatch - i;
5101 // already reordered
5106 if (index >= param_count) {
5107 // When using parameters which should not be available to the user
5108 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5111 arguments.Add (null);
5115 if (index == arg_count)
5116 return NamedArgumentsMismatch - i - 1;
5118 temp = arguments [index];
5120 // The slot has been taken by positional argument
5121 if (temp != null && !(temp is NamedArgument))
5122 return NamedArgumentsMismatch - i - 1;
5126 arguments = arguments.MarkOrderedArgument (na);
5130 if (arguments == orig_args) {
5131 arguments = new Arguments (orig_args.Count);
5132 arguments.AddRange (orig_args);
5135 arguments[index] = arguments[i];
5136 arguments[i] = temp;
5143 arg_count = arguments.Count;
5145 } else if (arguments != null) {
5146 arg_count = arguments.Count;
5150 // Don't do any expensive checks when the candidate cannot succeed
5152 if (arg_count != param_count && !cpd.HasParams)
5153 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5155 var dep = candidate.GetMissingDependencies ();
5157 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5162 // 1. Handle generic method using type arguments when specified or type inference
5165 var ms = candidate as MethodSpec;
5166 if (ms != null && ms.IsGeneric) {
5167 if (type_arguments != null) {
5168 var g_args_count = ms.Arity;
5169 if (g_args_count != type_arguments.Count)
5170 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5172 if (type_arguments.Arguments != null)
5173 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5176 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5177 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5178 // candidate was found use the set to report more details about what was wrong with lambda body.
5179 // The general idea is to distinguish between code errors and errors caused by
5180 // trial-and-error type inference
5182 if (lambda_conv_msgs == null) {
5183 for (int i = 0; i < arg_count; i++) {
5184 Argument a = arguments[i];
5188 var am = a.Expr as AnonymousMethodExpression;
5190 if (lambda_conv_msgs == null)
5191 lambda_conv_msgs = new SessionReportPrinter ();
5193 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5198 var ti = new TypeInference (arguments);
5199 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5202 return TypeArgumentsMismatch - ti.InferenceScore;
5205 // Clear any error messages when the result was success
5207 if (lambda_conv_msgs != null)
5208 lambda_conv_msgs.ClearSession ();
5210 if (i_args.Length != 0) {
5212 for (int i = 0; i < i_args.Length; ++i) {
5213 var ta = i_args [i];
5214 if (!ta.IsAccessible (ec))
5215 return TypeArgumentsMismatch - i;
5219 ms = ms.MakeGenericMethod (ec, i_args);
5224 // Type arguments constraints have to match for the method to be applicable
5226 if (!CheckInflatedArguments (ms)) {
5228 return InflatedTypesMismatch;
5232 // We have a generic return type and at same time the method is override which
5233 // means we have to also inflate override return type in case the candidate is
5234 // best candidate and override return type is different to base return type.
5236 // virtual Foo<T, object> with override Foo<T, dynamic>
5238 if (candidate != pm) {
5239 MethodSpec override_ms = (MethodSpec) pm;
5240 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5241 returnType = inflator.Inflate (returnType);
5243 returnType = ms.ReturnType;
5250 if (type_arguments != null)
5251 return UnexpectedTypeArguments;
5257 // 2. Each argument has to be implicitly convertible to method parameter
5259 Parameter.Modifier p_mod = 0;
5262 for (int i = 0; i < arg_count; i++) {
5263 Argument a = arguments[i];
5265 var fp = pd.FixedParameters[i];
5266 if (!fp.HasDefaultValue) {
5267 arguments = orig_args;
5268 return arg_count * 2 + 2;
5272 // Get the default value expression, we can use the same expression
5273 // if the type matches
5275 Expression e = fp.DefaultValue;
5277 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5279 // Restore for possible error reporting
5280 for (int ii = i; ii < arg_count; ++ii)
5281 arguments.RemoveAt (i);
5283 return (arg_count - i) * 2 + 1;
5287 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5289 // LAMESPEC: Attributes can be mixed together with build-in priority
5291 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5292 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5293 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5294 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5295 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5296 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5300 arguments[i] = new Argument (e, Argument.AType.Default);
5304 if (p_mod != Parameter.Modifier.PARAMS) {
5305 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5307 } else if (!params_expanded_form) {
5308 params_expanded_form = true;
5309 pt = ((ElementTypeSpec) pt).Element;
5315 if (!params_expanded_form) {
5316 if (a.IsExtensionType) {
5317 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5322 score = IsArgumentCompatible (ec, a, p_mod, pt);
5325 dynamicArgument = true;
5330 // It can be applicable in expanded form (when not doing exact match like for delegates)
5332 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5333 if (!params_expanded_form) {
5334 pt = ((ElementTypeSpec) pt).Element;
5338 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5341 params_expanded_form = true;
5342 dynamicArgument = true;
5343 } else if (score == 0 || arg_count > pd.Count) {
5344 params_expanded_form = true;
5349 if (params_expanded_form)
5351 return (arg_count - i) * 2 + score;
5356 // Restore original arguments for dynamic binder to keep the intention of original source code
5358 if (dynamicArgument)
5359 arguments = orig_args;
5364 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5366 if (e is Constant && e.Type == ptype)
5370 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5372 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5373 e = new MemberAccess (new MemberAccess (new MemberAccess (
5374 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5375 } else if (e is Constant) {
5377 // Handles int to int? conversions, DefaultParameterValue check
5379 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5383 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5386 return e.Resolve (ec);
5390 // Tests argument compatibility with the parameter
5391 // The possible return values are
5393 // 1 - modifier mismatch
5394 // 2 - type mismatch
5395 // -1 - dynamic binding required
5397 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5400 // Types have to be identical when ref or out modifer
5401 // is used and argument is not of dynamic type
5403 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5404 var arg_type = argument.Type;
5406 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5408 // Using dynamic for ref/out parameter can still succeed at runtime
5410 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5416 if (arg_type != parameter) {
5417 if (arg_type == InternalType.VarOutType)
5421 // Do full equality check after quick path
5423 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5425 // Using dynamic for ref/out parameter can still succeed at runtime
5427 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5435 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5439 // Use implicit conversion in all modes to return same candidates when the expression
5440 // is used as argument or delegate conversion
5442 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5443 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5450 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5452 if (p.IsGenericParameter != q.IsGenericParameter)
5453 return p.IsGenericParameter ? q : p;
5455 var ac_p = p as ArrayContainer;
5457 var ac_q = q as ArrayContainer;
5461 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5462 if (specific == ac_p.Element)
5464 if (specific == ac_q.Element)
5470 if (p.IsGeneric && q.IsGeneric) {
5471 var pargs = p.TypeArguments;
5472 var qargs = q.TypeArguments;
5474 bool p_specific_at_least_once = false;
5475 bool q_specific_at_least_once = false;
5477 for (int i = 0; i < pargs.Length; i++) {
5478 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5479 if (specific == pargs [i])
5480 p_specific_at_least_once = true;
5481 if (specific == qargs [i])
5482 q_specific_at_least_once = true;
5485 if (p_specific_at_least_once && !q_specific_at_least_once)
5487 if (!p_specific_at_least_once && q_specific_at_least_once)
5495 // Find the best method from candidate list
5497 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5499 List<AmbiguousCandidate> ambiguous_candidates = null;
5501 MemberSpec best_candidate;
5502 Arguments best_candidate_args = null;
5503 bool best_candidate_params = false;
5504 bool best_candidate_dynamic = false;
5505 int best_candidate_rate;
5506 IParametersMember best_parameter_member = null;
5508 int args_count = args != null ? args.Count : 0;
5510 Arguments candidate_args = args;
5511 bool error_mode = false;
5512 MemberSpec invocable_member = null;
5513 int applicable_candidates = 0;
5516 best_candidate = null;
5517 best_candidate_rate = int.MaxValue;
5519 var type_members = members;
5521 for (int i = 0; i < type_members.Count; ++i) {
5522 var member = type_members[i];
5525 // Methods in a base class are not candidates if any method in a derived
5526 // class is applicable
5528 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5532 if (!member.IsAccessible (rc))
5535 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5538 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5539 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5544 IParametersMember pm = member as IParametersMember;
5547 // Will use it later to report ambiguity between best method and invocable member
5549 if (Invocation.IsMemberInvocable (member))
5550 invocable_member = member;
5556 // Overload resolution is looking for base member but using parameter names
5557 // and default values from the closest member. That means to do expensive lookup
5558 // for the closest override for virtual or abstract members
5560 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5561 var override_params = base_provider.GetOverrideMemberParameters (member);
5562 if (override_params != null)
5563 pm = override_params;
5567 // Check if the member candidate is applicable
5569 bool params_expanded_form = false;
5570 bool dynamic_argument = false;
5571 TypeSpec rt = pm.MemberType;
5572 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5574 if (lambda_conv_msgs != null)
5575 lambda_conv_msgs.EndSession ();
5578 // How does it score compare to others
5580 if (candidate_rate < best_candidate_rate) {
5582 // Fatal error (missing dependency), cannot continue
5583 if (candidate_rate < 0)
5586 applicable_candidates = 1;
5587 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5588 // Only parameterless methods are considered
5590 best_candidate_rate = candidate_rate;
5591 best_candidate = member;
5592 best_candidate_args = candidate_args;
5593 best_candidate_params = params_expanded_form;
5594 best_candidate_dynamic = dynamic_argument;
5595 best_parameter_member = pm;
5596 best_candidate_return_type = rt;
5598 } else if (candidate_rate == 0) {
5600 // The member look is done per type for most operations but sometimes
5601 // it's not possible like for binary operators overload because they
5602 // are unioned between 2 sides
5604 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5605 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5609 ++applicable_candidates;
5611 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5613 // We pack all interface members into top level type which makes the overload resolution
5614 // more complicated for interfaces. We compensate it by removing methods with same
5615 // signature when building the cache hence this path should not really be hit often
5618 // interface IA { void Foo (int arg); }
5619 // interface IB : IA { void Foo (params int[] args); }
5621 // IB::Foo is the best overload when calling IB.Foo (1)
5624 if (ambiguous_candidates != null) {
5625 foreach (var amb_cand in ambiguous_candidates) {
5626 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5635 ambiguous_candidates = null;
5638 // Is the new candidate better
5639 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5643 best_candidate = member;
5644 best_candidate_args = candidate_args;
5645 best_candidate_params = params_expanded_form;
5646 best_candidate_dynamic = dynamic_argument;
5647 best_parameter_member = pm;
5648 best_candidate_return_type = rt;
5650 // It's not better but any other found later could be but we are not sure yet
5651 if (ambiguous_candidates == null)
5652 ambiguous_candidates = new List<AmbiguousCandidate> ();
5654 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5658 // Restore expanded arguments
5659 candidate_args = args;
5661 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5664 // We've found exact match
5666 if (best_candidate_rate == 0)
5670 // Try extension methods lookup when no ordinary method match was found and provider enables it
5673 var emg = base_provider.LookupExtensionMethod (rc);
5675 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5677 best_candidate_extension_group = emg;
5678 return (T) (MemberSpec) emg.BestCandidate;
5683 // Don't run expensive error reporting mode for probing
5690 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5693 lambda_conv_msgs = null;
5698 // No best member match found, report an error
5700 if (best_candidate_rate != 0 || error_mode) {
5701 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5705 if (best_candidate_dynamic) {
5706 if (args[0].IsExtensionType) {
5707 rc.Report.Error (1973, loc,
5708 "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",
5709 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5713 // Check type constraints only when explicit type arguments are used
5715 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5716 MethodSpec bc = best_candidate as MethodSpec;
5717 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5718 ConstraintChecker cc = new ConstraintChecker (rc);
5719 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5723 BestCandidateIsDynamic = true;
5728 // These flags indicates we are running delegate probing conversion. No need to
5729 // do more expensive checks
5731 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5732 return (T) best_candidate;
5734 if (ambiguous_candidates != null) {
5736 // Now check that there are no ambiguities i.e the selected method
5737 // should be better than all the others
5739 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5740 var candidate = ambiguous_candidates [ix];
5742 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5743 var ambiguous = candidate.Member;
5744 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5745 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5746 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5747 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5748 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5751 return (T) best_candidate;
5756 if (invocable_member != null && !IsProbingOnly) {
5757 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5758 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5759 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5760 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5764 // And now check if the arguments are all
5765 // compatible, perform conversions if
5766 // necessary etc. and return if everything is
5769 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5772 if (best_candidate == null)
5776 // Don't run possibly expensive checks in probing mode
5778 if (!IsProbingOnly && !rc.IsInProbingMode) {
5780 // Check ObsoleteAttribute on the best method
5782 best_candidate.CheckObsoleteness (rc, loc);
5784 best_candidate.MemberDefinition.SetIsUsed ();
5787 args = best_candidate_args;
5788 return (T) best_candidate;
5791 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5793 return ResolveMember<MethodSpec> (rc, ref args);
5796 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5797 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5799 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5802 if (a.Type == InternalType.ErrorType)
5805 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5806 ec.Report.SymbolRelatedToPreviousError (method);
5807 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5808 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5809 TypeManager.CSharpSignature (method));
5812 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5813 TypeManager.CSharpSignature (method));
5814 } else if (IsDelegateInvoke) {
5815 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5816 DelegateType.GetSignatureForError ());
5818 ec.Report.SymbolRelatedToPreviousError (method);
5819 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5820 method.GetSignatureForError ());
5823 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5825 string index = (idx + 1).ToString ();
5826 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5827 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5828 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5829 index, Parameter.GetModifierSignature (a.Modifier));
5831 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5832 index, Parameter.GetModifierSignature (mod));
5834 string p1 = a.GetSignatureForError ();
5835 string p2 = paramType.GetSignatureForError ();
5838 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5839 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5842 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5843 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5844 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5847 ec.Report.Error (1503, a.Expr.Location,
5848 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5853 // We have failed to find exact match so we return error info about the closest match
5855 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5857 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5858 int arg_count = args == null ? 0 : args.Count;
5860 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5861 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5862 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5866 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5871 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5872 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5873 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5877 // For candidates which match on parameters count report more details about incorrect arguments
5880 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5881 // Reject any inaccessible member
5882 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5883 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5884 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5888 var ms = best_candidate as MethodSpec;
5889 if (ms != null && ms.IsGeneric) {
5890 bool constr_ok = true;
5891 if (ms.TypeArguments != null)
5892 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5894 if (ta_count == 0 && ms.TypeArguments == null) {
5895 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5899 rc.Report.Error (411, loc,
5900 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5901 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5908 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5914 // We failed to find any method with correct argument count, report best candidate
5916 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5919 if (best_candidate.Kind == MemberKind.Constructor) {
5920 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5921 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5922 } else if (IsDelegateInvoke) {
5923 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5924 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5925 DelegateType.GetSignatureForError (), arg_count.ToString ());
5927 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5928 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5929 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5930 name, arg_count.ToString ());
5934 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5936 var p = ((IParametersMember)best_candidate).Parameters;
5941 for (int i = p.Count - 1; i != 0; --i) {
5942 var fp = p.FixedParameters [i];
5943 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5953 foreach (var arg in args) {
5954 var na = arg as NamedArgument;
5958 if (na.Name == name) {
5967 return args.Count + 1 == pm.Parameters.Count;
5970 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5972 var pd = pm.Parameters;
5973 var cpd = ((IParametersMember) member).Parameters;
5974 var ptypes = cpd.Types;
5976 Parameter.Modifier p_mod = 0;
5978 int a_idx = 0, a_pos = 0;
5980 ArrayInitializer params_initializers = null;
5981 bool has_unsafe_arg = pm.MemberType.IsPointer;
5982 int arg_count = args == null ? 0 : args.Count;
5984 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5989 if (p_mod != Parameter.Modifier.PARAMS) {
5990 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5992 has_unsafe_arg |= pt.IsPointer;
5994 if (p_mod == Parameter.Modifier.PARAMS) {
5995 if (chose_params_expanded) {
5996 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5997 pt = TypeManager.GetElementType (pt);
6003 // Types have to be identical when ref or out modifer is used
6005 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
6006 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
6009 var arg_type = a.Type;
6013 if (arg_type == InternalType.VarOutType) {
6015 // Set underlying variable type based on parameter type
6017 ((DeclarationExpression)a.Expr).Variable.Type = pt;
6021 if (!TypeSpecComparer.IsEqual (arg_type, pt))
6025 NamedArgument na = a as NamedArgument;
6027 int name_index = pd.GetParameterIndexByName (na.Name);
6028 if (name_index < 0 || name_index >= pd.Count) {
6029 if (IsDelegateInvoke) {
6030 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6031 ec.Report.Error (1746, na.Location,
6032 "The delegate `{0}' does not contain a parameter named `{1}'",
6033 DelegateType.GetSignatureForError (), na.Name);
6035 ec.Report.SymbolRelatedToPreviousError (member);
6036 ec.Report.Error (1739, na.Location,
6037 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6038 TypeManager.CSharpSignature (member), na.Name);
6040 } else if (args[name_index] != a && args[name_index] != null) {
6041 if (IsDelegateInvoke)
6042 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6044 ec.Report.SymbolRelatedToPreviousError (member);
6046 ec.Report.Error (1744, na.Location,
6047 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6052 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6055 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6056 if (a.IsExtensionType) {
6057 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6058 // CS1061 but that still better than confusing CS0123
6059 var ma = new MemberAccess (a.Expr, member.Name, loc);
6060 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6062 custom_errors.NoArgumentMatch (ec, member);
6068 if (a.IsExtensionType) {
6069 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6072 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6074 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6077 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6084 // Convert params arguments to an array initializer
6086 if (params_initializers != null) {
6087 // we choose to use 'a.Expr' rather than 'conv' so that
6088 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6089 params_initializers.Add (a.Expr);
6090 args.RemoveAt (a_idx--);
6096 // Update the argument with the implicit conversion
6100 if (a_idx != arg_count) {
6102 // Convert all var out argument to error type for less confusing error reporting
6103 // when no matching overload is found
6105 for (; a_idx < arg_count; a_idx++) {
6106 var arg = args [a_idx];
6110 if (arg.Type == InternalType.VarOutType) {
6111 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6115 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6120 // Fill not provided arguments required by params modifier
6122 if (params_initializers == null && arg_count + 1 == pd.Count) {
6124 args = new Arguments (1);
6126 pt = ptypes[pd.Count - 1];
6127 pt = TypeManager.GetElementType (pt);
6128 has_unsafe_arg |= pt.IsPointer;
6129 params_initializers = new ArrayInitializer (0, loc);
6133 // Append an array argument with all params arguments
6135 if (params_initializers != null) {
6136 args.Add (new Argument (
6137 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6141 if (has_unsafe_arg) {
6142 if (ec.CurrentIterator != null) {
6143 Expression.UnsafeInsideIteratorError (ec, loc);
6144 } else if (!ec.IsUnsafe) {
6145 Expression.UnsafeError (ec, loc);
6150 // We could infer inaccesible type arguments
6152 if (type_arguments == null && member.IsGeneric) {
6153 var ms = (MethodSpec) member;
6154 foreach (var ta in ms.TypeArguments) {
6155 if (!ta.IsAccessible (ec)) {
6156 ec.Report.SymbolRelatedToPreviousError (ta);
6157 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6167 public class ConstantExpr : MemberExpr
6169 readonly ConstSpec constant;
6171 public ConstantExpr (ConstSpec constant, Location loc)
6173 this.constant = constant;
6177 public override string Name {
6178 get { throw new NotImplementedException (); }
6181 public override string KindName {
6182 get { return "constant"; }
6185 public override bool IsInstance {
6186 get { return !IsStatic; }
6189 public override bool IsStatic {
6190 get { return true; }
6193 protected override TypeSpec DeclaringType {
6194 get { return constant.DeclaringType; }
6197 public override Expression CreateExpressionTree (ResolveContext ec)
6199 throw new NotSupportedException ("ET");
6202 protected override Expression DoResolve (ResolveContext rc)
6204 ResolveInstanceExpression (rc, null);
6205 DoBestMemberChecks (rc, constant);
6207 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6208 eclass = ExprClass.Value;
6209 type = constant.MemberType;
6213 var c = constant.GetConstant (rc);
6215 // Creates reference expression to the constant value
6216 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6219 public override void Emit (EmitContext ec)
6221 throw new NotSupportedException ();
6224 public override string GetSignatureForError ()
6226 return constant.GetSignatureForError ();
6229 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6231 constant.CheckObsoleteness (rc, expr.Location);
6234 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6236 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6241 // Fully resolved expression that references a Field
6243 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6245 protected FieldSpec spec;
6246 VariableInfo variable_info;
6248 LocalTemporary temp;
6251 protected FieldExpr (Location l)
6256 public FieldExpr (FieldSpec spec, Location loc)
6261 type = spec.MemberType;
6264 public FieldExpr (FieldBase fi, Location l)
6271 public override string Name {
6277 public bool IsHoisted {
6279 IVariableReference hv = InstanceExpression as IVariableReference;
6280 return hv != null && hv.IsHoisted;
6284 public override bool IsInstance {
6286 return !spec.IsStatic;
6290 public override bool IsStatic {
6292 return spec.IsStatic;
6296 public override string KindName {
6297 get { return "field"; }
6300 public FieldSpec Spec {
6306 protected override TypeSpec DeclaringType {
6308 return spec.DeclaringType;
6312 public VariableInfo VariableInfo {
6314 return variable_info;
6320 public override string GetSignatureForError ()
6322 return spec.GetSignatureForError ();
6325 public bool IsMarshalByRefAccess (ResolveContext rc)
6327 // Checks possible ldflda of field access expression
6328 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6329 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6330 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6333 public void SetHasAddressTaken ()
6335 IVariableReference vr = InstanceExpression as IVariableReference;
6337 vr.SetHasAddressTaken ();
6341 protected override void CloneTo (CloneContext clonectx, Expression target)
6343 var t = (FieldExpr) target;
6345 if (InstanceExpression != null)
6346 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6349 public override Expression CreateExpressionTree (ResolveContext ec)
6351 if (ConditionalAccess) {
6352 Error_NullShortCircuitInsideExpressionTree (ec);
6355 return CreateExpressionTree (ec, true);
6358 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6361 Expression instance;
6363 if (InstanceExpression == null) {
6364 instance = new NullLiteral (loc);
6365 } else if (convertInstance) {
6366 instance = InstanceExpression.CreateExpressionTree (ec);
6368 args = new Arguments (1);
6369 args.Add (new Argument (InstanceExpression));
6370 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6373 args = Arguments.CreateForExpressionTree (ec, null,
6375 CreateTypeOfExpression ());
6377 return CreateExpressionFactoryCall (ec, "Field", args);
6380 public Expression CreateTypeOfExpression ()
6382 return new TypeOfField (spec, loc);
6385 protected override Expression DoResolve (ResolveContext ec)
6387 spec.MemberDefinition.SetIsUsed ();
6389 return DoResolve (ec, null);
6392 Expression DoResolve (ResolveContext ec, Expression rhs)
6394 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6397 ResolveConditionalAccessReceiver (ec);
6399 if (ResolveInstanceExpression (ec, rhs)) {
6400 // Resolve the field's instance expression while flow analysis is turned
6401 // off: when accessing a field "a.b", we must check whether the field
6402 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6404 if (lvalue_instance) {
6405 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6407 Expression right_side =
6408 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6410 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6412 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6415 if (InstanceExpression == null)
6419 DoBestMemberChecks (ec, spec);
6421 if (conditional_access_receiver)
6422 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6425 var fb = spec as FixedFieldSpec;
6426 IVariableReference var = InstanceExpression as IVariableReference;
6429 IFixedExpression fe = InstanceExpression as IFixedExpression;
6430 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6431 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6434 if (InstanceExpression.eclass != ExprClass.Variable) {
6435 ec.Report.SymbolRelatedToPreviousError (spec);
6436 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6437 TypeManager.GetFullNameSignature (spec));
6438 } else if (var != null && var.IsHoisted) {
6439 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6442 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6446 // Set flow-analysis variable info for struct member access. It will be check later
6447 // for precise error reporting
6449 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6450 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6453 if (conditional_access_receiver)
6454 type = LiftMemberType (ec, type);
6456 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6457 return Constant.CreateConstantFromValue (type, null, loc);
6459 eclass = ExprClass.Variable;
6463 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6465 spec.CheckObsoleteness (rc, expr.Location);
6468 public void SetFieldAssigned (FlowAnalysisContext fc)
6473 bool lvalue_instance = spec.DeclaringType.IsStruct;
6474 if (lvalue_instance) {
6475 var var = InstanceExpression as IVariableReference;
6476 if (var != null && var.VariableInfo != null) {
6477 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6481 var fe = InstanceExpression as FieldExpr;
6483 Expression instance;
6486 instance = fe.InstanceExpression;
6487 var fe_instance = instance as FieldExpr;
6488 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6489 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6490 var var = InstanceExpression as IVariableReference;
6491 if (var != null && var.VariableInfo == null) {
6492 var var_inst = instance as IVariableReference;
6493 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6494 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6498 if (fe_instance != null) {
6507 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6508 instance.FlowAnalysis (fc);
6510 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6511 InstanceExpression.FlowAnalysis (fc);
6515 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6517 // The return value is always null. Returning a value simplifies calling code.
6519 if (right_side == EmptyExpression.OutAccess) {
6521 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6522 GetSignatureForError ());
6524 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6525 GetSignatureForError ());
6531 if (right_side == EmptyExpression.LValueMemberAccess) {
6532 // Already reported as CS1648/CS1650
6536 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6538 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6539 GetSignatureForError ());
6541 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6542 GetSignatureForError ());
6548 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6549 GetSignatureForError ());
6551 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6552 GetSignatureForError ());
6558 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6560 if (HasConditionalAccess ())
6561 Error_NullPropagatingLValue (ec);
6563 if (spec is FixedFieldSpec) {
6564 // It could be much better error message but we want to be error compatible
6565 Error_ValueAssignment (ec, right_side);
6568 Expression e = DoResolve (ec, right_side);
6573 spec.MemberDefinition.SetIsAssigned ();
6575 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6576 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6577 ec.Report.Warning (420, 1, loc,
6578 "`{0}': A volatile field references will not be treated as volatile",
6579 spec.GetSignatureForError ());
6582 if (spec.IsReadOnly) {
6583 // InitOnly fields can only be assigned in constructors or initializers
6584 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6585 return Error_AssignToReadonly (ec, right_side);
6587 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6589 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6590 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6591 return Error_AssignToReadonly (ec, right_side);
6592 // static InitOnly fields cannot be assigned-to in an instance constructor
6593 if (IsStatic && !ec.IsStatic)
6594 return Error_AssignToReadonly (ec, right_side);
6595 // instance constructors can't modify InitOnly fields of other instances of the same type
6596 if (!IsStatic && !(InstanceExpression is This))
6597 return Error_AssignToReadonly (ec, right_side);
6601 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6602 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6603 ec.Report.Warning (197, 1, loc,
6604 "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",
6605 GetSignatureForError ());
6608 eclass = ExprClass.Variable;
6612 public override void FlowAnalysis (FlowAnalysisContext fc)
6614 var var = InstanceExpression as IVariableReference;
6616 var vi = var.VariableInfo;
6617 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6618 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6622 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6623 var le = SkipLeftValueTypeAccess (InstanceExpression);
6625 le.FlowAnalysis (fc);
6631 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6633 base.FlowAnalysis (fc);
6635 if (conditional_access_receiver)
6636 fc.DefiniteAssignment = da;
6639 static Expression SkipLeftValueTypeAccess (Expression expr)
6641 if (!TypeSpec.IsValueType (expr.Type))
6644 if (expr is VariableReference)
6647 var fe = expr as FieldExpr;
6651 if (fe.InstanceExpression == null)
6654 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6657 public override int GetHashCode ()
6659 return spec.GetHashCode ();
6662 public bool IsFixed {
6665 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6667 IVariableReference variable = InstanceExpression as IVariableReference;
6668 if (variable != null)
6669 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6671 IFixedExpression fe = InstanceExpression as IFixedExpression;
6672 return fe != null && fe.IsFixed;
6676 public override bool Equals (object obj)
6678 FieldExpr fe = obj as FieldExpr;
6682 if (spec != fe.spec)
6685 if (InstanceExpression == null || fe.InstanceExpression == null)
6688 return InstanceExpression.Equals (fe.InstanceExpression);
6691 public void Emit (EmitContext ec, bool leave_copy)
6693 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6697 ec.Emit (OpCodes.Volatile);
6699 ec.Emit (OpCodes.Ldsfld, spec);
6701 var ca = ec.ConditionalAccess;
6704 if (conditional_access_receiver)
6705 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6707 EmitInstance (ec, false);
6710 // Optimization for build-in types
6711 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6712 ec.EmitLoadFromPtr (type);
6714 var ff = spec as FixedFieldSpec;
6716 ec.Emit (OpCodes.Ldflda, spec);
6717 ec.Emit (OpCodes.Ldflda, ff.Element);
6720 ec.Emit (OpCodes.Volatile);
6722 ec.Emit (OpCodes.Ldfld, spec);
6726 if (conditional_access_receiver) {
6727 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6728 ec.ConditionalAccess = ca;
6733 ec.Emit (OpCodes.Dup);
6735 temp = new LocalTemporary (this.Type);
6741 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6743 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6744 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6749 if (ConditionalAccess)
6750 throw new NotImplementedException ("null operator assignment");
6752 if (has_await_source)
6753 source = source.EmitToField (ec);
6755 EmitInstance (ec, prepared);
6760 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6761 ec.Emit (OpCodes.Dup);
6763 temp = new LocalTemporary (this.Type);
6768 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6769 ec.Emit (OpCodes.Volatile);
6771 spec.MemberDefinition.SetIsAssigned ();
6774 ec.Emit (OpCodes.Stsfld, spec);
6776 ec.Emit (OpCodes.Stfld, spec);
6778 if (ec.NotifyEvaluatorOnStore) {
6780 throw new NotImplementedException ("instance field write");
6783 ec.Emit (OpCodes.Dup);
6785 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6796 // Emits store to field with prepared values on stack
6798 public void EmitAssignFromStack (EmitContext ec)
6801 ec.Emit (OpCodes.Stsfld, spec);
6803 ec.Emit (OpCodes.Stfld, spec);
6807 public override void Emit (EmitContext ec)
6812 public override void EmitSideEffect (EmitContext ec)
6814 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6816 if (is_volatile) // || is_marshal_by_ref ())
6817 base.EmitSideEffect (ec);
6820 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6822 if ((mode & AddressOp.Store) != 0)
6823 spec.MemberDefinition.SetIsAssigned ();
6824 if ((mode & AddressOp.Load) != 0)
6825 spec.MemberDefinition.SetIsUsed ();
6828 // Handle initonly fields specially: make a copy and then
6829 // get the address of the copy.
6832 if (spec.IsReadOnly){
6834 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6846 var temp = ec.GetTemporaryLocal (type);
6847 ec.Emit (OpCodes.Stloc, temp);
6848 ec.Emit (OpCodes.Ldloca, temp);
6854 ec.Emit (OpCodes.Ldsflda, spec);
6857 EmitInstance (ec, false);
6858 ec.Emit (OpCodes.Ldflda, spec);
6862 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6864 return MakeExpression (ctx);
6867 public override SLE.Expression MakeExpression (BuilderContext ctx)
6870 return base.MakeExpression (ctx);
6872 return SLE.Expression.Field (
6873 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6874 spec.GetMetaInfo ());
6878 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6880 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6886 // Expression that evaluates to a Property.
6888 // This is not an LValue because we need to re-write the expression. We
6889 // can not take data from the stack and store it.
6891 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6893 Arguments arguments;
6894 FieldExpr backing_field;
6896 public PropertyExpr (PropertySpec spec, Location l)
6899 best_candidate = spec;
6900 type = spec.MemberType;
6905 protected override Arguments Arguments {
6914 protected override TypeSpec DeclaringType {
6916 return best_candidate.DeclaringType;
6920 public override string Name {
6922 return best_candidate.Name;
6926 public bool IsAutoPropertyAccess {
6928 var prop = best_candidate.MemberDefinition as Property;
6929 return prop != null && prop.BackingField != null;
6933 public override bool IsInstance {
6939 public override bool IsStatic {
6941 return best_candidate.IsStatic;
6945 public override string KindName {
6946 get { return "property"; }
6949 public PropertySpec PropertyInfo {
6951 return best_candidate;
6957 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6959 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6962 var args_count = arguments == null ? 0 : arguments.Count;
6963 if (args_count != body.Parameters.Count && args_count == 0)
6966 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6967 mg.InstanceExpression = InstanceExpression;
6972 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6974 return new PropertyExpr (spec, loc) {
6980 public override Expression CreateExpressionTree (ResolveContext ec)
6982 if (ConditionalAccess) {
6983 Error_NullShortCircuitInsideExpressionTree (ec);
6987 if (IsSingleDimensionalArrayLength ()) {
6988 args = new Arguments (1);
6989 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6990 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6993 args = new Arguments (2);
6994 if (InstanceExpression == null)
6995 args.Add (new Argument (new NullLiteral (loc)));
6997 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6998 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6999 return CreateExpressionFactoryCall (ec, "Property", args);
7002 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
7004 DoResolveLValue (rc, null);
7005 return new TypeOfMethod (Setter, loc);
7008 public override string GetSignatureForError ()
7010 return best_candidate.GetSignatureForError ();
7013 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
7016 return base.MakeExpression (ctx);
7018 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
7022 public override SLE.Expression MakeExpression (BuilderContext ctx)
7025 return base.MakeExpression (ctx);
7027 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
7031 void Error_PropertyNotValid (ResolveContext ec)
7033 ec.Report.SymbolRelatedToPreviousError (best_candidate);
7034 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
7035 GetSignatureForError ());
7038 bool IsSingleDimensionalArrayLength ()
7040 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7043 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7044 return ac != null && ac.Rank == 1;
7047 public override void Emit (EmitContext ec, bool leave_copy)
7050 // Special case: length of single dimension array property is turned into ldlen
7052 if (IsSingleDimensionalArrayLength ()) {
7053 if (conditional_access_receiver) {
7054 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7057 EmitInstance (ec, false);
7059 ec.Emit (OpCodes.Ldlen);
7060 ec.Emit (OpCodes.Conv_I4);
7062 if (conditional_access_receiver) {
7063 ec.CloseConditionalAccess (type);
7069 base.Emit (ec, leave_copy);
7072 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7074 if (backing_field != null) {
7075 backing_field.EmitAssign (ec, source, leave_copy, false);
7080 LocalTemporary await_source_arg = null;
7082 if (isCompound && !(source is DynamicExpressionStatement)) {
7083 emitting_compound_assignment = true;
7086 if (has_await_arguments) {
7087 await_source_arg = new LocalTemporary (Type);
7088 await_source_arg.Store (ec);
7090 args = new Arguments (1);
7091 args.Add (new Argument (await_source_arg));
7094 temp = await_source_arg;
7097 has_await_arguments = false;
7102 ec.Emit (OpCodes.Dup);
7103 temp = new LocalTemporary (this.Type);
7108 args = arguments ?? new Arguments (1);
7112 temp = new LocalTemporary (this.Type);
7114 args.Add (new Argument (temp));
7116 args.Add (new Argument (source));
7120 emitting_compound_assignment = false;
7122 var call = new CallEmitter ();
7123 call.InstanceExpression = InstanceExpression;
7125 call.InstanceExpressionOnStack = true;
7127 if (ConditionalAccess) {
7128 call.ConditionalAccess = true;
7132 call.Emit (ec, Setter, args, loc);
7134 call.EmitStatement (ec, Setter, args, loc);
7141 if (await_source_arg != null) {
7142 await_source_arg.Release (ec);
7146 public override void FlowAnalysis (FlowAnalysisContext fc)
7148 var prop = best_candidate.MemberDefinition as Property;
7149 if (prop != null && prop.BackingField != null) {
7150 var var = InstanceExpression as IVariableReference;
7152 var vi = var.VariableInfo;
7153 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7154 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7158 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7163 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7165 base.FlowAnalysis (fc);
7167 if (conditional_access_receiver)
7168 fc.DefiniteAssignment = da;
7171 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7173 eclass = ExprClass.PropertyAccess;
7175 if (best_candidate.IsNotCSharpCompatible) {
7176 Error_PropertyNotValid (rc);
7179 ResolveInstanceExpression (rc, right_side);
7181 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7182 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7183 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7185 type = p.MemberType;
7189 DoBestMemberChecks (rc, best_candidate);
7191 // Handling of com-imported properties with any number of default property parameters
7192 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7193 var p = best_candidate.Get.Parameters;
7194 arguments = new Arguments (p.Count);
7195 for (int i = 0; i < p.Count; ++i) {
7196 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7198 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7199 var p = best_candidate.Set.Parameters;
7200 arguments = new Arguments (p.Count - 1);
7201 for (int i = 0; i < p.Count - 1; ++i) {
7202 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7209 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7211 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7214 var prop = best_candidate.MemberDefinition as Property;
7215 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7216 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7220 prop = (Property)ps.MemberDefinition;
7223 var spec = prop.BackingField;
7227 if (rc.IsStatic != spec.IsStatic)
7230 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7233 backing_field = new FieldExpr (prop.BackingField, loc);
7234 backing_field.ResolveLValue (rc, rhs);
7238 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7240 if (!best_candidate.IsAccessible (rc))
7241 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7243 best_candidate.CheckObsoleteness (rc, expr.Location);
7246 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7248 if (backing_field != null) {
7249 backing_field.SetFieldAssigned (fc);
7253 if (!IsAutoPropertyAccess)
7256 var prop = best_candidate.MemberDefinition as Property;
7257 if (prop != null && prop.BackingField != null) {
7258 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7259 if (lvalue_instance) {
7260 var var = InstanceExpression as IVariableReference;
7261 if (var != null && var.VariableInfo != null) {
7262 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7268 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7270 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7274 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7276 // getter and setter can be different for base calls
7277 MethodSpec getter, setter;
7278 protected T best_candidate;
7280 protected LocalTemporary temp;
7281 protected bool emitting_compound_assignment;
7282 protected bool has_await_arguments;
7284 protected PropertyOrIndexerExpr (Location l)
7291 protected abstract Arguments Arguments { get; set; }
7293 public MethodSpec Getter {
7302 public MethodSpec Setter {
7313 protected override Expression DoResolve (ResolveContext ec)
7315 if (eclass == ExprClass.Unresolved) {
7316 ResolveConditionalAccessReceiver (ec);
7318 var expr = OverloadResolve (ec, null);
7323 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7324 return expr.Resolve (ec);
7327 if (conditional_access_receiver) {
7328 type = LiftMemberType (ec, type);
7332 if (!ResolveGetter (ec))
7338 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7340 if (HasConditionalAccess ())
7341 Error_NullPropagatingLValue (rc);
7343 if (right_side == EmptyExpression.OutAccess) {
7344 // TODO: best_candidate can be null at this point
7345 INamedBlockVariable variable = null;
7346 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7347 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7348 best_candidate.Name);
7350 right_side.DoResolveLValue (rc, this);
7355 if (eclass == ExprClass.Unresolved) {
7356 var expr = OverloadResolve (rc, right_side);
7361 return expr.ResolveLValue (rc, right_side);
7363 ResolveInstanceExpression (rc, right_side);
7366 if (!best_candidate.HasSet) {
7367 if (ResolveAutopropertyAssignment (rc, right_side))
7370 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7371 GetSignatureForError ());
7375 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7376 if (best_candidate.HasDifferentAccessibility) {
7377 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7378 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7379 GetSignatureForError ());
7381 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7382 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7386 if (best_candidate.HasDifferentAccessibility)
7387 CheckProtectedMemberAccess (rc, best_candidate.Set);
7389 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7393 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7395 var ca = ec.ConditionalAccess;
7396 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7398 call.Emit (ec, method, arguments, loc);
7400 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7401 ec.ConditionalAccess = ca;
7405 // Implements the IAssignMethod interface for assignments
7407 public virtual void Emit (EmitContext ec, bool leave_copy)
7409 var call = new CallEmitter ();
7410 call.ConditionalAccess = ConditionalAccess;
7411 call.InstanceExpression = InstanceExpression;
7412 if (has_await_arguments)
7413 call.HasAwaitArguments = true;
7415 call.DuplicateArguments = emitting_compound_assignment;
7417 if (conditional_access_receiver)
7418 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7420 call.Emit (ec, Getter, Arguments, loc);
7422 if (call.HasAwaitArguments) {
7423 InstanceExpression = call.InstanceExpression;
7424 Arguments = call.EmittedArguments;
7425 has_await_arguments = true;
7429 ec.Emit (OpCodes.Dup);
7430 temp = new LocalTemporary (Type);
7435 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7437 public override void Emit (EmitContext ec)
7442 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7444 has_await_arguments = true;
7449 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7451 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7453 bool ResolveGetter (ResolveContext rc)
7455 if (!best_candidate.HasGet) {
7456 if (InstanceExpression != EmptyExpression.Null) {
7457 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7458 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7459 best_candidate.GetSignatureForError ());
7462 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7463 if (best_candidate.HasDifferentAccessibility) {
7464 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7465 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7466 TypeManager.CSharpSignature (best_candidate));
7468 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7469 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7473 if (best_candidate.HasDifferentAccessibility) {
7474 CheckProtectedMemberAccess (rc, best_candidate.Get);
7477 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7481 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7488 /// Fully resolved expression that evaluates to an Event
7490 public class EventExpr : MemberExpr, IAssignMethod
7492 readonly EventSpec spec;
7495 public EventExpr (EventSpec spec, Location loc)
7503 protected override TypeSpec DeclaringType {
7505 return spec.DeclaringType;
7509 public override string Name {
7515 public override bool IsInstance {
7517 return !spec.IsStatic;
7521 public override bool IsStatic {
7523 return spec.IsStatic;
7527 public override string KindName {
7528 get { return "event"; }
7531 public MethodSpec Operator {
7539 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7542 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7544 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7545 if (spec.BackingField != null &&
7546 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7548 spec.MemberDefinition.SetIsUsed ();
7550 spec.CheckObsoleteness (ec, loc);
7552 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7553 Error_AssignmentEventOnly (ec);
7555 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7557 InstanceExpression = null;
7559 return ml.ResolveMemberAccess (ec, left, original);
7563 return base.ResolveMemberAccess (ec, left, original);
7566 public override Expression CreateExpressionTree (ResolveContext ec)
7568 throw new NotSupportedException ("ET");
7571 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7573 if (right_side == EmptyExpression.EventAddition) {
7574 op = spec.AccessorAdd;
7575 } else if (right_side == EmptyExpression.EventSubtraction) {
7576 op = spec.AccessorRemove;
7580 Error_AssignmentEventOnly (ec);
7584 if (HasConditionalAccess ())
7585 Error_NullPropagatingLValue (ec);
7587 op = CandidateToBaseOverride (ec, op);
7591 protected override Expression DoResolve (ResolveContext ec)
7593 eclass = ExprClass.EventAccess;
7594 type = spec.MemberType;
7596 ResolveInstanceExpression (ec, null);
7598 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7599 Error_AssignmentEventOnly (ec);
7602 DoBestMemberChecks (ec, spec);
7606 public override void Emit (EmitContext ec)
7608 throw new NotSupportedException ();
7609 //Error_CannotAssign ();
7612 #region IAssignMethod Members
7614 public void Emit (EmitContext ec, bool leave_copy)
7616 throw new NotImplementedException ();
7619 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7621 if (leave_copy || !isCompound)
7622 throw new NotImplementedException ("EventExpr::EmitAssign");
7624 Arguments args = new Arguments (1);
7625 args.Add (new Argument (source));
7627 // TODO: Wrong, needs receiver
7628 // if (NullShortCircuit) {
7629 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7632 var call = new CallEmitter ();
7633 call.InstanceExpression = InstanceExpression;
7634 call.ConditionalAccess = ConditionalAccess;
7635 call.EmitStatement (ec, op, args, loc);
7637 // if (NullShortCircuit)
7638 // ec.CloseConditionalAccess (null);
7643 void Error_AssignmentEventOnly (ResolveContext ec)
7645 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7646 ec.Report.Error (79, loc,
7647 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7648 GetSignatureForError ());
7650 ec.Report.Error (70, loc,
7651 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7652 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7656 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7658 name = name.Substring (0, name.LastIndexOf ('.'));
7659 base.Error_CannotCallAbstractBase (rc, name);
7662 public override string GetSignatureForError ()
7664 return TypeManager.CSharpSignature (spec);
7667 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7669 spec.CheckObsoleteness (rc, expr.Location);
7672 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7674 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7678 public class TemporaryVariableReference : VariableReference
7680 public class Declarator : Statement
7682 TemporaryVariableReference variable;
7684 public Declarator (TemporaryVariableReference variable)
7686 this.variable = variable;
7690 protected override void DoEmit (EmitContext ec)
7692 variable.li.CreateBuilder (ec);
7695 public override void Emit (EmitContext ec)
7697 // Don't create sequence point
7701 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7706 protected override void CloneTo (CloneContext clonectx, Statement target)
7714 public TemporaryVariableReference (LocalVariable li, Location loc)
7717 this.type = li.Type;
7721 public override bool IsLockedByStatement {
7729 public LocalVariable LocalInfo {
7735 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7737 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7738 return new TemporaryVariableReference (li, loc);
7741 protected override Expression DoResolve (ResolveContext ec)
7743 eclass = ExprClass.Variable;
7746 // Don't capture temporary variables except when using
7747 // state machine redirection and block yields
7749 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7750 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7751 ec.IsVariableCapturingRequired) {
7752 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7753 storey.CaptureLocalVariable (ec, li);
7759 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7761 return Resolve (ec);
7764 public override void Emit (EmitContext ec)
7766 li.CreateBuilder (ec);
7771 public void EmitAssign (EmitContext ec, Expression source)
7773 li.CreateBuilder (ec);
7775 EmitAssign (ec, source, false, false);
7778 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7780 return li.HoistedVariant;
7783 public override bool IsFixed {
7784 get { return true; }
7787 public override bool IsRef {
7788 get { return false; }
7791 public override string Name {
7792 get { throw new NotImplementedException (); }
7795 public override void SetHasAddressTaken ()
7797 throw new NotImplementedException ();
7800 protected override ILocalVariable Variable {
7804 public override VariableInfo VariableInfo {
7805 get { return null; }
7810 /// Handles `var' contextual keyword; var becomes a keyword only
7811 /// if no type called var exists in a variable scope
7813 class VarExpr : SimpleName
7815 public VarExpr (Location loc)
7820 public bool InferType (ResolveContext ec, Expression rhs)
7823 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7827 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || (rhs is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
7828 ec.Report.Error (815, loc,
7829 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7830 type.GetSignatureForError ());
7831 type = InternalType.ErrorType;
7835 eclass = ExprClass.Variable;
7839 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7841 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7842 base.Error_TypeOrNamespaceNotFound (ec);
7844 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");