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 expr.FlowAnalysis (fc);
2435 public override SLE.Expression MakeExpression (BuilderContext ctx)
2437 return orig_expr.MakeExpression (ctx);
2440 public override Reachability MarkReachable (Reachability rc)
2442 return expr.MarkReachable (rc);
2447 // Standard composite pattern
2449 public abstract class CompositeExpression : Expression
2451 protected Expression expr;
2453 protected CompositeExpression (Expression expr)
2456 this.loc = expr.Location;
2459 public override bool ContainsEmitWithAwait ()
2461 return expr.ContainsEmitWithAwait ();
2464 public override Expression CreateExpressionTree (ResolveContext rc)
2466 return expr.CreateExpressionTree (rc);
2469 public Expression Child {
2470 get { return expr; }
2473 protected override Expression DoResolve (ResolveContext rc)
2475 expr = expr.Resolve (rc);
2480 eclass = expr.eclass;
2484 public override void Emit (EmitContext ec)
2489 public override bool IsNull {
2490 get { return expr.IsNull; }
2495 // Base of expressions used only to narrow resolve flow
2497 public abstract class ShimExpression : Expression
2499 protected Expression expr;
2501 protected ShimExpression (Expression expr)
2506 public Expression Expr {
2512 protected override void CloneTo (CloneContext clonectx, Expression t)
2517 ShimExpression target = (ShimExpression) t;
2518 target.expr = expr.Clone (clonectx);
2521 public override bool ContainsEmitWithAwait ()
2523 return expr.ContainsEmitWithAwait ();
2526 public override Expression CreateExpressionTree (ResolveContext ec)
2528 throw new NotSupportedException ("ET");
2531 public override void Emit (EmitContext ec)
2533 throw new InternalErrorException ("Missing Resolve call");
2537 public class UnreachableExpression : Expression
2539 public UnreachableExpression (Expression expr)
2541 this.loc = expr.Location;
2544 public override Expression CreateExpressionTree (ResolveContext ec)
2547 throw new NotImplementedException ();
2550 protected override Expression DoResolve (ResolveContext rc)
2552 throw new NotSupportedException ();
2555 public override void FlowAnalysis (FlowAnalysisContext fc)
2557 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2560 public override void Emit (EmitContext ec)
2564 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2570 // Unresolved type name expressions
2572 public abstract class ATypeNameExpression : FullNamedExpression
2575 protected TypeArguments targs;
2577 protected ATypeNameExpression (string name, Location l)
2583 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2590 protected ATypeNameExpression (string name, int arity, Location l)
2591 : this (name, new UnboundTypeArguments (arity, l), l)
2599 return targs == null ? 0 : targs.Count;
2603 public bool HasTypeArguments {
2605 return targs != null && !targs.IsEmpty;
2609 public string Name {
2618 public TypeArguments TypeArguments {
2626 public override bool Equals (object obj)
2628 ATypeNameExpression atne = obj as ATypeNameExpression;
2629 return atne != null && atne.Name == Name &&
2630 (targs == null || targs.Equals (atne.targs));
2633 public override int GetHashCode ()
2635 return Name.GetHashCode ();
2638 // TODO: Move it to MemberCore
2639 public static string GetMemberType (MemberCore mc)
2645 if (mc is FieldBase)
2647 if (mc is MethodCore)
2649 if (mc is EnumMember)
2657 public override string GetSignatureForError ()
2659 if (targs != null) {
2660 return Name + "<" + targs.GetSignatureForError () + ">";
2666 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2670 /// SimpleName expressions are formed of a single word and only happen at the beginning
2671 /// of a dotted-name.
2673 public class SimpleName : ATypeNameExpression
2675 public SimpleName (string name, Location l)
2680 public SimpleName (string name, TypeArguments args, Location l)
2681 : base (name, args, l)
2685 public SimpleName (string name, int arity, Location l)
2686 : base (name, arity, l)
2690 public SimpleName GetMethodGroup ()
2692 return new SimpleName (Name, targs, loc);
2695 protected override Expression DoResolve (ResolveContext rc)
2697 return SimpleNameResolve (rc, null);
2700 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2702 return SimpleNameResolve (ec, right_side);
2705 public void Error_NameDoesNotExist (ResolveContext rc)
2707 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2710 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2712 if (ctx.CurrentType != null) {
2713 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2714 if (member != null) {
2715 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2720 var report = ctx.Module.Compiler.Report;
2722 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2723 if (retval != null) {
2724 report.SymbolRelatedToPreviousError (retval.Type);
2725 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2729 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2730 if (retval != null) {
2731 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2735 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2736 if (ns_candidates != null) {
2737 if (ctx is UsingAliasNamespace.AliasContext) {
2738 report.Error (246, loc,
2739 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2740 ns_candidates[0], Name);
2742 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2743 report.Error (246, loc,
2744 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2748 report.Error (246, loc,
2749 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2754 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2756 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2759 if (fne.Type != null && Arity > 0) {
2760 if (HasTypeArguments) {
2761 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2762 if (ct.ResolveAsType (mc) == null)
2768 targs.Resolve (mc, allowUnboundTypeArguments);
2770 return new GenericOpenTypeExpr (fne.Type, loc);
2774 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2776 if (!(fne is NamespaceExpression))
2780 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2781 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2782 mc.Module.Compiler.Report.Error (1980, Location,
2783 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2784 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2787 fne = new DynamicTypeExpr (loc);
2788 fne.ResolveAsType (mc);
2794 Error_TypeOrNamespaceNotFound (mc);
2798 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2801 // Has to ignore static usings because we are looking for any member not just type
2804 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2807 public bool IsPossibleType (IMemberContext mc)
2809 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2812 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2814 int lookup_arity = Arity;
2815 bool errorMode = false;
2817 Block current_block = rc.CurrentBlock;
2818 INamedBlockVariable variable = null;
2819 bool variable_found = false;
2823 // Stage 1: binding to local variables or parameters
2825 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2827 if (current_block != null && lookup_arity == 0) {
2828 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2829 if (!variable.IsDeclared) {
2830 // We found local name in accessible block but it's not
2831 // initialized yet, maybe the user wanted to bind to something else
2833 variable_found = true;
2835 e = variable.CreateReferenceExpression (rc, loc);
2838 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2847 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2849 TypeSpec member_type = rc.CurrentType;
2850 for (; member_type != null; member_type = member_type.DeclaringType) {
2851 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2855 var me = e as MemberExpr;
2857 // The name matches a type, defer to ResolveAsTypeStep
2865 if (variable != null) {
2866 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2867 rc.Report.Error (844, loc,
2868 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2869 Name, me.GetSignatureForError ());
2873 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2874 // Leave it to overload resolution to report correct error
2876 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2877 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2881 // MemberLookup does not check accessors availability, this is actually needed for properties only
2883 var pe = me as PropertyExpr;
2886 // Break as there is no other overload available anyway
2887 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2888 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2891 pe.Getter = pe.PropertyInfo.Get;
2893 if (!pe.PropertyInfo.HasSet) {
2894 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2895 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2896 var p = (Property) pe.PropertyInfo.MemberDefinition;
2897 return new FieldExpr (p.BackingField, loc);
2900 variable_found = true;
2904 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2905 variable_found = true;
2909 pe.Setter = pe.PropertyInfo.Set;
2914 // TODO: It's used by EventExpr -> FieldExpr transformation only
2915 // TODO: Should go to MemberAccess
2916 me = me.ResolveMemberAccess (rc, null, null);
2919 targs.Resolve (rc, false);
2920 me.SetTypeArguments (rc, targs);
2927 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2929 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2930 if (IsPossibleTypeOrNamespace (rc)) {
2931 return ResolveAsTypeOrNamespace (rc, false);
2935 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2938 targs.Resolve (rc, false);
2940 var me = expr as MemberExpr;
2942 me.SetTypeArguments (rc, targs);
2947 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2948 return new NameOf (this);
2951 if (variable_found) {
2952 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2955 var tparams = rc.CurrentTypeParameters;
2956 if (tparams != null) {
2957 if (tparams.Find (Name) != null) {
2958 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2963 var ct = rc.CurrentType;
2965 if (ct.MemberDefinition.TypeParametersCount > 0) {
2966 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2967 if (ctp.Name == Name) {
2968 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2974 ct = ct.DeclaringType;
2975 } while (ct != null);
2978 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2979 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2981 rc.Report.SymbolRelatedToPreviousError (e.Type);
2982 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2986 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2988 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2989 return ErrorExpression.Instance;
2993 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2995 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2996 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
3000 if (e is TypeExpr) {
3001 // TypeExpression does not have correct location
3002 if (e is TypeExpression)
3003 e = new TypeExpression (e.Type, loc);
3009 Error_NameDoesNotExist (rc);
3012 return ErrorExpression.Instance;
3015 if (rc.Module.Evaluator != null) {
3016 var fi = rc.Module.Evaluator.LookupField (Name);
3018 return new FieldExpr (fi.Item1, loc);
3026 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3028 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3033 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3034 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3038 if (right_side != null) {
3039 e = e.ResolveLValue (ec, right_side);
3047 public override object Accept (StructuralVisitor visitor)
3049 return visitor.Visit (this);
3054 /// Represents a namespace or a type. The name of the class was inspired by
3055 /// section 10.8.1 (Fully Qualified Names).
3057 public abstract class FullNamedExpression : Expression
3059 protected override void CloneTo (CloneContext clonectx, Expression target)
3061 // Do nothing, most unresolved type expressions cannot be
3062 // resolved to different type
3065 public override bool ContainsEmitWithAwait ()
3070 public override Expression CreateExpressionTree (ResolveContext ec)
3072 throw new NotSupportedException ("ET");
3075 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3078 // This is used to resolve the expression as a type, a null
3079 // value will be returned if the expression is not a type
3082 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3084 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3089 TypeExpr te = fne as TypeExpr;
3091 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3099 var dep = type.GetMissingDependencies ();
3101 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3104 if (type.Kind == MemberKind.Void) {
3105 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3109 // Obsolete checks cannot be done when resolving base context as they
3110 // require type dependencies to be set but we are in process of resolving them
3112 if (mc is ResolveContext) {
3113 var oa = type.GetAttributeObsolete ();
3114 if (oa != null && !mc.IsObsolete)
3115 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3122 public override void Emit (EmitContext ec)
3124 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3125 GetSignatureForError ());
3130 /// Expression that evaluates to a type
3132 public abstract class TypeExpr : FullNamedExpression
3134 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3140 protected sealed override Expression DoResolve (ResolveContext ec)
3146 public override bool Equals (object obj)
3148 TypeExpr tobj = obj as TypeExpr;
3152 return Type == tobj.Type;
3155 public override int GetHashCode ()
3157 return Type.GetHashCode ();
3162 /// Fully resolved Expression that already evaluated to a type
3164 public class TypeExpression : TypeExpr
3166 public TypeExpression (TypeSpec t, Location l)
3169 eclass = ExprClass.Type;
3173 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3179 public class NamespaceExpression : FullNamedExpression
3181 readonly Namespace ns;
3183 public NamespaceExpression (Namespace ns, Location loc)
3186 this.Type = InternalType.Namespace;
3187 this.eclass = ExprClass.Namespace;
3191 public Namespace Namespace {
3197 protected override Expression DoResolve (ResolveContext rc)
3199 throw new NotImplementedException ();
3202 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3207 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3209 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3210 if (retval != null) {
3211 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3212 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3216 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3217 if (retval != null) {
3218 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3223 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3224 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3228 string assembly = null;
3229 string possible_name = Namespace.GetSignatureForError () + "." + name;
3231 // Only assembly unique name should be added
3232 switch (possible_name) {
3233 case "System.Drawing":
3234 case "System.Web.Services":
3237 case "System.Configuration":
3238 case "System.Data.Services":
3239 case "System.DirectoryServices":
3241 case "System.Net.Http":
3242 case "System.Numerics":
3243 case "System.Runtime.Caching":
3244 case "System.ServiceModel":
3245 case "System.Transactions":
3246 case "System.Web.Routing":
3247 case "System.Xml.Linq":
3249 assembly = possible_name;
3253 case "System.Linq.Expressions":
3254 assembly = "System.Core";
3257 case "System.Windows.Forms":
3258 case "System.Windows.Forms.Layout":
3259 assembly = "System.Windows.Forms";
3263 assembly = assembly == null ? "an" : "`" + assembly + "'";
3265 if (Namespace is GlobalRootNamespace) {
3266 ctx.Module.Compiler.Report.Error (400, loc,
3267 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3270 ctx.Module.Compiler.Report.Error (234, loc,
3271 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3272 name, GetSignatureForError (), assembly);
3276 public override string GetSignatureForError ()
3278 return ns.GetSignatureForError ();
3281 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3283 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3286 public override string ToString ()
3288 return Namespace.Name;
3293 /// This class denotes an expression which evaluates to a member
3294 /// of a struct or a class.
3296 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3298 protected bool conditional_access_receiver;
3301 // An instance expression associated with this member, if it's a
3302 // non-static member
3304 public Expression InstanceExpression;
3307 /// The name of this member.
3309 public abstract string Name {
3314 // When base.member is used
3316 public bool IsBase {
3317 get { return InstanceExpression is BaseThis; }
3321 /// Whether this is an instance member.
3323 public abstract bool IsInstance {
3328 /// Whether this is a static member.
3330 public abstract bool IsStatic {
3334 public abstract string KindName {
3338 public bool ConditionalAccess { get; set; }
3340 protected abstract TypeSpec DeclaringType {
3344 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3346 return InstanceExpression.Type;
3351 // Converts best base candidate for virtual method starting from QueriedBaseType
3353 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3356 // Only when base.member is used and method is virtual
3362 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3363 // means for base.member access we have to find the closest match after we found best candidate
3365 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3367 // The method could already be what we are looking for
3369 TypeSpec[] targs = null;
3370 if (method.DeclaringType != InstanceExpression.Type) {
3372 // Candidate can have inflated MVAR parameters and we need to find
3373 // base match for original definition not inflated parameter types
3375 var parameters = method.Parameters;
3376 if (method.Arity > 0) {
3377 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3378 var inflated = method.DeclaringType as InflatedTypeSpec;
3379 if (inflated != null) {
3380 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3384 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3385 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3386 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3387 if (base_override.IsGeneric)
3388 targs = method.TypeArguments;
3390 method = base_override;
3395 // When base access is used inside anonymous method/iterator/etc we need to
3396 // get back to the context of original type. We do it by emiting proxy
3397 // method in original class and rewriting base call to this compiler
3398 // generated method call which does the actual base invocation. This may
3399 // introduce redundant storey but with `this' only but it's tricky to avoid
3400 // at this stage as we don't know what expressions follow base
3402 // TODO: It's needed only when the method with base call is moved to a storey
3404 if (rc.CurrentAnonymousMethod != null) {
3405 if (targs == null && method.IsGeneric) {
3406 targs = method.TypeArguments;
3407 method = method.GetGenericMethodDefinition ();
3410 if (method.Parameters.HasArglist)
3411 throw new NotImplementedException ("__arglist base call proxy");
3413 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3415 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3416 // get/set member expressions second call would fail to proxy because left expression
3417 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3418 // FIXME: The async check is another hack but will probably fail with mutators
3419 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3420 InstanceExpression = new This (loc).Resolve (rc);
3424 method = method.MakeGenericMethod (rc, targs);
3428 // Only base will allow this invocation to happen.
3430 if (method.IsAbstract) {
3431 rc.Report.SymbolRelatedToPreviousError (method);
3432 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3438 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3440 if (InstanceExpression == null)
3443 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3444 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3445 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3450 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3452 if (InstanceExpression == null)
3455 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3458 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3460 var ct = rc.CurrentType;
3461 if (ct == qualifier)
3464 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3467 qualifier = qualifier.GetDefinition ();
3468 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3475 public override bool ContainsEmitWithAwait ()
3477 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3480 public override bool HasConditionalAccess ()
3482 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3485 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3488 type = type.GetDefinition ();
3490 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3493 type = type.DeclaringType;
3494 } while (type != null);
3499 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3501 if (InstanceExpression != null) {
3502 InstanceExpression = InstanceExpression.Resolve (rc);
3503 CheckProtectedMemberAccess (rc, member);
3506 if (member.MemberType.IsPointer) {
3507 if (rc.CurrentIterator != null) {
3508 UnsafeInsideIteratorError (rc, loc);
3509 } else if (!rc.IsUnsafe) {
3510 UnsafeError (rc, loc);
3514 var dep = member.GetMissingDependencies ();
3516 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3519 member.CheckObsoleteness (rc, loc);
3521 if (!(member is FieldSpec))
3522 member.MemberDefinition.SetIsUsed ();
3525 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3527 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3530 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3532 rc.Report.SymbolRelatedToPreviousError (member);
3533 rc.Report.Error (1540, loc,
3534 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3535 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3538 public override void FlowAnalysis (FlowAnalysisContext fc)
3540 if (InstanceExpression != null) {
3541 InstanceExpression.FlowAnalysis (fc);
3545 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3547 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3548 conditional_access_receiver = true;
3552 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3554 if (!ResolveInstanceExpressionCore (rc, rhs))
3558 // Check intermediate value modification which won't have any effect
3560 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3561 var fexpr = InstanceExpression as FieldExpr;
3562 if (fexpr != null) {
3563 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3566 if (fexpr.IsStatic) {
3567 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3568 fexpr.GetSignatureForError ());
3570 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3571 fexpr.GetSignatureForError ());
3577 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3578 if (rc.CurrentInitializerVariable != null) {
3579 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3580 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3582 rc.Report.Error (1612, loc,
3583 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3584 InstanceExpression.GetSignatureForError ());
3590 var lvr = InstanceExpression as LocalVariableReference;
3593 if (!lvr.local_info.IsReadonly)
3596 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3597 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3604 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3607 if (InstanceExpression != null) {
3608 if (InstanceExpression is TypeExpr) {
3609 var t = InstanceExpression.Type;
3611 t.CheckObsoleteness (rc, loc);
3613 t = t.DeclaringType;
3614 } while (t != null);
3616 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3617 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3618 rc.Report.Error (176, loc,
3619 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3620 GetSignatureForError ());
3624 InstanceExpression = null;
3630 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3631 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3632 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3633 rc.Report.Error (236, loc,
3634 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3635 GetSignatureForError ());
3637 var fe = this as FieldExpr;
3638 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3639 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3640 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3642 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3646 rc.Report.Error (120, loc,
3647 "An object reference is required to access non-static member `{0}'",
3648 GetSignatureForError ());
3652 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3656 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3657 rc.Report.Error (38, loc,
3658 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3659 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3662 InstanceExpression = new This (loc).Resolve (rc);
3666 var me = InstanceExpression as MemberExpr;
3668 me.ResolveInstanceExpressionCore (rc, rhs);
3670 var fe = me as FieldExpr;
3671 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3672 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3673 rc.Report.Warning (1690, 1, loc,
3674 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3675 me.GetSignatureForError ());
3682 // Additional checks for l-value member access
3685 if (InstanceExpression is UnboxCast) {
3686 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3693 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3695 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3696 ec.Report.Warning (1720, 1, left.Location,
3697 "Expression will always cause a `{0}'", "System.NullReferenceException");
3700 InstanceExpression = left;
3704 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3709 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3711 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3712 inst.Emit (ec, ConditionalAccess);
3714 if (prepare_for_load)
3715 ec.Emit (OpCodes.Dup);
3718 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3721 public class ExtensionMethodCandidates
3723 readonly NamespaceContainer container;
3724 readonly IList<MethodSpec> methods;
3726 readonly IMemberContext context;
3728 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3730 this.context = context;
3731 this.methods = methods;
3732 this.container = nsContainer;
3733 this.index = lookupIndex;
3736 public NamespaceContainer Container {
3742 public IMemberContext Context {
3748 public int LookupIndex {
3754 public IList<MethodSpec> Methods {
3762 // Represents a group of extension method candidates for whole namespace
3764 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3766 ExtensionMethodCandidates candidates;
3767 public Expression ExtensionExpression;
3769 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3770 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3772 this.candidates = candidates;
3773 this.ExtensionExpression = extensionExpr;
3776 public override bool IsStatic {
3777 get { return true; }
3781 // For extension methodgroup we are not looking for base members but parent
3782 // namespace extension methods
3784 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3786 // TODO: candidates are null only when doing error reporting, that's
3787 // incorrect. We have to discover same extension methods in error mode
3788 if (candidates == null)
3791 int arity = type_arguments == null ? 0 : type_arguments.Count;
3793 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3794 if (candidates == null)
3797 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3800 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3803 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3805 // LAMESPEC: or implicit type parameter conversion
3807 return argType == extensionType ||
3808 TypeSpecComparer.IsEqual (argType, extensionType) ||
3809 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3810 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3813 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3815 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3818 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3820 // We are already here
3824 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3826 if (arguments == null)
3827 arguments = new Arguments (1);
3829 ExtensionExpression = ExtensionExpression.Resolve (ec);
3830 if (ExtensionExpression == null)
3833 var cand = candidates;
3834 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3835 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3836 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3838 // Restore candidates in case we are running in probing mode
3841 // Store resolved argument and restore original arguments
3843 // Clean-up modified arguments for error reporting
3844 arguments.RemoveAt (0);
3848 var me = ExtensionExpression as MemberExpr;
3850 me.ResolveInstanceExpression (ec, null);
3851 var fe = me as FieldExpr;
3853 fe.Spec.MemberDefinition.SetIsUsed ();
3856 InstanceExpression = null;
3860 #region IErrorHandler Members
3862 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3867 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3869 rc.Report.SymbolRelatedToPreviousError (best);
3872 rc.Report.Error (1929, loc,
3873 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3874 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3876 rc.Report.Error (1928, loc,
3877 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3878 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3884 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3889 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3898 /// MethodGroupExpr represents a group of method candidates which
3899 /// can be resolved to the best method overload
3901 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3903 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3905 protected IList<MemberSpec> Methods;
3906 MethodSpec best_candidate;
3907 TypeSpec best_candidate_return;
3908 protected TypeArguments type_arguments;
3910 SimpleName simple_name;
3911 protected TypeSpec queried_type;
3913 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3917 this.type = InternalType.MethodGroup;
3919 eclass = ExprClass.MethodGroup;
3920 queried_type = type;
3923 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3924 : this (new MemberSpec[] { m }, type, loc)
3930 public MethodSpec BestCandidate {
3932 return best_candidate;
3936 public TypeSpec BestCandidateReturnType {
3938 return best_candidate_return;
3942 public IList<MemberSpec> Candidates {
3948 protected override TypeSpec DeclaringType {
3950 return queried_type;
3954 public bool IsConditionallyExcluded {
3956 return Methods == Excluded;
3960 public override bool IsInstance {
3962 if (best_candidate != null)
3963 return !best_candidate.IsStatic;
3969 public override bool IsSideEffectFree {
3971 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3975 public override bool IsStatic {
3977 if (best_candidate != null)
3978 return best_candidate.IsStatic;
3984 public override string KindName {
3985 get { return "method"; }
3988 public override string Name {
3990 if (best_candidate != null)
3991 return best_candidate.Name;
3994 return Methods.First ().Name;
4001 // When best candidate is already know this factory can be used
4002 // to avoid expensive overload resolution to be called
4004 // NOTE: InstanceExpression has to be set manually
4006 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4008 return new MethodGroupExpr (best, queriedType, loc) {
4009 best_candidate = best,
4010 best_candidate_return = best.ReturnType
4014 public override string GetSignatureForError ()
4016 if (best_candidate != null)
4017 return best_candidate.GetSignatureForError ();
4019 return Methods.First ().GetSignatureForError ();
4022 public override Expression CreateExpressionTree (ResolveContext ec)
4024 if (best_candidate == null) {
4025 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4029 if (IsConditionallyExcluded)
4030 ec.Report.Error (765, loc,
4031 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4033 if (ConditionalAccess)
4034 Error_NullShortCircuitInsideExpressionTree (ec);
4036 return new TypeOfMethod (best_candidate, loc);
4039 protected override Expression DoResolve (ResolveContext ec)
4041 this.eclass = ExprClass.MethodGroup;
4043 if (InstanceExpression != null) {
4044 InstanceExpression = InstanceExpression.Resolve (ec);
4045 if (InstanceExpression == null)
4052 public override void Emit (EmitContext ec)
4054 throw new NotSupportedException ();
4057 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4059 var call = new CallEmitter ();
4060 call.InstanceExpression = InstanceExpression;
4061 call.ConditionalAccess = ConditionalAccess;
4064 call.EmitStatement (ec, best_candidate, arguments, loc);
4066 call.Emit (ec, best_candidate, arguments, loc);
4069 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4071 var ca = ec.ConditionalAccess;
4072 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4073 Statement = statement
4076 EmitCall (ec, arguments, statement);
4078 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4079 ec.ConditionalAccess = ca;
4082 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4084 if (target != InternalType.ErrorType) {
4085 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4086 Name, target.GetSignatureForError ());
4090 public bool HasAccessibleCandidate (ResolveContext rc)
4092 foreach (var candidate in Candidates) {
4093 if (candidate.IsAccessible (rc))
4100 public static bool IsExtensionMethodArgument (Expression expr)
4103 // LAMESPEC: No details about which expressions are not allowed
4105 return !(expr is TypeExpr) && !(expr is BaseThis);
4109 /// Find the Applicable Function Members (7.4.2.1)
4111 /// me: Method Group expression with the members to select.
4112 /// it might contain constructors or methods (or anything
4113 /// that maps to a method).
4115 /// Arguments: ArrayList containing resolved Argument objects.
4117 /// loc: The location if we want an error to be reported, or a Null
4118 /// location for "probing" purposes.
4120 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4121 /// that is the best match of me on Arguments.
4124 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4126 // TODO: causes issues with probing mode, remove explicit Kind check
4127 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4130 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4131 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4132 r.BaseMembersProvider = this;
4133 r.InstanceQualifier = this;
4136 if (cerrors != null)
4137 r.CustomErrors = cerrors;
4139 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4140 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4141 if (best_candidate == null) {
4142 if (!r.BestCandidateIsDynamic)
4145 if (simple_name != null && ec.IsStatic)
4146 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4151 // Overload resolver had to create a new method group, all checks bellow have already been executed
4152 if (r.BestCandidateNewMethodGroup != null)
4153 return r.BestCandidateNewMethodGroup;
4155 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4156 if (InstanceExpression != null) {
4157 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4158 InstanceExpression = null;
4160 if (simple_name != null && best_candidate.IsStatic) {
4161 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4164 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4168 ResolveInstanceExpression (ec, null);
4171 var base_override = CandidateToBaseOverride (ec, best_candidate);
4172 if (base_override == best_candidate) {
4173 best_candidate_return = r.BestCandidateReturnType;
4175 best_candidate = base_override;
4176 best_candidate_return = best_candidate.ReturnType;
4179 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4180 ConstraintChecker cc = new ConstraintChecker (ec);
4181 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4185 // Additional check for possible imported base override method which
4186 // could not be done during IsOverrideMethodBaseTypeAccessible
4188 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4189 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4190 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4191 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4194 // Speed up the check by not doing it on disallowed targets
4195 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4201 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4203 var fe = left as FieldExpr;
4206 // Using method-group on struct fields makes the struct assigned. I am not sure
4207 // why but that's what .net does
4209 fe.Spec.MemberDefinition.SetIsAssigned ();
4212 simple_name = original;
4213 return base.ResolveMemberAccess (ec, left, original);
4216 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4218 if (!HasAccessibleCandidate (rc)) {
4219 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4222 if (expr.HasTypeArguments) {
4223 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4227 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4229 type_arguments = ta;
4232 #region IBaseMembersProvider Members
4234 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4236 var baseType = type.BaseType;
4238 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4240 if (members == null && !type.IsInterface) {
4241 var tps = queried_type as TypeParameterSpec;
4243 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4249 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4251 if (queried_type == member.DeclaringType)
4254 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4255 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4259 // Extension methods lookup after ordinary methods candidates failed to apply
4261 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4263 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4266 if (!IsExtensionMethodArgument (InstanceExpression))
4269 int arity = type_arguments == null ? 0 : type_arguments.Count;
4270 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4271 if (methods == null)
4274 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4275 emg.SetTypeArguments (rc, type_arguments);
4276 emg.ConditionalAccess = ConditionalAccess;
4283 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4285 public ConstructorInstanceQualifier (TypeSpec type)
4288 InstanceType = type;
4291 public TypeSpec InstanceType { get; private set; }
4293 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4295 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4299 public struct OverloadResolver
4302 public enum Restrictions
4306 ProbingOnly = 1 << 1,
4307 CovariantDelegate = 1 << 2,
4308 NoBaseMembers = 1 << 3,
4309 BaseMembersIncluded = 1 << 4,
4310 GetEnumeratorLookup = 1 << 5
4313 public interface IBaseMembersProvider
4315 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4316 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4317 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4320 public interface IErrorHandler
4322 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4323 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4324 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4325 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4328 public interface IInstanceQualifier
4330 TypeSpec InstanceType { get; }
4331 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4334 sealed class NoBaseMembers : IBaseMembersProvider
4336 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4338 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4343 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4348 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4354 struct AmbiguousCandidate
4356 public readonly MemberSpec Member;
4357 public readonly bool Expanded;
4358 public readonly AParametersCollection Parameters;
4360 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4363 Parameters = parameters;
4364 Expanded = expanded;
4369 IList<MemberSpec> members;
4370 TypeArguments type_arguments;
4371 IBaseMembersProvider base_provider;
4372 IErrorHandler custom_errors;
4373 IInstanceQualifier instance_qualifier;
4374 Restrictions restrictions;
4375 MethodGroupExpr best_candidate_extension_group;
4376 TypeSpec best_candidate_return_type;
4378 SessionReportPrinter lambda_conv_msgs;
4380 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4381 : this (members, null, restrictions, loc)
4385 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4388 if (members == null || members.Count == 0)
4389 throw new ArgumentException ("empty members set");
4391 this.members = members;
4393 type_arguments = targs;
4394 this.restrictions = restrictions;
4395 if (IsDelegateInvoke)
4396 this.restrictions |= Restrictions.NoBaseMembers;
4398 base_provider = NoBaseMembers.Instance;
4403 public IBaseMembersProvider BaseMembersProvider {
4405 return base_provider;
4408 base_provider = value;
4412 public bool BestCandidateIsDynamic { get; set; }
4415 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4417 public MethodGroupExpr BestCandidateNewMethodGroup {
4419 return best_candidate_extension_group;
4424 // Return type can be different between best candidate and closest override
4426 public TypeSpec BestCandidateReturnType {
4428 return best_candidate_return_type;
4432 public IErrorHandler CustomErrors {
4434 return custom_errors;
4437 custom_errors = value;
4441 TypeSpec DelegateType {
4443 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4444 throw new InternalErrorException ("Not running in delegate mode", loc);
4446 return members [0].DeclaringType;
4450 public IInstanceQualifier InstanceQualifier {
4452 return instance_qualifier;
4455 instance_qualifier = value;
4459 bool IsProbingOnly {
4461 return (restrictions & Restrictions.ProbingOnly) != 0;
4465 bool IsDelegateInvoke {
4467 return (restrictions & Restrictions.DelegateInvoke) != 0;
4474 // 7.4.3.3 Better conversion from expression
4475 // Returns : 1 if a->p is better,
4476 // 2 if a->q is better,
4477 // 0 if neither is better
4479 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4481 TypeSpec argument_type = a.Type;
4484 // Exactly matching Expression phase
4488 // If argument is an anonymous function
4490 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4492 // p and q are delegate types or expression tree types
4494 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4495 if (q.MemberDefinition != p.MemberDefinition) {
4500 // Uwrap delegate from Expression<T>
4502 q = TypeManager.GetTypeArguments (q) [0];
4503 p = TypeManager.GetTypeArguments (p) [0];
4506 var p_m = Delegate.GetInvokeMethod (p);
4507 var q_m = Delegate.GetInvokeMethod (q);
4510 // With identical parameter lists
4512 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4520 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4522 if (p.Kind == MemberKind.Void) {
4523 return q.Kind != MemberKind.Void ? 2 : 0;
4527 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4529 if (q.Kind == MemberKind.Void) {
4530 return p.Kind != MemberKind.Void ? 1 : 0;
4533 var am = (AnonymousMethodExpression)a.Expr;
4536 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4537 // better conversion is performed between underlying types Y1 and Y2
4539 if (p.IsGenericTask || q.IsGenericTask) {
4540 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4541 q = q.TypeArguments [0];
4542 p = p.TypeArguments [0];
4548 // An inferred return type X exists for E in the context of the parameter list, and
4549 // an identity conversion exists from X to the return type of D
4551 var inferred_type = am.InferReturnType (ec, null, orig_q);
4552 if (inferred_type != null) {
4553 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4554 inferred_type = ec.BuiltinTypes.Object;
4556 if (inferred_type == p)
4559 if (inferred_type == q)
4565 if (argument_type == p)
4568 if (argument_type == q)
4571 return IsBetterConversionTarget (ec, p, q);
4574 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4576 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4578 if (p.Kind != MemberKind.Delegate) {
4579 p = TypeManager.GetTypeArguments (p) [0];
4582 if (q.Kind != MemberKind.Delegate) {
4583 q = TypeManager.GetTypeArguments (q) [0];
4586 var p_m = Delegate.GetInvokeMethod (p);
4587 var q_m = Delegate.GetInvokeMethod (q);
4593 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4595 if (p.Kind == MemberKind.Void) {
4596 return q.Kind != MemberKind.Void ? 2 : 0;
4600 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4602 if (q.Kind == MemberKind.Void) {
4603 return p.Kind != MemberKind.Void ? 1 : 0;
4606 return IsBetterConversionTarget (rc, p, q);
4609 if (p.IsGenericTask && q.IsGenericTask) {
4610 q = q.TypeArguments [0];
4611 p = p.TypeArguments [0];
4612 return IsBetterConversionTarget (rc, p, q);
4616 if (p.IsNullableType) {
4617 p = Nullable.NullableInfo.GetUnderlyingType (p);
4618 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4619 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4622 // Spec expects implicit conversion check between p and q, q and p
4623 // to be done before nullable unwrapping but that's expensive operation.
4625 // Extra manual tweak is needed because BetterTypeConversion works on
4633 if (q.IsNullableType) {
4634 q = Nullable.NullableInfo.GetUnderlyingType (q);
4635 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4636 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4642 return BetterTypeConversion (rc, p, q);
4646 // 7.4.3.4 Better conversion from type
4648 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4650 if (p == null || q == null)
4651 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4653 switch (p.BuiltinType) {
4654 case BuiltinTypeSpec.Type.Int:
4655 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4658 case BuiltinTypeSpec.Type.Long:
4659 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4662 case BuiltinTypeSpec.Type.SByte:
4663 switch (q.BuiltinType) {
4664 case BuiltinTypeSpec.Type.Byte:
4665 case BuiltinTypeSpec.Type.UShort:
4666 case BuiltinTypeSpec.Type.UInt:
4667 case BuiltinTypeSpec.Type.ULong:
4671 case BuiltinTypeSpec.Type.Short:
4672 switch (q.BuiltinType) {
4673 case BuiltinTypeSpec.Type.UShort:
4674 case BuiltinTypeSpec.Type.UInt:
4675 case BuiltinTypeSpec.Type.ULong:
4679 case BuiltinTypeSpec.Type.Dynamic:
4680 // LAMESPEC: Dynamic conversions is not considered
4681 p = ec.Module.Compiler.BuiltinTypes.Object;
4685 switch (q.BuiltinType) {
4686 case BuiltinTypeSpec.Type.Int:
4687 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4690 case BuiltinTypeSpec.Type.Long:
4691 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4694 case BuiltinTypeSpec.Type.SByte:
4695 switch (p.BuiltinType) {
4696 case BuiltinTypeSpec.Type.Byte:
4697 case BuiltinTypeSpec.Type.UShort:
4698 case BuiltinTypeSpec.Type.UInt:
4699 case BuiltinTypeSpec.Type.ULong:
4703 case BuiltinTypeSpec.Type.Short:
4704 switch (p.BuiltinType) {
4705 case BuiltinTypeSpec.Type.UShort:
4706 case BuiltinTypeSpec.Type.UInt:
4707 case BuiltinTypeSpec.Type.ULong:
4711 case BuiltinTypeSpec.Type.Dynamic:
4712 // LAMESPEC: Dynamic conversions is not considered
4713 q = ec.Module.Compiler.BuiltinTypes.Object;
4717 return BetterTypeConversionImplicitConversion (ec, p, q);
4720 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4722 // TODO: this is expensive
4723 Expression p_tmp = new EmptyExpression (p);
4724 Expression q_tmp = new EmptyExpression (q);
4726 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4727 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4729 if (p_to_q && !q_to_p)
4732 if (q_to_p && !p_to_q)
4739 /// Determines "Better function" between candidate
4740 /// and the current best match
4743 /// Returns a boolean indicating :
4744 /// false if candidate ain't better
4745 /// true if candidate is better than the current best match
4747 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4748 MemberSpec best, AParametersCollection bparam, bool best_params)
4750 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4751 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4753 int candidate_better_count = 0;
4754 int best_better_count = 0;
4756 bool are_equivalent = true;
4757 int args_count = args == null ? 0 : args.Count;
4761 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4764 // Default arguments are ignored for better decision
4765 if (a.IsDefaultArgument)
4769 // When comparing named argument the parameter type index has to be looked up
4770 // in original parameter set (override version for virtual members)
4772 NamedArgument na = a as NamedArgument;
4774 int idx = cparam.GetParameterIndexByName (na.Name);
4775 ct = candidate_pd.Types[idx];
4776 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4777 ct = TypeManager.GetElementType (ct);
4779 idx = bparam.GetParameterIndexByName (na.Name);
4780 bt = best_pd.Types[idx];
4781 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4782 bt = TypeManager.GetElementType (bt);
4784 ct = candidate_pd.Types[c_idx];
4785 bt = best_pd.Types[b_idx];
4787 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4788 ct = TypeManager.GetElementType (ct);
4792 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4793 bt = TypeManager.GetElementType (bt);
4798 if (TypeSpecComparer.IsEqual (ct, bt))
4801 are_equivalent = false;
4802 int result = BetterExpressionConversion (ec, a, ct, bt);
4804 // for each argument, the conversion to 'ct' should be no worse than
4805 // the conversion to 'bt'.
4808 // No optional parameters tie breaking rules for delegates overload resolution
4810 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4813 ++best_better_count;
4817 // for at least one argument, the conversion to 'ct' should be better than
4818 // the conversion to 'bt'.
4820 ++candidate_better_count;
4823 if (candidate_better_count != 0 && best_better_count == 0)
4826 if (best_better_count > 0 && candidate_better_count == 0)
4830 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4832 if (!are_equivalent) {
4833 while (j < args_count && !args [j++].IsDefaultArgument) ;
4836 // A candidate with no default parameters is still better when there
4837 // is no better expression conversion and does not have more parameters
4839 if (candidate_pd.Count < best_pd.Count) {
4840 if (candidate_params)
4843 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4846 if (best_pd.FixedParameters [j].HasDefaultValue)
4849 } else if (candidate_pd.Count == best_pd.Count) {
4850 if (candidate_params)
4853 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4856 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4864 // If candidate is applicable in its normal form and best has a params array and is applicable
4865 // only in its expanded form, then candidate is better
4867 if (candidate_params != best_params)
4868 return !candidate_params;
4871 // We have not reached end of parameters list due to params or used default parameters
4873 bool defaults_ambiguity = false;
4874 while (j < candidate_pd.Count && j < best_pd.Count) {
4875 var cand_param = candidate_pd.FixedParameters [j];
4876 var best_param = best_pd.FixedParameters [j];
4878 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4879 return cand_param.HasDefaultValue;
4881 defaults_ambiguity = true;
4882 if (candidate_pd.Count == best_pd.Count) {
4886 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4887 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4889 if (cand_param.HasDefaultValue) {
4898 // Neither is better when not all arguments are provided
4900 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4901 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4902 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4907 if (candidate_pd.Count != best_pd.Count) {
4908 if (defaults_ambiguity && best_pd.Count - 1 == j)
4909 return best_pd.HasParams;
4911 return candidate_pd.Count < best_pd.Count;
4915 // One is a non-generic method and second is a generic method, then non-generic is better
4917 if (best.IsGeneric != candidate.IsGeneric)
4918 return best.IsGeneric;
4921 // Both methods have the same number of parameters, and the parameters have equal types
4922 // Pick the "more specific" signature using rules over original (non-inflated) types
4924 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4925 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4927 bool specific_at_least_once = false;
4928 for (j = 0; j < args_count; ++j) {
4929 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4931 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4932 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4934 ct = candidate_def_pd.Types[j];
4935 bt = best_def_pd.Types[j];
4940 TypeSpec specific = MoreSpecific (ct, bt);
4944 specific_at_least_once = true;
4947 if (specific_at_least_once)
4953 static bool CheckInflatedArguments (MethodSpec ms)
4955 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4958 // Setup constraint checker for probing only
4959 ConstraintChecker cc = new ConstraintChecker (null);
4961 var mp = ms.Parameters.Types;
4962 for (int i = 0; i < mp.Length; ++i) {
4963 var type = mp[i] as InflatedTypeSpec;
4967 var targs = type.TypeArguments;
4968 if (targs.Length == 0)
4971 // TODO: Checking inflated MVAR arguments should be enough
4972 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4979 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4981 rc.Report.Error (1729, loc,
4982 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4983 type.GetSignatureForError (), argCount.ToString ());
4987 // Determines if the candidate method is applicable to the given set of arguments
4988 // There could be two different set of parameters for same candidate where one
4989 // is the closest override for default values and named arguments checks and second
4990 // one being the virtual base for the parameter types and modifiers.
4992 // A return value rates candidate method compatibility,
4994 // 0 = the best, int.MaxValue = the worst
4996 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)
4999 // Each step has allocated 10 values, it can overflow for
5000 // more than 10 arguments but that's ok as it's used for
5001 // better error reporting only
5003 const int ArgumentCountMismatch = 1000000000;
5004 const int NamedArgumentsMismatch = 100000000;
5005 const int DefaultArgumentMismatch = 10000000;
5006 const int UnexpectedTypeArguments = 1000000;
5007 const int TypeArgumentsMismatch = 100000;
5008 const int InflatedTypesMismatch = 10000;
5010 // Parameters of most-derived type used mainly for named and optional parameters
5011 var pd = pm.Parameters;
5013 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
5014 // params modifier instead of most-derived type
5015 var cpd = ((IParametersMember) candidate).Parameters;
5016 int param_count = pd.Count;
5017 int optional_count = 0;
5019 Arguments orig_args = arguments;
5021 if (arg_count != param_count) {
5023 // No arguments expansion when doing exact match for delegates
5025 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5026 for (int i = 0; i < pd.Count; ++i) {
5027 if (pd.FixedParameters[i].HasDefaultValue) {
5028 optional_count = pd.Count - i;
5034 if (optional_count != 0) {
5035 // Readjust expected number when params used
5036 if (cpd.HasParams) {
5038 if (arg_count < param_count)
5040 } else if (arg_count > param_count) {
5041 int args_gap = System.Math.Abs (arg_count - param_count);
5042 return ArgumentCountMismatch + args_gap;
5043 } else if (arg_count < param_count - optional_count) {
5044 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5045 return ArgumentCountMismatch + args_gap;
5047 } else if (arg_count != param_count) {
5048 int args_gap = System.Math.Abs (arg_count - param_count);
5050 return ArgumentCountMismatch + args_gap;
5051 if (arg_count < param_count - 1)
5052 return ArgumentCountMismatch + args_gap;
5055 // Resize to fit optional arguments
5056 if (optional_count != 0) {
5057 if (arguments == null) {
5058 arguments = new Arguments (optional_count);
5060 // Have to create a new container, so the next run can do same
5061 var resized = new Arguments (param_count);
5062 resized.AddRange (arguments);
5063 arguments = resized;
5066 for (int i = arg_count; i < param_count; ++i)
5067 arguments.Add (null);
5071 if (arg_count > 0) {
5073 // Shuffle named arguments to the right positions if there are any
5075 if (arguments[arg_count - 1] is NamedArgument) {
5076 arg_count = arguments.Count;
5078 for (int i = 0; i < arg_count; ++i) {
5079 bool arg_moved = false;
5081 NamedArgument na = arguments[i] as NamedArgument;
5085 int index = pd.GetParameterIndexByName (na.Name);
5087 // Named parameter not found
5089 return NamedArgumentsMismatch - i;
5091 // already reordered
5096 if (index >= param_count) {
5097 // When using parameters which should not be available to the user
5098 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5101 arguments.Add (null);
5105 if (index == arg_count)
5106 return NamedArgumentsMismatch - i - 1;
5108 temp = arguments [index];
5110 // The slot has been taken by positional argument
5111 if (temp != null && !(temp is NamedArgument))
5112 return NamedArgumentsMismatch - i - 1;
5116 arguments = arguments.MarkOrderedArgument (na);
5120 if (arguments == orig_args) {
5121 arguments = new Arguments (orig_args.Count);
5122 arguments.AddRange (orig_args);
5125 arguments[index] = arguments[i];
5126 arguments[i] = temp;
5133 arg_count = arguments.Count;
5135 } else if (arguments != null) {
5136 arg_count = arguments.Count;
5140 // Don't do any expensive checks when the candidate cannot succeed
5142 if (arg_count != param_count && !cpd.HasParams)
5143 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5145 var dep = candidate.GetMissingDependencies ();
5147 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5152 // 1. Handle generic method using type arguments when specified or type inference
5155 var ms = candidate as MethodSpec;
5156 if (ms != null && ms.IsGeneric) {
5157 if (type_arguments != null) {
5158 var g_args_count = ms.Arity;
5159 if (g_args_count != type_arguments.Count)
5160 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5162 if (type_arguments.Arguments != null)
5163 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5166 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5167 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5168 // candidate was found use the set to report more details about what was wrong with lambda body.
5169 // The general idea is to distinguish between code errors and errors caused by
5170 // trial-and-error type inference
5172 if (lambda_conv_msgs == null) {
5173 for (int i = 0; i < arg_count; i++) {
5174 Argument a = arguments[i];
5178 var am = a.Expr as AnonymousMethodExpression;
5180 if (lambda_conv_msgs == null)
5181 lambda_conv_msgs = new SessionReportPrinter ();
5183 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5188 var ti = new TypeInference (arguments);
5189 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5192 return TypeArgumentsMismatch - ti.InferenceScore;
5195 // Clear any error messages when the result was success
5197 if (lambda_conv_msgs != null)
5198 lambda_conv_msgs.ClearSession ();
5200 if (i_args.Length != 0) {
5202 for (int i = 0; i < i_args.Length; ++i) {
5203 var ta = i_args [i];
5204 if (!ta.IsAccessible (ec))
5205 return TypeArgumentsMismatch - i;
5209 ms = ms.MakeGenericMethod (ec, i_args);
5214 // Type arguments constraints have to match for the method to be applicable
5216 if (!CheckInflatedArguments (ms)) {
5218 return InflatedTypesMismatch;
5222 // We have a generic return type and at same time the method is override which
5223 // means we have to also inflate override return type in case the candidate is
5224 // best candidate and override return type is different to base return type.
5226 // virtual Foo<T, object> with override Foo<T, dynamic>
5228 if (candidate != pm) {
5229 MethodSpec override_ms = (MethodSpec) pm;
5230 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5231 returnType = inflator.Inflate (returnType);
5233 returnType = ms.ReturnType;
5240 if (type_arguments != null)
5241 return UnexpectedTypeArguments;
5247 // 2. Each argument has to be implicitly convertible to method parameter
5249 Parameter.Modifier p_mod = 0;
5252 for (int i = 0; i < arg_count; i++) {
5253 Argument a = arguments[i];
5255 var fp = pd.FixedParameters[i];
5256 if (!fp.HasDefaultValue) {
5257 arguments = orig_args;
5258 return arg_count * 2 + 2;
5262 // Get the default value expression, we can use the same expression
5263 // if the type matches
5265 Expression e = fp.DefaultValue;
5267 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5269 // Restore for possible error reporting
5270 for (int ii = i; ii < arg_count; ++ii)
5271 arguments.RemoveAt (i);
5273 return (arg_count - i) * 2 + 1;
5277 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5279 // LAMESPEC: Attributes can be mixed together with build-in priority
5281 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5282 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5283 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5284 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5285 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5286 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5290 arguments[i] = new Argument (e, Argument.AType.Default);
5294 if (p_mod != Parameter.Modifier.PARAMS) {
5295 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5297 } else if (!params_expanded_form) {
5298 params_expanded_form = true;
5299 pt = ((ElementTypeSpec) pt).Element;
5305 if (!params_expanded_form) {
5306 if (a.IsExtensionType) {
5307 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5312 score = IsArgumentCompatible (ec, a, p_mod, pt);
5315 dynamicArgument = true;
5320 // It can be applicable in expanded form (when not doing exact match like for delegates)
5322 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5323 if (!params_expanded_form) {
5324 pt = ((ElementTypeSpec) pt).Element;
5328 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5331 params_expanded_form = true;
5332 dynamicArgument = true;
5333 } else if (score == 0 || arg_count > pd.Count) {
5334 params_expanded_form = true;
5339 if (params_expanded_form)
5341 return (arg_count - i) * 2 + score;
5346 // Restore original arguments for dynamic binder to keep the intention of original source code
5348 if (dynamicArgument)
5349 arguments = orig_args;
5354 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5356 if (e is Constant && e.Type == ptype)
5360 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5362 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5363 e = new MemberAccess (new MemberAccess (new MemberAccess (
5364 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5365 } else if (e is Constant) {
5367 // Handles int to int? conversions, DefaultParameterValue check
5369 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5373 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5376 return e.Resolve (ec);
5380 // Tests argument compatibility with the parameter
5381 // The possible return values are
5383 // 1 - modifier mismatch
5384 // 2 - type mismatch
5385 // -1 - dynamic binding required
5387 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5390 // Types have to be identical when ref or out modifer
5391 // is used and argument is not of dynamic type
5393 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5394 var arg_type = argument.Type;
5396 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5398 // Using dynamic for ref/out parameter can still succeed at runtime
5400 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5406 if (arg_type != parameter) {
5407 if (arg_type == InternalType.VarOutType)
5411 // Do full equality check after quick path
5413 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5415 // Using dynamic for ref/out parameter can still succeed at runtime
5417 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5425 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5429 // Use implicit conversion in all modes to return same candidates when the expression
5430 // is used as argument or delegate conversion
5432 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5433 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5440 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5442 if (p.IsGenericParameter != q.IsGenericParameter)
5443 return p.IsGenericParameter ? q : p;
5445 var ac_p = p as ArrayContainer;
5447 var ac_q = q as ArrayContainer;
5451 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5452 if (specific == ac_p.Element)
5454 if (specific == ac_q.Element)
5460 if (p.IsGeneric && q.IsGeneric) {
5461 var pargs = p.TypeArguments;
5462 var qargs = q.TypeArguments;
5464 bool p_specific_at_least_once = false;
5465 bool q_specific_at_least_once = false;
5467 for (int i = 0; i < pargs.Length; i++) {
5468 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5469 if (specific == pargs [i])
5470 p_specific_at_least_once = true;
5471 if (specific == qargs [i])
5472 q_specific_at_least_once = true;
5475 if (p_specific_at_least_once && !q_specific_at_least_once)
5477 if (!p_specific_at_least_once && q_specific_at_least_once)
5485 // Find the best method from candidate list
5487 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5489 List<AmbiguousCandidate> ambiguous_candidates = null;
5491 MemberSpec best_candidate;
5492 Arguments best_candidate_args = null;
5493 bool best_candidate_params = false;
5494 bool best_candidate_dynamic = false;
5495 int best_candidate_rate;
5496 IParametersMember best_parameter_member = null;
5498 int args_count = args != null ? args.Count : 0;
5500 Arguments candidate_args = args;
5501 bool error_mode = false;
5502 MemberSpec invocable_member = null;
5503 int applicable_candidates = 0;
5506 best_candidate = null;
5507 best_candidate_rate = int.MaxValue;
5509 var type_members = members;
5511 for (int i = 0; i < type_members.Count; ++i) {
5512 var member = type_members[i];
5515 // Methods in a base class are not candidates if any method in a derived
5516 // class is applicable
5518 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5522 if (!member.IsAccessible (rc))
5525 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5528 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5529 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5534 IParametersMember pm = member as IParametersMember;
5537 // Will use it later to report ambiguity between best method and invocable member
5539 if (Invocation.IsMemberInvocable (member))
5540 invocable_member = member;
5546 // Overload resolution is looking for base member but using parameter names
5547 // and default values from the closest member. That means to do expensive lookup
5548 // for the closest override for virtual or abstract members
5550 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5551 var override_params = base_provider.GetOverrideMemberParameters (member);
5552 if (override_params != null)
5553 pm = override_params;
5557 // Check if the member candidate is applicable
5559 bool params_expanded_form = false;
5560 bool dynamic_argument = false;
5561 TypeSpec rt = pm.MemberType;
5562 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5564 if (lambda_conv_msgs != null)
5565 lambda_conv_msgs.EndSession ();
5568 // How does it score compare to others
5570 if (candidate_rate < best_candidate_rate) {
5572 // Fatal error (missing dependency), cannot continue
5573 if (candidate_rate < 0)
5576 applicable_candidates = 1;
5577 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5578 // Only parameterless methods are considered
5580 best_candidate_rate = candidate_rate;
5581 best_candidate = member;
5582 best_candidate_args = candidate_args;
5583 best_candidate_params = params_expanded_form;
5584 best_candidate_dynamic = dynamic_argument;
5585 best_parameter_member = pm;
5586 best_candidate_return_type = rt;
5588 } else if (candidate_rate == 0) {
5590 // The member look is done per type for most operations but sometimes
5591 // it's not possible like for binary operators overload because they
5592 // are unioned between 2 sides
5594 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5595 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5599 ++applicable_candidates;
5601 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5603 // We pack all interface members into top level type which makes the overload resolution
5604 // more complicated for interfaces. We compensate it by removing methods with same
5605 // signature when building the cache hence this path should not really be hit often
5608 // interface IA { void Foo (int arg); }
5609 // interface IB : IA { void Foo (params int[] args); }
5611 // IB::Foo is the best overload when calling IB.Foo (1)
5614 if (ambiguous_candidates != null) {
5615 foreach (var amb_cand in ambiguous_candidates) {
5616 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5625 ambiguous_candidates = null;
5628 // Is the new candidate better
5629 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5633 best_candidate = member;
5634 best_candidate_args = candidate_args;
5635 best_candidate_params = params_expanded_form;
5636 best_candidate_dynamic = dynamic_argument;
5637 best_parameter_member = pm;
5638 best_candidate_return_type = rt;
5640 // It's not better but any other found later could be but we are not sure yet
5641 if (ambiguous_candidates == null)
5642 ambiguous_candidates = new List<AmbiguousCandidate> ();
5644 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5648 // Restore expanded arguments
5649 candidate_args = args;
5651 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5654 // We've found exact match
5656 if (best_candidate_rate == 0)
5660 // Try extension methods lookup when no ordinary method match was found and provider enables it
5663 var emg = base_provider.LookupExtensionMethod (rc);
5665 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5667 best_candidate_extension_group = emg;
5668 return (T) (MemberSpec) emg.BestCandidate;
5673 // Don't run expensive error reporting mode for probing
5680 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5683 lambda_conv_msgs = null;
5688 // No best member match found, report an error
5690 if (best_candidate_rate != 0 || error_mode) {
5691 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5695 if (best_candidate_dynamic) {
5696 if (args[0].IsExtensionType) {
5697 rc.Report.Error (1973, loc,
5698 "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",
5699 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5703 // Check type constraints only when explicit type arguments are used
5705 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5706 MethodSpec bc = best_candidate as MethodSpec;
5707 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5708 ConstraintChecker cc = new ConstraintChecker (rc);
5709 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5713 BestCandidateIsDynamic = true;
5718 // These flags indicates we are running delegate probing conversion. No need to
5719 // do more expensive checks
5721 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5722 return (T) best_candidate;
5724 if (ambiguous_candidates != null) {
5726 // Now check that there are no ambiguities i.e the selected method
5727 // should be better than all the others
5729 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5730 var candidate = ambiguous_candidates [ix];
5732 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5733 var ambiguous = candidate.Member;
5734 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5735 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5736 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5737 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5738 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5741 return (T) best_candidate;
5746 if (invocable_member != null && !IsProbingOnly) {
5747 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5748 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5749 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5750 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5754 // And now check if the arguments are all
5755 // compatible, perform conversions if
5756 // necessary etc. and return if everything is
5759 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5762 if (best_candidate == null)
5766 // Don't run possibly expensive checks in probing mode
5768 if (!IsProbingOnly && !rc.IsInProbingMode) {
5770 // Check ObsoleteAttribute on the best method
5772 best_candidate.CheckObsoleteness (rc, loc);
5774 best_candidate.MemberDefinition.SetIsUsed ();
5777 args = best_candidate_args;
5778 return (T) best_candidate;
5781 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5783 return ResolveMember<MethodSpec> (rc, ref args);
5786 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5787 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5789 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5792 if (a.Type == InternalType.ErrorType)
5795 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5796 ec.Report.SymbolRelatedToPreviousError (method);
5797 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5798 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5799 TypeManager.CSharpSignature (method));
5802 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5803 TypeManager.CSharpSignature (method));
5804 } else if (IsDelegateInvoke) {
5805 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5806 DelegateType.GetSignatureForError ());
5808 ec.Report.SymbolRelatedToPreviousError (method);
5809 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5810 method.GetSignatureForError ());
5813 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5815 string index = (idx + 1).ToString ();
5816 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5817 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5818 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5819 index, Parameter.GetModifierSignature (a.Modifier));
5821 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5822 index, Parameter.GetModifierSignature (mod));
5824 string p1 = a.GetSignatureForError ();
5825 string p2 = paramType.GetSignatureForError ();
5828 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5829 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5832 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5833 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5834 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5837 ec.Report.Error (1503, a.Expr.Location,
5838 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5843 // We have failed to find exact match so we return error info about the closest match
5845 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5847 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5848 int arg_count = args == null ? 0 : args.Count;
5850 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5851 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5852 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5856 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5861 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5862 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5863 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5867 // For candidates which match on parameters count report more details about incorrect arguments
5870 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5871 // Reject any inaccessible member
5872 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5873 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5874 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5878 var ms = best_candidate as MethodSpec;
5879 if (ms != null && ms.IsGeneric) {
5880 bool constr_ok = true;
5881 if (ms.TypeArguments != null)
5882 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5884 if (ta_count == 0 && ms.TypeArguments == null) {
5885 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5889 rc.Report.Error (411, loc,
5890 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5891 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5898 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5904 // We failed to find any method with correct argument count, report best candidate
5906 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5909 if (best_candidate.Kind == MemberKind.Constructor) {
5910 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5911 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5912 } else if (IsDelegateInvoke) {
5913 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5914 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5915 DelegateType.GetSignatureForError (), arg_count.ToString ());
5917 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5918 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5919 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5920 name, arg_count.ToString ());
5924 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5926 var p = ((IParametersMember)best_candidate).Parameters;
5931 for (int i = p.Count - 1; i != 0; --i) {
5932 var fp = p.FixedParameters [i];
5933 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5943 foreach (var arg in args) {
5944 var na = arg as NamedArgument;
5948 if (na.Name == name) {
5957 return args.Count + 1 == pm.Parameters.Count;
5960 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5962 var pd = pm.Parameters;
5963 var cpd = ((IParametersMember) member).Parameters;
5964 var ptypes = cpd.Types;
5966 Parameter.Modifier p_mod = 0;
5968 int a_idx = 0, a_pos = 0;
5970 ArrayInitializer params_initializers = null;
5971 bool has_unsafe_arg = pm.MemberType.IsPointer;
5972 int arg_count = args == null ? 0 : args.Count;
5974 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5979 if (p_mod != Parameter.Modifier.PARAMS) {
5980 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5982 has_unsafe_arg |= pt.IsPointer;
5984 if (p_mod == Parameter.Modifier.PARAMS) {
5985 if (chose_params_expanded) {
5986 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5987 pt = TypeManager.GetElementType (pt);
5993 // Types have to be identical when ref or out modifer is used
5995 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5996 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5999 var arg_type = a.Type;
6003 if (arg_type == InternalType.VarOutType) {
6005 // Set underlying variable type based on parameter type
6007 ((DeclarationExpression)a.Expr).Variable.Type = pt;
6011 if (!TypeSpecComparer.IsEqual (arg_type, pt))
6015 NamedArgument na = a as NamedArgument;
6017 int name_index = pd.GetParameterIndexByName (na.Name);
6018 if (name_index < 0 || name_index >= pd.Count) {
6019 if (IsDelegateInvoke) {
6020 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6021 ec.Report.Error (1746, na.Location,
6022 "The delegate `{0}' does not contain a parameter named `{1}'",
6023 DelegateType.GetSignatureForError (), na.Name);
6025 ec.Report.SymbolRelatedToPreviousError (member);
6026 ec.Report.Error (1739, na.Location,
6027 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6028 TypeManager.CSharpSignature (member), na.Name);
6030 } else if (args[name_index] != a && args[name_index] != null) {
6031 if (IsDelegateInvoke)
6032 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6034 ec.Report.SymbolRelatedToPreviousError (member);
6036 ec.Report.Error (1744, na.Location,
6037 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6042 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6045 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6046 if (a.IsExtensionType) {
6047 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6048 // CS1061 but that still better than confusing CS0123
6049 var ma = new MemberAccess (a.Expr, member.Name, loc);
6050 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6052 custom_errors.NoArgumentMatch (ec, member);
6058 if (a.IsExtensionType) {
6059 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6062 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6064 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6067 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6074 // Convert params arguments to an array initializer
6076 if (params_initializers != null) {
6077 // we choose to use 'a.Expr' rather than 'conv' so that
6078 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6079 params_initializers.Add (a.Expr);
6080 args.RemoveAt (a_idx--);
6086 // Update the argument with the implicit conversion
6090 if (a_idx != arg_count) {
6092 // Convert all var out argument to error type for less confusing error reporting
6093 // when no matching overload is found
6095 for (; a_idx < arg_count; a_idx++) {
6096 var arg = args [a_idx];
6100 if (arg.Type == InternalType.VarOutType) {
6101 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6105 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6110 // Fill not provided arguments required by params modifier
6112 if (params_initializers == null && arg_count + 1 == pd.Count) {
6114 args = new Arguments (1);
6116 pt = ptypes[pd.Count - 1];
6117 pt = TypeManager.GetElementType (pt);
6118 has_unsafe_arg |= pt.IsPointer;
6119 params_initializers = new ArrayInitializer (0, loc);
6123 // Append an array argument with all params arguments
6125 if (params_initializers != null) {
6126 args.Add (new Argument (
6127 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6131 if (has_unsafe_arg) {
6132 if (ec.CurrentIterator != null) {
6133 Expression.UnsafeInsideIteratorError (ec, loc);
6134 } else if (!ec.IsUnsafe) {
6135 Expression.UnsafeError (ec, loc);
6140 // We could infer inaccesible type arguments
6142 if (type_arguments == null && member.IsGeneric) {
6143 var ms = (MethodSpec) member;
6144 foreach (var ta in ms.TypeArguments) {
6145 if (!ta.IsAccessible (ec)) {
6146 ec.Report.SymbolRelatedToPreviousError (ta);
6147 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6157 public class ConstantExpr : MemberExpr
6159 readonly ConstSpec constant;
6161 public ConstantExpr (ConstSpec constant, Location loc)
6163 this.constant = constant;
6167 public override string Name {
6168 get { throw new NotImplementedException (); }
6171 public override string KindName {
6172 get { return "constant"; }
6175 public override bool IsInstance {
6176 get { return !IsStatic; }
6179 public override bool IsStatic {
6180 get { return true; }
6183 protected override TypeSpec DeclaringType {
6184 get { return constant.DeclaringType; }
6187 public override Expression CreateExpressionTree (ResolveContext ec)
6189 throw new NotSupportedException ("ET");
6192 protected override Expression DoResolve (ResolveContext rc)
6194 ResolveInstanceExpression (rc, null);
6195 DoBestMemberChecks (rc, constant);
6197 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6198 eclass = ExprClass.Value;
6199 type = constant.MemberType;
6203 var c = constant.GetConstant (rc);
6205 // Creates reference expression to the constant value
6206 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6209 public override void Emit (EmitContext ec)
6211 throw new NotSupportedException ();
6214 public override string GetSignatureForError ()
6216 return constant.GetSignatureForError ();
6219 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6221 constant.CheckObsoleteness (rc, expr.Location);
6224 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6226 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6231 // Fully resolved expression that references a Field
6233 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6235 protected FieldSpec spec;
6236 VariableInfo variable_info;
6238 LocalTemporary temp;
6241 protected FieldExpr (Location l)
6246 public FieldExpr (FieldSpec spec, Location loc)
6251 type = spec.MemberType;
6254 public FieldExpr (FieldBase fi, Location l)
6261 public override string Name {
6267 public bool IsHoisted {
6269 IVariableReference hv = InstanceExpression as IVariableReference;
6270 return hv != null && hv.IsHoisted;
6274 public override bool IsInstance {
6276 return !spec.IsStatic;
6280 public override bool IsStatic {
6282 return spec.IsStatic;
6286 public override string KindName {
6287 get { return "field"; }
6290 public FieldSpec Spec {
6296 protected override TypeSpec DeclaringType {
6298 return spec.DeclaringType;
6302 public VariableInfo VariableInfo {
6304 return variable_info;
6310 public override string GetSignatureForError ()
6312 return spec.GetSignatureForError ();
6315 public bool IsMarshalByRefAccess (ResolveContext rc)
6317 // Checks possible ldflda of field access expression
6318 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6319 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6320 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6323 public void SetHasAddressTaken ()
6325 IVariableReference vr = InstanceExpression as IVariableReference;
6327 vr.SetHasAddressTaken ();
6331 protected override void CloneTo (CloneContext clonectx, Expression target)
6333 var t = (FieldExpr) target;
6335 if (InstanceExpression != null)
6336 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6339 public override Expression CreateExpressionTree (ResolveContext ec)
6341 if (ConditionalAccess) {
6342 Error_NullShortCircuitInsideExpressionTree (ec);
6345 return CreateExpressionTree (ec, true);
6348 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6351 Expression instance;
6353 if (InstanceExpression == null) {
6354 instance = new NullLiteral (loc);
6355 } else if (convertInstance) {
6356 instance = InstanceExpression.CreateExpressionTree (ec);
6358 args = new Arguments (1);
6359 args.Add (new Argument (InstanceExpression));
6360 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6363 args = Arguments.CreateForExpressionTree (ec, null,
6365 CreateTypeOfExpression ());
6367 return CreateExpressionFactoryCall (ec, "Field", args);
6370 public Expression CreateTypeOfExpression ()
6372 return new TypeOfField (spec, loc);
6375 protected override Expression DoResolve (ResolveContext ec)
6377 spec.MemberDefinition.SetIsUsed ();
6379 return DoResolve (ec, null);
6382 Expression DoResolve (ResolveContext ec, Expression rhs)
6384 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6387 ResolveConditionalAccessReceiver (ec);
6389 if (ResolveInstanceExpression (ec, rhs)) {
6390 // Resolve the field's instance expression while flow analysis is turned
6391 // off: when accessing a field "a.b", we must check whether the field
6392 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6394 if (lvalue_instance) {
6395 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6397 Expression right_side =
6398 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6400 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6402 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6405 if (InstanceExpression == null)
6409 DoBestMemberChecks (ec, spec);
6411 if (conditional_access_receiver)
6412 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6415 var fb = spec as FixedFieldSpec;
6416 IVariableReference var = InstanceExpression as IVariableReference;
6419 IFixedExpression fe = InstanceExpression as IFixedExpression;
6420 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6421 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6424 if (InstanceExpression.eclass != ExprClass.Variable) {
6425 ec.Report.SymbolRelatedToPreviousError (spec);
6426 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6427 TypeManager.GetFullNameSignature (spec));
6428 } else if (var != null && var.IsHoisted) {
6429 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6432 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6436 // Set flow-analysis variable info for struct member access. It will be check later
6437 // for precise error reporting
6439 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6440 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6443 if (conditional_access_receiver)
6444 type = LiftMemberType (ec, type);
6446 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6447 return Constant.CreateConstantFromValue (type, null, loc);
6449 eclass = ExprClass.Variable;
6453 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6455 spec.CheckObsoleteness (rc, expr.Location);
6458 public void SetFieldAssigned (FlowAnalysisContext fc)
6463 bool lvalue_instance = spec.DeclaringType.IsStruct;
6464 if (lvalue_instance) {
6465 var var = InstanceExpression as IVariableReference;
6466 if (var != null && var.VariableInfo != null) {
6467 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6471 var fe = InstanceExpression as FieldExpr;
6473 Expression instance;
6476 instance = fe.InstanceExpression;
6477 var fe_instance = instance as FieldExpr;
6478 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6479 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6480 var var = InstanceExpression as IVariableReference;
6481 if (var != null && var.VariableInfo == null) {
6482 var var_inst = instance as IVariableReference;
6483 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6484 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6488 if (fe_instance != null) {
6497 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6498 instance.FlowAnalysis (fc);
6500 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6501 InstanceExpression.FlowAnalysis (fc);
6505 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6507 // The return value is always null. Returning a value simplifies calling code.
6509 if (right_side == EmptyExpression.OutAccess) {
6511 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6512 GetSignatureForError ());
6514 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6515 GetSignatureForError ());
6521 if (right_side == EmptyExpression.LValueMemberAccess) {
6522 // Already reported as CS1648/CS1650
6526 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6528 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6529 GetSignatureForError ());
6531 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6532 GetSignatureForError ());
6538 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6539 GetSignatureForError ());
6541 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6542 GetSignatureForError ());
6548 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6550 if (HasConditionalAccess ())
6551 Error_NullPropagatingLValue (ec);
6553 if (spec is FixedFieldSpec) {
6554 // It could be much better error message but we want to be error compatible
6555 Error_ValueAssignment (ec, right_side);
6558 Expression e = DoResolve (ec, right_side);
6563 spec.MemberDefinition.SetIsAssigned ();
6565 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6566 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6567 ec.Report.Warning (420, 1, loc,
6568 "`{0}': A volatile field references will not be treated as volatile",
6569 spec.GetSignatureForError ());
6572 if (spec.IsReadOnly) {
6573 // InitOnly fields can only be assigned in constructors or initializers
6574 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6575 return Error_AssignToReadonly (ec, right_side);
6577 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6579 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6580 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6581 return Error_AssignToReadonly (ec, right_side);
6582 // static InitOnly fields cannot be assigned-to in an instance constructor
6583 if (IsStatic && !ec.IsStatic)
6584 return Error_AssignToReadonly (ec, right_side);
6585 // instance constructors can't modify InitOnly fields of other instances of the same type
6586 if (!IsStatic && !(InstanceExpression is This))
6587 return Error_AssignToReadonly (ec, right_side);
6591 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6592 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6593 ec.Report.Warning (197, 1, loc,
6594 "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",
6595 GetSignatureForError ());
6598 eclass = ExprClass.Variable;
6602 public override void FlowAnalysis (FlowAnalysisContext fc)
6604 var var = InstanceExpression as IVariableReference;
6606 var vi = var.VariableInfo;
6607 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6608 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6612 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6613 var le = SkipLeftValueTypeAccess (InstanceExpression);
6615 le.FlowAnalysis (fc);
6621 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6623 base.FlowAnalysis (fc);
6625 if (conditional_access_receiver)
6626 fc.DefiniteAssignment = da;
6629 static Expression SkipLeftValueTypeAccess (Expression expr)
6631 if (!TypeSpec.IsValueType (expr.Type))
6634 if (expr is VariableReference)
6637 var fe = expr as FieldExpr;
6641 if (fe.InstanceExpression == null)
6644 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6647 public override int GetHashCode ()
6649 return spec.GetHashCode ();
6652 public bool IsFixed {
6655 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6657 IVariableReference variable = InstanceExpression as IVariableReference;
6658 if (variable != null)
6659 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6661 IFixedExpression fe = InstanceExpression as IFixedExpression;
6662 return fe != null && fe.IsFixed;
6666 public override bool Equals (object obj)
6668 FieldExpr fe = obj as FieldExpr;
6672 if (spec != fe.spec)
6675 if (InstanceExpression == null || fe.InstanceExpression == null)
6678 return InstanceExpression.Equals (fe.InstanceExpression);
6681 public void Emit (EmitContext ec, bool leave_copy)
6683 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6687 ec.Emit (OpCodes.Volatile);
6689 ec.Emit (OpCodes.Ldsfld, spec);
6691 var ca = ec.ConditionalAccess;
6694 if (conditional_access_receiver)
6695 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6697 EmitInstance (ec, false);
6700 // Optimization for build-in types
6701 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6702 ec.EmitLoadFromPtr (type);
6704 var ff = spec as FixedFieldSpec;
6706 ec.Emit (OpCodes.Ldflda, spec);
6707 ec.Emit (OpCodes.Ldflda, ff.Element);
6710 ec.Emit (OpCodes.Volatile);
6712 ec.Emit (OpCodes.Ldfld, spec);
6716 if (conditional_access_receiver) {
6717 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6718 ec.ConditionalAccess = ca;
6723 ec.Emit (OpCodes.Dup);
6725 temp = new LocalTemporary (this.Type);
6731 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6733 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6734 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6739 if (ConditionalAccess)
6740 throw new NotImplementedException ("null operator assignment");
6742 if (has_await_source)
6743 source = source.EmitToField (ec);
6745 EmitInstance (ec, prepared);
6750 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6751 ec.Emit (OpCodes.Dup);
6753 temp = new LocalTemporary (this.Type);
6758 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6759 ec.Emit (OpCodes.Volatile);
6761 spec.MemberDefinition.SetIsAssigned ();
6764 ec.Emit (OpCodes.Stsfld, spec);
6766 ec.Emit (OpCodes.Stfld, spec);
6768 if (ec.NotifyEvaluatorOnStore) {
6770 throw new NotImplementedException ("instance field write");
6773 ec.Emit (OpCodes.Dup);
6775 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6786 // Emits store to field with prepared values on stack
6788 public void EmitAssignFromStack (EmitContext ec)
6791 ec.Emit (OpCodes.Stsfld, spec);
6793 ec.Emit (OpCodes.Stfld, spec);
6797 public override void Emit (EmitContext ec)
6802 public override void EmitSideEffect (EmitContext ec)
6804 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6806 if (is_volatile) // || is_marshal_by_ref ())
6807 base.EmitSideEffect (ec);
6810 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6812 if ((mode & AddressOp.Store) != 0)
6813 spec.MemberDefinition.SetIsAssigned ();
6814 if ((mode & AddressOp.Load) != 0)
6815 spec.MemberDefinition.SetIsUsed ();
6818 // Handle initonly fields specially: make a copy and then
6819 // get the address of the copy.
6822 if (spec.IsReadOnly){
6824 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6836 var temp = ec.GetTemporaryLocal (type);
6837 ec.Emit (OpCodes.Stloc, temp);
6838 ec.Emit (OpCodes.Ldloca, temp);
6844 ec.Emit (OpCodes.Ldsflda, spec);
6847 EmitInstance (ec, false);
6848 ec.Emit (OpCodes.Ldflda, spec);
6852 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6854 return MakeExpression (ctx);
6857 public override SLE.Expression MakeExpression (BuilderContext ctx)
6860 return base.MakeExpression (ctx);
6862 return SLE.Expression.Field (
6863 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6864 spec.GetMetaInfo ());
6868 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6870 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6876 // Expression that evaluates to a Property.
6878 // This is not an LValue because we need to re-write the expression. We
6879 // can not take data from the stack and store it.
6881 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6883 Arguments arguments;
6884 FieldExpr backing_field;
6886 public PropertyExpr (PropertySpec spec, Location l)
6889 best_candidate = spec;
6890 type = spec.MemberType;
6895 protected override Arguments Arguments {
6904 protected override TypeSpec DeclaringType {
6906 return best_candidate.DeclaringType;
6910 public override string Name {
6912 return best_candidate.Name;
6916 public bool IsAutoPropertyAccess {
6918 var prop = best_candidate.MemberDefinition as Property;
6919 return prop != null && prop.BackingField != null;
6923 public override bool IsInstance {
6929 public override bool IsStatic {
6931 return best_candidate.IsStatic;
6935 public override string KindName {
6936 get { return "property"; }
6939 public PropertySpec PropertyInfo {
6941 return best_candidate;
6947 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6949 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6952 var args_count = arguments == null ? 0 : arguments.Count;
6953 if (args_count != body.Parameters.Count && args_count == 0)
6956 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6957 mg.InstanceExpression = InstanceExpression;
6962 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6964 return new PropertyExpr (spec, loc) {
6970 public override Expression CreateExpressionTree (ResolveContext ec)
6972 if (ConditionalAccess) {
6973 Error_NullShortCircuitInsideExpressionTree (ec);
6977 if (IsSingleDimensionalArrayLength ()) {
6978 args = new Arguments (1);
6979 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6980 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6983 args = new Arguments (2);
6984 if (InstanceExpression == null)
6985 args.Add (new Argument (new NullLiteral (loc)));
6987 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6988 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6989 return CreateExpressionFactoryCall (ec, "Property", args);
6992 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6994 DoResolveLValue (rc, null);
6995 return new TypeOfMethod (Setter, loc);
6998 public override string GetSignatureForError ()
7000 return best_candidate.GetSignatureForError ();
7003 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
7006 return base.MakeExpression (ctx);
7008 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
7012 public override SLE.Expression MakeExpression (BuilderContext ctx)
7015 return base.MakeExpression (ctx);
7017 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
7021 void Error_PropertyNotValid (ResolveContext ec)
7023 ec.Report.SymbolRelatedToPreviousError (best_candidate);
7024 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
7025 GetSignatureForError ());
7028 bool IsSingleDimensionalArrayLength ()
7030 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7033 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7034 return ac != null && ac.Rank == 1;
7037 public override void Emit (EmitContext ec, bool leave_copy)
7040 // Special case: length of single dimension array property is turned into ldlen
7042 if (IsSingleDimensionalArrayLength ()) {
7043 if (conditional_access_receiver) {
7044 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7047 EmitInstance (ec, false);
7049 ec.Emit (OpCodes.Ldlen);
7050 ec.Emit (OpCodes.Conv_I4);
7052 if (conditional_access_receiver) {
7053 ec.CloseConditionalAccess (type);
7059 base.Emit (ec, leave_copy);
7062 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7064 if (backing_field != null) {
7065 backing_field.EmitAssign (ec, source, leave_copy, false);
7070 LocalTemporary await_source_arg = null;
7072 if (isCompound && !(source is DynamicExpressionStatement)) {
7073 emitting_compound_assignment = true;
7076 if (has_await_arguments) {
7077 await_source_arg = new LocalTemporary (Type);
7078 await_source_arg.Store (ec);
7080 args = new Arguments (1);
7081 args.Add (new Argument (await_source_arg));
7084 temp = await_source_arg;
7087 has_await_arguments = false;
7092 ec.Emit (OpCodes.Dup);
7093 temp = new LocalTemporary (this.Type);
7098 args = arguments ?? new Arguments (1);
7102 temp = new LocalTemporary (this.Type);
7104 args.Add (new Argument (temp));
7106 args.Add (new Argument (source));
7110 emitting_compound_assignment = false;
7112 var call = new CallEmitter ();
7113 call.InstanceExpression = InstanceExpression;
7115 call.InstanceExpressionOnStack = true;
7117 if (ConditionalAccess) {
7118 call.ConditionalAccess = true;
7122 call.Emit (ec, Setter, args, loc);
7124 call.EmitStatement (ec, Setter, args, loc);
7131 if (await_source_arg != null) {
7132 await_source_arg.Release (ec);
7136 public override void FlowAnalysis (FlowAnalysisContext fc)
7138 var prop = best_candidate.MemberDefinition as Property;
7139 if (prop != null && prop.BackingField != null) {
7140 var var = InstanceExpression as IVariableReference;
7142 var vi = var.VariableInfo;
7143 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7144 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7148 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7153 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7155 base.FlowAnalysis (fc);
7157 if (conditional_access_receiver)
7158 fc.DefiniteAssignment = da;
7161 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7163 eclass = ExprClass.PropertyAccess;
7165 if (best_candidate.IsNotCSharpCompatible) {
7166 Error_PropertyNotValid (rc);
7169 ResolveInstanceExpression (rc, right_side);
7171 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7172 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7173 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7175 type = p.MemberType;
7179 DoBestMemberChecks (rc, best_candidate);
7181 // Handling of com-imported properties with any number of default property parameters
7182 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7183 var p = best_candidate.Get.Parameters;
7184 arguments = new Arguments (p.Count);
7185 for (int i = 0; i < p.Count; ++i) {
7186 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7188 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7189 var p = best_candidate.Set.Parameters;
7190 arguments = new Arguments (p.Count - 1);
7191 for (int i = 0; i < p.Count - 1; ++i) {
7192 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7199 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7201 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7204 var prop = best_candidate.MemberDefinition as Property;
7205 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7206 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7210 prop = (Property)ps.MemberDefinition;
7213 var spec = prop.BackingField;
7217 if (rc.IsStatic != spec.IsStatic)
7220 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7223 backing_field = new FieldExpr (prop.BackingField, loc);
7224 backing_field.ResolveLValue (rc, rhs);
7228 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7230 if (!best_candidate.IsAccessible (rc))
7231 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7233 best_candidate.CheckObsoleteness (rc, expr.Location);
7236 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7238 if (backing_field != null) {
7239 backing_field.SetFieldAssigned (fc);
7243 if (!IsAutoPropertyAccess)
7246 var prop = best_candidate.MemberDefinition as Property;
7247 if (prop != null && prop.BackingField != null) {
7248 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7249 if (lvalue_instance) {
7250 var var = InstanceExpression as IVariableReference;
7251 if (var != null && var.VariableInfo != null) {
7252 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7258 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7260 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7264 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7266 // getter and setter can be different for base calls
7267 MethodSpec getter, setter;
7268 protected T best_candidate;
7270 protected LocalTemporary temp;
7271 protected bool emitting_compound_assignment;
7272 protected bool has_await_arguments;
7274 protected PropertyOrIndexerExpr (Location l)
7281 protected abstract Arguments Arguments { get; set; }
7283 public MethodSpec Getter {
7292 public MethodSpec Setter {
7303 protected override Expression DoResolve (ResolveContext ec)
7305 if (eclass == ExprClass.Unresolved) {
7306 ResolveConditionalAccessReceiver (ec);
7308 var expr = OverloadResolve (ec, null);
7313 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7314 return expr.Resolve (ec);
7317 if (conditional_access_receiver) {
7318 type = LiftMemberType (ec, type);
7322 if (!ResolveGetter (ec))
7328 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7330 if (HasConditionalAccess ())
7331 Error_NullPropagatingLValue (rc);
7333 if (right_side == EmptyExpression.OutAccess) {
7334 // TODO: best_candidate can be null at this point
7335 INamedBlockVariable variable = null;
7336 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7337 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7338 best_candidate.Name);
7340 right_side.DoResolveLValue (rc, this);
7345 if (eclass == ExprClass.Unresolved) {
7346 var expr = OverloadResolve (rc, right_side);
7351 return expr.ResolveLValue (rc, right_side);
7353 ResolveInstanceExpression (rc, right_side);
7356 if (!best_candidate.HasSet) {
7357 if (ResolveAutopropertyAssignment (rc, right_side))
7360 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7361 GetSignatureForError ());
7365 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7366 if (best_candidate.HasDifferentAccessibility) {
7367 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7368 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7369 GetSignatureForError ());
7371 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7372 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7376 if (best_candidate.HasDifferentAccessibility)
7377 CheckProtectedMemberAccess (rc, best_candidate.Set);
7379 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7383 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7385 var ca = ec.ConditionalAccess;
7386 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7388 call.Emit (ec, method, arguments, loc);
7390 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7391 ec.ConditionalAccess = ca;
7395 // Implements the IAssignMethod interface for assignments
7397 public virtual void Emit (EmitContext ec, bool leave_copy)
7399 var call = new CallEmitter ();
7400 call.ConditionalAccess = ConditionalAccess;
7401 call.InstanceExpression = InstanceExpression;
7402 if (has_await_arguments)
7403 call.HasAwaitArguments = true;
7405 call.DuplicateArguments = emitting_compound_assignment;
7407 if (conditional_access_receiver)
7408 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7410 call.Emit (ec, Getter, Arguments, loc);
7412 if (call.HasAwaitArguments) {
7413 InstanceExpression = call.InstanceExpression;
7414 Arguments = call.EmittedArguments;
7415 has_await_arguments = true;
7419 ec.Emit (OpCodes.Dup);
7420 temp = new LocalTemporary (Type);
7425 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7427 public override void Emit (EmitContext ec)
7432 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7434 has_await_arguments = true;
7439 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7441 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7443 bool ResolveGetter (ResolveContext rc)
7445 if (!best_candidate.HasGet) {
7446 if (InstanceExpression != EmptyExpression.Null) {
7447 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7448 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7449 best_candidate.GetSignatureForError ());
7452 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7453 if (best_candidate.HasDifferentAccessibility) {
7454 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7455 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7456 TypeManager.CSharpSignature (best_candidate));
7458 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7459 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7463 if (best_candidate.HasDifferentAccessibility) {
7464 CheckProtectedMemberAccess (rc, best_candidate.Get);
7467 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7471 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7478 /// Fully resolved expression that evaluates to an Event
7480 public class EventExpr : MemberExpr, IAssignMethod
7482 readonly EventSpec spec;
7485 public EventExpr (EventSpec spec, Location loc)
7493 protected override TypeSpec DeclaringType {
7495 return spec.DeclaringType;
7499 public override string Name {
7505 public override bool IsInstance {
7507 return !spec.IsStatic;
7511 public override bool IsStatic {
7513 return spec.IsStatic;
7517 public override string KindName {
7518 get { return "event"; }
7521 public MethodSpec Operator {
7529 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7532 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7534 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7535 if (spec.BackingField != null &&
7536 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7538 spec.MemberDefinition.SetIsUsed ();
7540 spec.CheckObsoleteness (ec, loc);
7542 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7543 Error_AssignmentEventOnly (ec);
7545 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7547 InstanceExpression = null;
7549 return ml.ResolveMemberAccess (ec, left, original);
7553 return base.ResolveMemberAccess (ec, left, original);
7556 public override Expression CreateExpressionTree (ResolveContext ec)
7558 throw new NotSupportedException ("ET");
7561 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7563 if (right_side == EmptyExpression.EventAddition) {
7564 op = spec.AccessorAdd;
7565 } else if (right_side == EmptyExpression.EventSubtraction) {
7566 op = spec.AccessorRemove;
7570 Error_AssignmentEventOnly (ec);
7574 if (HasConditionalAccess ())
7575 Error_NullPropagatingLValue (ec);
7577 op = CandidateToBaseOverride (ec, op);
7581 protected override Expression DoResolve (ResolveContext ec)
7583 eclass = ExprClass.EventAccess;
7584 type = spec.MemberType;
7586 ResolveInstanceExpression (ec, null);
7588 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7589 Error_AssignmentEventOnly (ec);
7592 DoBestMemberChecks (ec, spec);
7596 public override void Emit (EmitContext ec)
7598 throw new NotSupportedException ();
7599 //Error_CannotAssign ();
7602 #region IAssignMethod Members
7604 public void Emit (EmitContext ec, bool leave_copy)
7606 throw new NotImplementedException ();
7609 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7611 if (leave_copy || !isCompound)
7612 throw new NotImplementedException ("EventExpr::EmitAssign");
7614 Arguments args = new Arguments (1);
7615 args.Add (new Argument (source));
7617 // TODO: Wrong, needs receiver
7618 // if (NullShortCircuit) {
7619 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7622 var call = new CallEmitter ();
7623 call.InstanceExpression = InstanceExpression;
7624 call.ConditionalAccess = ConditionalAccess;
7625 call.EmitStatement (ec, op, args, loc);
7627 // if (NullShortCircuit)
7628 // ec.CloseConditionalAccess (null);
7633 void Error_AssignmentEventOnly (ResolveContext ec)
7635 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7636 ec.Report.Error (79, loc,
7637 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7638 GetSignatureForError ());
7640 ec.Report.Error (70, loc,
7641 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7642 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7646 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7648 name = name.Substring (0, name.LastIndexOf ('.'));
7649 base.Error_CannotCallAbstractBase (rc, name);
7652 public override string GetSignatureForError ()
7654 return TypeManager.CSharpSignature (spec);
7657 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7659 spec.CheckObsoleteness (rc, expr.Location);
7662 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7664 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7668 public class TemporaryVariableReference : VariableReference
7670 public class Declarator : Statement
7672 TemporaryVariableReference variable;
7674 public Declarator (TemporaryVariableReference variable)
7676 this.variable = variable;
7680 protected override void DoEmit (EmitContext ec)
7682 variable.li.CreateBuilder (ec);
7685 public override void Emit (EmitContext ec)
7687 // Don't create sequence point
7691 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7696 protected override void CloneTo (CloneContext clonectx, Statement target)
7704 public TemporaryVariableReference (LocalVariable li, Location loc)
7707 this.type = li.Type;
7711 public override bool IsLockedByStatement {
7719 public LocalVariable LocalInfo {
7725 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7727 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7728 return new TemporaryVariableReference (li, loc);
7731 protected override Expression DoResolve (ResolveContext ec)
7733 eclass = ExprClass.Variable;
7736 // Don't capture temporary variables except when using
7737 // state machine redirection and block yields
7739 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7740 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7741 ec.IsVariableCapturingRequired) {
7742 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7743 storey.CaptureLocalVariable (ec, li);
7749 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7751 return Resolve (ec);
7754 public override void Emit (EmitContext ec)
7756 li.CreateBuilder (ec);
7761 public void EmitAssign (EmitContext ec, Expression source)
7763 li.CreateBuilder (ec);
7765 EmitAssign (ec, source, false, false);
7768 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7770 return li.HoistedVariant;
7773 public override bool IsFixed {
7774 get { return true; }
7777 public override bool IsRef {
7778 get { return false; }
7781 public override string Name {
7782 get { throw new NotImplementedException (); }
7785 public override void SetHasAddressTaken ()
7787 throw new NotImplementedException ();
7790 protected override ILocalVariable Variable {
7794 public override VariableInfo VariableInfo {
7795 get { return null; }
7800 /// Handles `var' contextual keyword; var becomes a keyword only
7801 /// if no type called var exists in a variable scope
7803 class VarExpr : SimpleName
7805 public VarExpr (Location loc)
7810 public bool InferType (ResolveContext ec, Expression rhs)
7813 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7817 if (type.Kind == MemberKind.Void || InternalType.HasNoType (type) || (rhs is TupleLiteral && TupleLiteral.ContainsNoTypeElement (type))) {
7818 ec.Report.Error (815, loc,
7819 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7820 type.GetSignatureForError ());
7821 type = InternalType.ErrorType;
7825 eclass = ExprClass.Variable;
7829 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7831 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7832 base.Error_TypeOrNamespaceNotFound (ec);
7834 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");