2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
233 var rc = mc as ResolveContext ?? new ResolveContext (mc);
234 Expression e = Resolve (rc);
236 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // 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
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 public static bool IsNeverNull (Expression expr)
435 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
438 var c = expr as Constant;
442 var tc = expr as TypeCast;
444 return IsNeverNull (tc.Child);
449 protected static bool IsNullPropagatingValid (TypeSpec type)
452 case MemberKind.Struct:
453 return type.IsNullableType;
454 case MemberKind.Enum:
455 case MemberKind.Void:
456 case MemberKind.PointerType:
458 case MemberKind.InternalCompilerType:
459 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
460 case MemberKind.TypeParameter:
461 return !((TypeParameterSpec) type).IsValueType;
467 public virtual bool HasConditionalAccess ()
472 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
474 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
475 Nullable.NullableInfo.MakeType (rc.Module, type) :
480 /// Resolves an expression and performs semantic analysis on it.
484 /// Currently Resolve wraps DoResolve to perform sanity
485 /// checking and assertion checking on what we expect from Resolve.
487 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
489 if (eclass != ExprClass.Unresolved) {
490 if ((flags & ExprClassToResolveFlags) == 0) {
491 Error_UnexpectedKind (ec, flags, loc);
505 if ((flags & e.ExprClassToResolveFlags) == 0) {
506 e.Error_UnexpectedKind (ec, flags, loc);
511 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
514 } catch (Exception ex) {
515 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
516 ec.Report.Printer is NullReportPrinter)
519 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
520 return ErrorExpression.Instance; // TODO: Add location
525 /// Resolves an expression and performs semantic analysis on it.
527 public Expression Resolve (ResolveContext rc)
529 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
533 /// Resolves an expression for LValue assignment
537 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
538 /// checking and assertion checking on what we expect from Resolve
540 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
542 int errors = ec.Report.Errors;
543 bool out_access = right_side == EmptyExpression.OutAccess;
545 Expression e = DoResolveLValue (ec, right_side);
547 if (e != null && out_access && !(e is IMemoryLocation)) {
548 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
549 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
551 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
552 // e.GetType () + " " + e.GetSignatureForError ());
557 if (errors == ec.Report.Errors) {
558 Error_ValueAssignment (ec, right_side);
563 if (e.eclass == ExprClass.Unresolved)
564 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
566 if ((e.type == null) && !(e is GenericTypeExpr))
567 throw new Exception ("Expression " + e + " did not set its type after Resolve");
572 public Constant ResolveLabelConstant (ResolveContext rc)
574 var expr = Resolve (rc);
578 Constant c = expr as Constant;
580 if (expr.type != InternalType.ErrorType)
581 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
589 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
591 if (Attribute.IsValidArgumentType (parameterType)) {
592 rc.Module.Compiler.Report.Error (182, loc,
593 "An attribute argument must be a constant expression, typeof expression or array creation expression");
595 rc.Module.Compiler.Report.Error (181, loc,
596 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
597 targetType.GetSignatureForError ());
602 /// Emits the code for the expression
606 /// The Emit method is invoked to generate the code
607 /// for the expression.
609 public abstract void Emit (EmitContext ec);
612 // Emit code to branch to @target if this expression is equivalent to @on_true.
613 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
614 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
615 // including the use of conditional branches. Note also that a branch MUST be emitted
616 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
619 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
622 // Emit this expression for its side effects, not for its value.
623 // The default implementation is to emit the value, and then throw it away.
624 // Subclasses can provide more efficient implementations, but those MUST be equivalent
625 public virtual void EmitSideEffect (EmitContext ec)
628 ec.Emit (OpCodes.Pop);
632 // Emits the expression into temporary field variable. The method
633 // should be used for await expressions only
635 public virtual Expression EmitToField (EmitContext ec)
638 // This is the await prepare Emit method. When emitting code like
639 // a + b we emit code like
645 // For await a + await b we have to interfere the flow to keep the
646 // stack clean because await yields from the expression. The emit
649 // a = a.EmitToField () // a is changed to temporary field access
650 // b = b.EmitToField ()
656 // The idea is to emit expression and leave the stack empty with
657 // result value still available.
659 // Expressions should override this default implementation when
660 // optimized version can be provided (e.g. FieldExpr)
663 // We can optimize for side-effect free expressions, they can be
664 // emitted out of order
666 if (IsSideEffectFree)
669 bool needs_temporary = ContainsEmitWithAwait ();
670 if (!needs_temporary)
673 // Emit original code
674 var field = EmitToFieldSource (ec);
677 // Store the result to temporary field when we
678 // cannot load `this' directly
680 field = ec.GetTemporaryField (type);
681 if (needs_temporary) {
683 // Create temporary local (we cannot load `this' before Emit)
685 var temp = ec.GetTemporaryLocal (type);
686 ec.Emit (OpCodes.Stloc, temp);
689 ec.Emit (OpCodes.Ldloc, temp);
690 field.EmitAssignFromStack (ec);
692 ec.FreeTemporaryLocal (temp, type);
694 field.EmitAssignFromStack (ec);
701 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
704 // Default implementation calls Emit method
710 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
712 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
713 bool contains_await = false;
715 for (int i = 1; i < expressions.Count; ++i) {
716 if (expressions[i].ContainsEmitWithAwait ()) {
717 contains_await = true;
722 if (contains_await) {
723 for (int i = 0; i < expressions.Count; ++i) {
724 expressions[i] = expressions[i].EmitToField (ec);
729 for (int i = 0; i < expressions.Count; ++i) {
730 expressions[i].Emit (ec);
735 /// Protected constructor. Only derivate types should
736 /// be able to be created
739 protected Expression ()
744 /// Returns a fully formed expression after a MemberLookup
747 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
749 if (spec is EventSpec)
750 return new EventExpr ((EventSpec) spec, loc);
751 if (spec is ConstSpec)
752 return new ConstantExpr ((ConstSpec) spec, loc);
753 if (spec is FieldSpec)
754 return new FieldExpr ((FieldSpec) spec, loc);
755 if (spec is PropertySpec)
756 return new PropertyExpr ((PropertySpec) spec, loc);
757 if (spec is TypeSpec)
758 return new TypeExpression (((TypeSpec) spec), loc);
763 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
765 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
768 case MemberKind.Struct:
769 // Every struct has implicit default constructor if not provided by user
773 rc.Report.SymbolRelatedToPreviousError (type);
774 // Report meaningful error for struct as they always have default ctor in C# context
775 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
777 case MemberKind.MissingType:
778 case MemberKind.InternalCompilerType:
779 // LAMESPEC: dynamic is not really object
780 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
784 rc.Report.SymbolRelatedToPreviousError (type);
785 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
786 type.GetSignatureForError ());
793 if (args == null && type.IsStruct) {
794 bool includes_empty = false;
795 foreach (MethodSpec ctor in ctors) {
796 if (ctor.Parameters.IsEmpty) {
797 includes_empty = true;
805 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
806 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
807 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
810 return r.ResolveMember<MethodSpec> (rc, ref args);
814 public enum MemberLookupRestrictions
820 EmptyArguments = 1 << 4,
821 IgnoreArity = 1 << 5,
822 IgnoreAmbiguity = 1 << 6,
823 NameOfExcluded = 1 << 7,
827 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
828 // `qualifier_type' or null to lookup members in the current class.
830 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
832 var members = MemberCache.FindMembers (queried_type, name, false);
838 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
842 if (members [0].DeclaringType.BaseType == null)
845 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
846 } while (members != null);
851 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
853 MemberSpec non_method = null;
854 MemberSpec ambig_non_method = null;
856 for (int i = 0; i < members.Count; ++i) {
857 var member = members [i];
859 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
860 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
863 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
866 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
870 if (!member.IsAccessible (rc))
874 // With runtime binder we can have a situation where queried type is inaccessible
875 // because it came via dynamic object, the check about inconsisted accessibility
876 // had no effect as the type was unknown during compilation
879 // private class N { }
881 // public dynamic Foo ()
887 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
891 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
892 if (member is MethodSpec) {
894 // Interface members that are hidden by class members are removed from the set. This
895 // step only has an effect if T is a type parameter and T has both an effective base
896 // class other than object and a non-empty effective interface set
898 var tps = queried_type as TypeParameterSpec;
899 if (tps != null && tps.HasTypeConstraint)
900 members = RemoveHiddenTypeParameterMethods (members);
902 return new MethodGroupExpr (members, queried_type, loc);
905 if (!Invocation.IsMemberInvocable (member))
909 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
911 } else if (!errorMode && !member.IsNotCSharpCompatible) {
913 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
914 // T has both an effective base class other than object and a non-empty effective interface set.
916 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
918 var tps = queried_type as TypeParameterSpec;
919 if (tps != null && tps.HasTypeConstraint) {
920 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
923 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
929 ambig_non_method = member;
933 if (non_method != null) {
934 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
935 var report = rc.Module.Compiler.Report;
936 report.SymbolRelatedToPreviousError (non_method);
937 report.SymbolRelatedToPreviousError (ambig_non_method);
938 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
939 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
942 if (non_method is MethodSpec)
943 return new MethodGroupExpr (members, queried_type, loc);
945 return ExprClassFromMemberInfo (non_method, loc);
951 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
953 if (members.Count < 2)
957 // If M is a method, then all non-method members declared in an interface declaration
958 // are removed from the set, and all methods with the same signature as M declared in
959 // an interface declaration are removed from the set
963 for (int i = 0; i < members.Count; ++i) {
964 var method = members[i] as MethodSpec;
965 if (method == null) {
968 members = new List<MemberSpec> (members);
971 members.RemoveAt (i--);
975 if (!method.DeclaringType.IsInterface)
978 for (int ii = 0; ii < members.Count; ++ii) {
979 var candidate = members[ii] as MethodSpec;
980 if (candidate == null || !candidate.DeclaringType.IsClass)
983 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
986 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
991 members = new List<MemberSpec> (members);
994 members.RemoveAt (i--);
1002 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1004 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1007 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1009 throw new NotImplementedException ();
1012 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1014 if (t == InternalType.ErrorType)
1017 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1018 oper, t.GetSignatureForError ());
1021 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1023 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1026 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1028 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1031 protected void Error_NullPropagatingLValue (ResolveContext rc)
1033 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1036 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1041 // Special version of flow analysis for expressions which can return different
1042 // on-true and on-false result. Used by &&, ||, ?: expressions
1044 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1047 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1051 /// Returns an expression that can be used to invoke operator true
1052 /// on the expression if it exists.
1054 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1056 return GetOperatorTrueOrFalse (ec, e, true, loc);
1060 /// Returns an expression that can be used to invoke operator false
1061 /// on the expression if it exists.
1063 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1065 return GetOperatorTrueOrFalse (ec, e, false, loc);
1068 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1070 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1072 if (type.IsNullableType)
1073 type = Nullable.NullableInfo.GetUnderlyingType (type);
1075 var methods = MemberCache.GetUserOperator (type, op, false);
1076 if (methods == null)
1079 Arguments arguments = new Arguments (1);
1080 arguments.Add (new Argument (e));
1082 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1083 var oper = res.ResolveOperator (ec, ref arguments);
1088 return new UserOperatorCall (oper, arguments, null, loc);
1091 public virtual string ExprClassName
1095 case ExprClass.Unresolved:
1096 return "Unresolved";
1097 case ExprClass.Value:
1099 case ExprClass.Variable:
1101 case ExprClass.Namespace:
1103 case ExprClass.Type:
1105 case ExprClass.MethodGroup:
1106 return "method group";
1107 case ExprClass.PropertyAccess:
1108 return "property access";
1109 case ExprClass.EventAccess:
1110 return "event access";
1111 case ExprClass.IndexerAccess:
1112 return "indexer access";
1113 case ExprClass.Nothing:
1115 case ExprClass.TypeParameter:
1116 return "type parameter";
1118 throw new Exception ("Should not happen");
1123 /// Reports that we were expecting `expr' to be of class `expected'
1125 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1127 var name = memberExpr.GetSignatureForError ();
1129 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1132 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1134 string [] valid = new string [4];
1137 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1138 valid [count++] = "variable";
1139 valid [count++] = "value";
1142 if ((flags & ResolveFlags.Type) != 0)
1143 valid [count++] = "type";
1145 if ((flags & ResolveFlags.MethodGroup) != 0)
1146 valid [count++] = "method group";
1149 valid [count++] = "unknown";
1151 StringBuilder sb = new StringBuilder (valid [0]);
1152 for (int i = 1; i < count - 1; i++) {
1154 sb.Append (valid [i]);
1157 sb.Append ("' or `");
1158 sb.Append (valid [count - 1]);
1161 ec.Report.Error (119, loc,
1162 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1165 public static void UnsafeError (ResolveContext ec, Location loc)
1167 UnsafeError (ec.Report, loc);
1170 public static void UnsafeError (Report Report, Location loc)
1172 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1176 // Converts `source' to an int, uint, long or ulong.
1178 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1180 var btypes = ec.BuiltinTypes;
1182 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1183 Arguments args = new Arguments (1);
1184 args.Add (new Argument (source));
1185 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1188 Expression converted;
1190 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1191 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1192 if (converted == null)
1193 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1194 if (converted == null)
1195 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1196 if (converted == null)
1197 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1199 if (converted == null) {
1200 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1209 // Only positive constants are allowed at compile time
1211 Constant c = converted as Constant;
1212 if (c != null && c.IsNegative)
1213 Error_NegativeArrayIndex (ec, source.loc);
1215 // No conversion needed to array index
1216 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1219 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1222 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1224 if (args.Count != 1){
1225 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1230 if (arg is NamedArgument)
1231 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1233 var index = arg.Expr.Resolve (rc);
1237 index = ConvertExpressionToArrayIndex (rc, index, true);
1239 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1240 return new Indirection (p, loc);
1244 // Derived classes implement this method by cloning the fields that
1245 // could become altered during the Resolve stage
1247 // Only expressions that are created for the parser need to implement
1250 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1252 throw new NotImplementedException (
1254 "CloneTo not implemented for expression {0}", this.GetType ()));
1258 // Clones an expression created by the parser.
1260 // We only support expressions created by the parser so far, not
1261 // expressions that have been resolved (many more classes would need
1262 // to implement CloneTo).
1264 // This infrastructure is here merely for Lambda expressions which
1265 // compile the same code using different type values for the same
1266 // arguments to find the correct overload
1268 public virtual Expression Clone (CloneContext clonectx)
1270 Expression cloned = (Expression) MemberwiseClone ();
1271 CloneTo (clonectx, cloned);
1277 // Implementation of expression to expression tree conversion
1279 public abstract Expression CreateExpressionTree (ResolveContext ec);
1281 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1283 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1286 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1288 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1291 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1293 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1296 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1298 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1302 return new TypeExpression (t, loc);
1306 // Implemented by all expressions which support conversion from
1307 // compiler expression to invokable runtime expression. Used by
1308 // dynamic C# binder.
1310 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1312 throw new NotImplementedException ("MakeExpression for " + GetType ());
1315 public virtual object Accept (StructuralVisitor visitor)
1317 return visitor.Visit (this);
1322 /// This is just a base class for expressions that can
1323 /// appear on statements (invocations, object creation,
1324 /// assignments, post/pre increment and decrement). The idea
1325 /// being that they would support an extra Emition interface that
1326 /// does not leave a result on the stack.
1328 public abstract class ExpressionStatement : Expression
1330 public virtual void MarkReachable (Reachability rc)
1334 public ExpressionStatement ResolveStatement (BlockContext ec)
1336 Expression e = Resolve (ec);
1340 ExpressionStatement es = e as ExpressionStatement;
1341 if (es == null || e is AnonymousMethodBody)
1342 Error_InvalidExpressionStatement (ec);
1345 // This is quite expensive warning, try to limit the damage
1347 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1348 WarningAsyncWithoutWait (ec, e);
1354 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1356 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1357 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1362 // Need to do full resolve because GetAwaiter can be extension method
1363 // available only in this context
1365 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1369 var arguments = new Arguments (0);
1370 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1375 // Use same check rules as for real await
1377 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1378 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1381 bc.Report.Warning (4014, 1, e.Location,
1382 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1386 var inv = e as Invocation;
1387 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1388 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1389 bc.Report.Warning (4014, 1, e.Location,
1390 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1396 /// Requests the expression to be emitted in a `statement'
1397 /// context. This means that no new value is left on the
1398 /// stack after invoking this method (constrasted with
1399 /// Emit that will always leave a value on the stack).
1401 public abstract void EmitStatement (EmitContext ec);
1403 public override void EmitSideEffect (EmitContext ec)
1410 /// This kind of cast is used to encapsulate the child
1411 /// whose type is child.Type into an expression that is
1412 /// reported to return "return_type". This is used to encapsulate
1413 /// expressions which have compatible types, but need to be dealt
1414 /// at higher levels with.
1416 /// For example, a "byte" expression could be encapsulated in one
1417 /// of these as an "unsigned int". The type for the expression
1418 /// would be "unsigned int".
1421 public abstract class TypeCast : Expression
1423 protected readonly Expression child;
1425 protected TypeCast (Expression child, TypeSpec return_type)
1427 eclass = child.eclass;
1428 loc = child.Location;
1433 public Expression Child {
1439 public override bool ContainsEmitWithAwait ()
1441 return child.ContainsEmitWithAwait ();
1444 public override Expression CreateExpressionTree (ResolveContext ec)
1446 Arguments args = new Arguments (2);
1447 args.Add (new Argument (child.CreateExpressionTree (ec)));
1448 args.Add (new Argument (new TypeOf (type, loc)));
1450 if (type.IsPointer || child.Type.IsPointer)
1451 Error_PointerInsideExpressionTree (ec);
1453 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1456 protected override Expression DoResolve (ResolveContext ec)
1458 // This should never be invoked, we are born in fully
1459 // initialized state.
1464 public override void Emit (EmitContext ec)
1469 public override void FlowAnalysis (FlowAnalysisContext fc)
1471 child.FlowAnalysis (fc);
1474 public override SLE.Expression MakeExpression (BuilderContext ctx)
1477 return base.MakeExpression (ctx);
1479 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1480 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1481 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1485 protected override void CloneTo (CloneContext clonectx, Expression t)
1490 public override bool IsNull {
1491 get { return child.IsNull; }
1495 public class EmptyCast : TypeCast {
1496 EmptyCast (Expression child, TypeSpec target_type)
1497 : base (child, target_type)
1501 public static Expression Create (Expression child, TypeSpec type)
1503 Constant c = child as Constant;
1505 var enum_constant = c as EnumConstant;
1506 if (enum_constant != null)
1507 c = enum_constant.Child;
1509 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1513 var res = c.ConvertImplicitly (type);
1519 EmptyCast e = child as EmptyCast;
1521 return new EmptyCast (e.child, type);
1523 return new EmptyCast (child, type);
1526 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1528 child.EmitBranchable (ec, label, on_true);
1531 public override void EmitSideEffect (EmitContext ec)
1533 child.EmitSideEffect (ec);
1538 // Used for predefined type user operator (no obsolete check, etc.)
1540 public class OperatorCast : TypeCast
1542 readonly MethodSpec conversion_operator;
1544 public OperatorCast (Expression expr, TypeSpec target_type)
1545 : this (expr, target_type, target_type, false)
1549 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1550 : this (expr, target_type, target_type, find_explicit)
1554 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1555 : base (expr, returnType)
1557 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1558 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1561 foreach (MethodSpec oper in mi) {
1562 if (oper.ReturnType != returnType)
1565 if (oper.Parameters.Types[0] == expr.Type) {
1566 conversion_operator = oper;
1572 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1573 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1576 public override void Emit (EmitContext ec)
1579 ec.Emit (OpCodes.Call, conversion_operator);
1584 // Constant specialization of EmptyCast.
1585 // We need to special case this since an empty cast of
1586 // a constant is still a constant.
1588 public class EmptyConstantCast : Constant
1590 public readonly Constant child;
1592 public EmptyConstantCast (Constant child, TypeSpec type)
1593 : base (child.Location)
1596 throw new ArgumentNullException ("child");
1599 this.eclass = child.eclass;
1603 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1605 if (child.Type == target_type)
1608 // FIXME: check that 'type' can be converted to 'target_type' first
1609 return child.ConvertExplicitly (in_checked_context, target_type);
1612 public override Expression CreateExpressionTree (ResolveContext ec)
1614 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1615 child.CreateExpressionTree (ec),
1616 new TypeOf (type, loc));
1619 Error_PointerInsideExpressionTree (ec);
1621 return CreateExpressionFactoryCall (ec, "Convert", args);
1624 public override bool IsDefaultValue {
1625 get { return child.IsDefaultValue; }
1628 public override bool IsNegative {
1629 get { return child.IsNegative; }
1632 public override bool IsNull {
1633 get { return child.IsNull; }
1636 public override bool IsOneInteger {
1637 get { return child.IsOneInteger; }
1640 public override bool IsSideEffectFree {
1642 return child.IsSideEffectFree;
1646 public override bool IsZeroInteger {
1647 get { return child.IsZeroInteger; }
1650 public override void Emit (EmitContext ec)
1655 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1657 child.EmitBranchable (ec, label, on_true);
1659 // Only to make verifier happy
1660 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1661 ec.Emit (OpCodes.Unbox_Any, type);
1664 public override void EmitSideEffect (EmitContext ec)
1666 child.EmitSideEffect (ec);
1669 public override object GetValue ()
1671 return child.GetValue ();
1674 public override string GetValueAsLiteral ()
1676 return child.GetValueAsLiteral ();
1679 public override long GetValueAsLong ()
1681 return child.GetValueAsLong ();
1684 public override Constant ConvertImplicitly (TypeSpec target_type)
1686 if (type == target_type)
1689 // FIXME: Do we need to check user conversions?
1690 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1693 return child.ConvertImplicitly (target_type);
1698 /// This class is used to wrap literals which belong inside Enums
1700 public class EnumConstant : Constant
1702 public Constant Child;
1704 public EnumConstant (Constant child, TypeSpec enum_type)
1705 : base (child.Location)
1709 this.eclass = ExprClass.Value;
1710 this.type = enum_type;
1713 protected EnumConstant (Location loc)
1718 public override void Emit (EmitContext ec)
1723 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1725 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1728 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1730 Child.EmitBranchable (ec, label, on_true);
1733 public override void EmitSideEffect (EmitContext ec)
1735 Child.EmitSideEffect (ec);
1738 public override string GetSignatureForError()
1740 return Type.GetSignatureForError ();
1743 public override object GetValue ()
1745 return Child.GetValue ();
1749 public override object GetTypedValue ()
1752 // The method can be used in dynamic context only (on closed types)
1754 // System.Enum.ToObject cannot be called on dynamic types
1755 // EnumBuilder has to be used, but we cannot use EnumBuilder
1756 // because it does not properly support generics
1758 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1762 public override string GetValueAsLiteral ()
1764 return Child.GetValueAsLiteral ();
1767 public override long GetValueAsLong ()
1769 return Child.GetValueAsLong ();
1772 public EnumConstant Increment()
1774 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1777 public override bool IsDefaultValue {
1779 return Child.IsDefaultValue;
1783 public override bool IsSideEffectFree {
1785 return Child.IsSideEffectFree;
1789 public override bool IsZeroInteger {
1790 get { return Child.IsZeroInteger; }
1793 public override bool IsNegative {
1795 return Child.IsNegative;
1799 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1801 if (Child.Type == target_type)
1804 return Child.ConvertExplicitly (in_checked_context, target_type);
1807 public override Constant ConvertImplicitly (TypeSpec type)
1809 if (this.type == type) {
1813 if (!Convert.ImplicitStandardConversionExists (this, type)){
1817 return Child.ConvertImplicitly (type);
1822 /// This kind of cast is used to encapsulate Value Types in objects.
1824 /// The effect of it is to box the value type emitted by the previous
1827 public class BoxedCast : TypeCast {
1829 public BoxedCast (Expression expr, TypeSpec target_type)
1830 : base (expr, target_type)
1832 eclass = ExprClass.Value;
1835 protected override Expression DoResolve (ResolveContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1845 // Only boxing to object type is supported
1846 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1847 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1851 enc.Encode (child.Type);
1852 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1855 public override void Emit (EmitContext ec)
1859 ec.Emit (OpCodes.Box, child.Type);
1862 public override void EmitSideEffect (EmitContext ec)
1864 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1865 // so, we need to emit the box+pop instructions in most cases
1866 if (child.Type.IsStruct &&
1867 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1868 child.EmitSideEffect (ec);
1870 base.EmitSideEffect (ec);
1874 public class UnboxCast : TypeCast {
1875 public UnboxCast (Expression expr, TypeSpec return_type)
1876 : base (expr, return_type)
1880 protected override Expression DoResolve (ResolveContext ec)
1882 // This should never be invoked, we are born in fully
1883 // initialized state.
1888 public override void Emit (EmitContext ec)
1892 ec.Emit (OpCodes.Unbox_Any, type);
1897 /// This is used to perform explicit numeric conversions.
1899 /// Explicit numeric conversions might trigger exceptions in a checked
1900 /// context, so they should generate the conv.ovf opcodes instead of
1903 public class ConvCast : TypeCast {
1904 public enum Mode : byte {
1905 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1907 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1908 U2_I1, U2_U1, U2_I2, U2_CH,
1909 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1910 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1911 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1912 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1913 CH_I1, CH_U1, CH_I2,
1914 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1915 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1921 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1922 : base (child, return_type)
1927 protected override Expression DoResolve (ResolveContext ec)
1929 // This should never be invoked, we are born in fully
1930 // initialized state.
1935 public override string ToString ()
1937 return String.Format ("ConvCast ({0}, {1})", mode, child);
1940 public override void Emit (EmitContext ec)
1946 public static void Emit (EmitContext ec, Mode mode)
1948 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1950 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1951 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1953 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1957 case Mode.U1_CH: /* nothing */ break;
1959 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1960 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1963 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1964 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1966 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1967 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1968 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1969 case Mode.U2_CH: /* nothing */ break;
1971 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1972 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1973 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1974 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1975 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1977 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1979 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1980 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1981 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1982 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1983 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1984 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1986 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1987 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1988 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1989 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1991 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1992 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1996 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1997 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1998 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1999 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2000 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2001 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2002 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2003 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2004 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2006 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2007 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2008 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2010 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2011 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2012 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2013 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2014 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2015 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2016 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2017 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2018 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2021 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2022 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2023 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2024 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2025 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2026 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2027 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2028 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2029 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2031 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2035 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2036 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2037 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2038 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2039 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2042 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2045 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2048 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2049 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2051 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2052 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2053 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2054 case Mode.U2_CH: /* nothing */ break;
2056 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2057 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2058 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2059 case Mode.I4_U4: /* nothing */ break;
2060 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2061 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2062 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2064 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2065 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2066 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2067 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2068 case Mode.U4_I4: /* nothing */ break;
2069 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2071 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2072 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2073 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2074 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2076 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2077 case Mode.I8_U8: /* nothing */ break;
2078 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2079 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2081 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2082 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2083 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2084 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2085 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2086 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2087 case Mode.U8_I8: /* nothing */ break;
2088 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2089 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2091 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2092 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2093 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2096 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2097 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2098 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2099 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2100 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2101 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2102 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2103 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2106 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2107 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2108 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2109 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2110 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2111 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2112 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2113 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2114 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2116 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2122 class OpcodeCast : TypeCast
2126 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2127 : base (child, return_type)
2132 protected override Expression DoResolve (ResolveContext ec)
2134 // This should never be invoked, we are born in fully
2135 // initialized state.
2140 public override void Emit (EmitContext ec)
2146 public TypeSpec UnderlyingType {
2147 get { return child.Type; }
2152 // Opcode casts expression with 2 opcodes but only
2153 // single expression tree node
2155 class OpcodeCastDuplex : OpcodeCast
2157 readonly OpCode second;
2159 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2160 : base (child, returnType, first)
2162 this.second = second;
2165 public override void Emit (EmitContext ec)
2173 /// This kind of cast is used to encapsulate a child and cast it
2174 /// to the class requested
2176 public sealed class ClassCast : TypeCast {
2177 readonly bool forced;
2179 public ClassCast (Expression child, TypeSpec return_type)
2180 : base (child, return_type)
2184 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2185 : base (child, return_type)
2187 this.forced = forced;
2190 public override void Emit (EmitContext ec)
2194 bool gen = TypeManager.IsGenericParameter (child.Type);
2196 ec.Emit (OpCodes.Box, child.Type);
2198 if (type.IsGenericParameter) {
2199 ec.Emit (OpCodes.Unbox_Any, type);
2206 ec.Emit (OpCodes.Castclass, type);
2211 // Created during resolving pahse when an expression is wrapped or constantified
2212 // and original expression can be used later (e.g. for expression trees)
2214 public class ReducedExpression : Expression
2216 public sealed class ReducedConstantExpression : EmptyConstantCast
2218 readonly Expression orig_expr;
2220 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2221 : base (expr, expr.Type)
2223 this.orig_expr = orig_expr;
2226 public Expression OriginalExpression {
2232 public override Constant ConvertImplicitly (TypeSpec target_type)
2234 Constant c = base.ConvertImplicitly (target_type);
2236 c = new ReducedConstantExpression (c, orig_expr);
2241 public override Expression CreateExpressionTree (ResolveContext ec)
2243 return orig_expr.CreateExpressionTree (ec);
2246 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2248 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2250 c = new ReducedConstantExpression (c, orig_expr);
2254 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2257 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2259 if (orig_expr is Conditional)
2260 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2262 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2266 sealed class ReducedExpressionStatement : ExpressionStatement
2268 readonly Expression orig_expr;
2269 readonly ExpressionStatement stm;
2271 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2273 this.orig_expr = orig;
2275 this.eclass = stm.eclass;
2276 this.type = stm.Type;
2278 this.loc = orig.Location;
2281 public override bool ContainsEmitWithAwait ()
2283 return stm.ContainsEmitWithAwait ();
2286 public override Expression CreateExpressionTree (ResolveContext ec)
2288 return orig_expr.CreateExpressionTree (ec);
2291 protected override Expression DoResolve (ResolveContext ec)
2296 public override void Emit (EmitContext ec)
2301 public override void EmitStatement (EmitContext ec)
2303 stm.EmitStatement (ec);
2306 public override void FlowAnalysis (FlowAnalysisContext fc)
2308 stm.FlowAnalysis (fc);
2312 readonly Expression expr, orig_expr;
2314 private ReducedExpression (Expression expr, Expression orig_expr)
2317 this.eclass = expr.eclass;
2318 this.type = expr.Type;
2319 this.orig_expr = orig_expr;
2320 this.loc = orig_expr.Location;
2325 public override bool IsSideEffectFree {
2327 return expr.IsSideEffectFree;
2331 public Expression OriginalExpression {
2339 public override bool ContainsEmitWithAwait ()
2341 return expr.ContainsEmitWithAwait ();
2345 // Creates fully resolved expression switcher
2347 public static Constant Create (Constant expr, Expression original_expr)
2349 if (expr.eclass == ExprClass.Unresolved)
2350 throw new ArgumentException ("Unresolved expression");
2352 return new ReducedConstantExpression (expr, original_expr);
2355 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2357 return new ReducedExpressionStatement (s, orig);
2360 public static Expression Create (Expression expr, Expression original_expr)
2362 return Create (expr, original_expr, true);
2366 // Creates unresolved reduce expression. The original expression has to be
2367 // already resolved. Created expression is constant based based on `expr'
2368 // value unless canBeConstant is used
2370 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2372 if (canBeConstant) {
2373 Constant c = expr as Constant;
2375 return Create (c, original_expr);
2378 ExpressionStatement s = expr as ExpressionStatement;
2380 return Create (s, original_expr);
2382 if (expr.eclass == ExprClass.Unresolved)
2383 throw new ArgumentException ("Unresolved expression");
2385 return new ReducedExpression (expr, original_expr);
2388 public override Expression CreateExpressionTree (ResolveContext ec)
2390 return orig_expr.CreateExpressionTree (ec);
2393 protected override Expression DoResolve (ResolveContext ec)
2398 public override void Emit (EmitContext ec)
2403 public override Expression EmitToField (EmitContext ec)
2405 return expr.EmitToField(ec);
2408 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2410 expr.EmitBranchable (ec, target, on_true);
2413 public override void FlowAnalysis (FlowAnalysisContext fc)
2415 expr.FlowAnalysis (fc);
2418 public override SLE.Expression MakeExpression (BuilderContext ctx)
2420 return orig_expr.MakeExpression (ctx);
2425 // Standard composite pattern
2427 public abstract class CompositeExpression : Expression
2429 protected Expression expr;
2431 protected CompositeExpression (Expression expr)
2434 this.loc = expr.Location;
2437 public override bool ContainsEmitWithAwait ()
2439 return expr.ContainsEmitWithAwait ();
2442 public override Expression CreateExpressionTree (ResolveContext rc)
2444 return expr.CreateExpressionTree (rc);
2447 public Expression Child {
2448 get { return expr; }
2451 protected override Expression DoResolve (ResolveContext rc)
2453 expr = expr.Resolve (rc);
2458 eclass = expr.eclass;
2462 public override void Emit (EmitContext ec)
2467 public override bool IsNull {
2468 get { return expr.IsNull; }
2473 // Base of expressions used only to narrow resolve flow
2475 public abstract class ShimExpression : Expression
2477 protected Expression expr;
2479 protected ShimExpression (Expression expr)
2484 public Expression Expr {
2490 protected override void CloneTo (CloneContext clonectx, Expression t)
2495 ShimExpression target = (ShimExpression) t;
2496 target.expr = expr.Clone (clonectx);
2499 public override bool ContainsEmitWithAwait ()
2501 return expr.ContainsEmitWithAwait ();
2504 public override Expression CreateExpressionTree (ResolveContext ec)
2506 throw new NotSupportedException ("ET");
2509 public override void Emit (EmitContext ec)
2511 throw new InternalErrorException ("Missing Resolve call");
2515 public class UnreachableExpression : Expression
2517 public UnreachableExpression (Expression expr)
2519 this.loc = expr.Location;
2522 public override Expression CreateExpressionTree (ResolveContext ec)
2525 throw new NotImplementedException ();
2528 protected override Expression DoResolve (ResolveContext rc)
2530 throw new NotSupportedException ();
2533 public override void FlowAnalysis (FlowAnalysisContext fc)
2535 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2538 public override void Emit (EmitContext ec)
2542 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2548 // Unresolved type name expressions
2550 public abstract class ATypeNameExpression : FullNamedExpression
2553 protected TypeArguments targs;
2555 protected ATypeNameExpression (string name, Location l)
2561 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2568 protected ATypeNameExpression (string name, int arity, Location l)
2569 : this (name, new UnboundTypeArguments (arity, l), l)
2577 return targs == null ? 0 : targs.Count;
2581 public bool HasTypeArguments {
2583 return targs != null && !targs.IsEmpty;
2587 public string Name {
2596 public TypeArguments TypeArguments {
2604 public override bool Equals (object obj)
2606 ATypeNameExpression atne = obj as ATypeNameExpression;
2607 return atne != null && atne.Name == Name &&
2608 (targs == null || targs.Equals (atne.targs));
2611 public override int GetHashCode ()
2613 return Name.GetHashCode ();
2616 // TODO: Move it to MemberCore
2617 public static string GetMemberType (MemberCore mc)
2623 if (mc is FieldBase)
2625 if (mc is MethodCore)
2627 if (mc is EnumMember)
2635 public override string GetSignatureForError ()
2637 if (targs != null) {
2638 return Name + "<" + targs.GetSignatureForError () + ">";
2644 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2648 /// SimpleName expressions are formed of a single word and only happen at the beginning
2649 /// of a dotted-name.
2651 public class SimpleName : ATypeNameExpression
2653 public SimpleName (string name, Location l)
2658 public SimpleName (string name, TypeArguments args, Location l)
2659 : base (name, args, l)
2663 public SimpleName (string name, int arity, Location l)
2664 : base (name, arity, l)
2668 public SimpleName GetMethodGroup ()
2670 return new SimpleName (Name, targs, loc);
2673 protected override Expression DoResolve (ResolveContext rc)
2675 return SimpleNameResolve (rc, null);
2678 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2680 return SimpleNameResolve (ec, right_side);
2683 public void Error_NameDoesNotExist (ResolveContext rc)
2685 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2688 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2690 if (ctx.CurrentType != null) {
2691 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2692 if (member != null) {
2693 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2698 var report = ctx.Module.Compiler.Report;
2700 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2701 if (retval != null) {
2702 report.SymbolRelatedToPreviousError (retval.Type);
2703 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2707 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2708 if (retval != null) {
2709 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2713 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2714 if (ns_candidates != null) {
2715 if (ctx is UsingAliasNamespace.AliasContext) {
2716 report.Error (246, loc,
2717 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2718 ns_candidates[0], Name);
2720 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2721 report.Error (246, loc,
2722 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2726 report.Error (246, loc,
2727 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2732 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2734 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2737 if (fne.Type != null && Arity > 0) {
2738 if (HasTypeArguments) {
2739 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2740 if (ct.ResolveAsType (mc) == null)
2746 targs.Resolve (mc, allowUnboundTypeArguments);
2748 return new GenericOpenTypeExpr (fne.Type, loc);
2752 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2754 if (!(fne is NamespaceExpression))
2758 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2759 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2760 mc.Module.Compiler.Report.Error (1980, Location,
2761 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2762 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2765 fne = new DynamicTypeExpr (loc);
2766 fne.ResolveAsType (mc);
2772 Error_TypeOrNamespaceNotFound (mc);
2776 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2778 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2781 public bool IsPossibleType (IMemberContext mc)
2783 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2786 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2788 int lookup_arity = Arity;
2789 bool errorMode = false;
2791 Block current_block = rc.CurrentBlock;
2792 INamedBlockVariable variable = null;
2793 bool variable_found = false;
2797 // Stage 1: binding to local variables or parameters
2799 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2801 if (current_block != null && lookup_arity == 0) {
2802 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2803 if (!variable.IsDeclared) {
2804 // We found local name in accessible block but it's not
2805 // initialized yet, maybe the user wanted to bind to something else
2807 variable_found = true;
2809 e = variable.CreateReferenceExpression (rc, loc);
2812 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2821 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2823 TypeSpec member_type = rc.CurrentType;
2824 for (; member_type != null; member_type = member_type.DeclaringType) {
2825 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2829 var me = e as MemberExpr;
2831 // The name matches a type, defer to ResolveAsTypeStep
2839 if (variable != null) {
2840 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2841 rc.Report.Error (844, loc,
2842 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2843 Name, me.GetSignatureForError ());
2847 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2848 // Leave it to overload resolution to report correct error
2850 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2851 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2855 // MemberLookup does not check accessors availability, this is actually needed for properties only
2857 var pe = me as PropertyExpr;
2860 // Break as there is no other overload available anyway
2861 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2862 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2865 pe.Getter = pe.PropertyInfo.Get;
2867 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2868 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2869 var p = (Property) pe.PropertyInfo.MemberDefinition;
2870 return new FieldExpr (p.BackingField, loc);
2873 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc)) {
2874 variable_found = true;
2878 pe.Setter = pe.PropertyInfo.Set;
2883 // TODO: It's used by EventExpr -> FieldExpr transformation only
2884 // TODO: Should go to MemberAccess
2885 me = me.ResolveMemberAccess (rc, null, null);
2888 targs.Resolve (rc, false);
2889 me.SetTypeArguments (rc, targs);
2896 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2898 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2899 if (IsPossibleTypeOrNamespace (rc)) {
2900 return ResolveAsTypeOrNamespace (rc, false);
2904 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2907 targs.Resolve (rc, false);
2909 var me = expr as MemberExpr;
2911 me.SetTypeArguments (rc, targs);
2916 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2917 return new NameOf (this);
2920 if (variable_found) {
2921 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2924 var tparams = rc.CurrentTypeParameters;
2925 if (tparams != null) {
2926 if (tparams.Find (Name) != null) {
2927 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2932 var ct = rc.CurrentType;
2934 if (ct.MemberDefinition.TypeParametersCount > 0) {
2935 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2936 if (ctp.Name == Name) {
2937 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2943 ct = ct.DeclaringType;
2944 } while (ct != null);
2947 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2948 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2950 rc.Report.SymbolRelatedToPreviousError (e.Type);
2951 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2955 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2957 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2958 return ErrorExpression.Instance;
2962 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2964 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2965 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2969 if (e is TypeExpr) {
2970 // TypeExpression does not have correct location
2971 if (e is TypeExpression)
2972 e = new TypeExpression (e.Type, loc);
2978 Error_NameDoesNotExist (rc);
2981 return ErrorExpression.Instance;
2984 if (rc.Module.Evaluator != null) {
2985 var fi = rc.Module.Evaluator.LookupField (Name);
2987 return new FieldExpr (fi.Item1, loc);
2995 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2997 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3002 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3003 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3007 if (right_side != null) {
3008 e = e.ResolveLValue (ec, right_side);
3016 public override object Accept (StructuralVisitor visitor)
3018 return visitor.Visit (this);
3023 /// Represents a namespace or a type. The name of the class was inspired by
3024 /// section 10.8.1 (Fully Qualified Names).
3026 public abstract class FullNamedExpression : Expression
3028 protected override void CloneTo (CloneContext clonectx, Expression target)
3030 // Do nothing, most unresolved type expressions cannot be
3031 // resolved to different type
3034 public override bool ContainsEmitWithAwait ()
3039 public override Expression CreateExpressionTree (ResolveContext ec)
3041 throw new NotSupportedException ("ET");
3044 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3047 // This is used to resolve the expression as a type, a null
3048 // value will be returned if the expression is not a type
3051 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3053 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3058 TypeExpr te = fne as TypeExpr;
3060 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3068 var dep = type.GetMissingDependencies ();
3070 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3073 if (type.Kind == MemberKind.Void) {
3074 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3078 // Obsolete checks cannot be done when resolving base context as they
3079 // require type dependencies to be set but we are in process of resolving them
3081 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3082 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3083 if (obsolete_attr != null && !mc.IsObsolete) {
3084 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3092 public override void Emit (EmitContext ec)
3094 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3095 GetSignatureForError ());
3100 /// Expression that evaluates to a type
3102 public abstract class TypeExpr : FullNamedExpression
3104 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3110 protected sealed override Expression DoResolve (ResolveContext ec)
3116 public override bool Equals (object obj)
3118 TypeExpr tobj = obj as TypeExpr;
3122 return Type == tobj.Type;
3125 public override int GetHashCode ()
3127 return Type.GetHashCode ();
3132 /// Fully resolved Expression that already evaluated to a type
3134 public class TypeExpression : TypeExpr
3136 public TypeExpression (TypeSpec t, Location l)
3139 eclass = ExprClass.Type;
3143 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3149 public class NamespaceExpression : FullNamedExpression
3151 readonly Namespace ns;
3153 public NamespaceExpression (Namespace ns, Location loc)
3156 this.Type = InternalType.Namespace;
3157 this.eclass = ExprClass.Namespace;
3161 public Namespace Namespace {
3167 protected override Expression DoResolve (ResolveContext rc)
3169 throw new NotImplementedException ();
3172 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3177 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3179 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3180 if (retval != null) {
3181 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3182 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3186 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3187 if (retval != null) {
3188 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3193 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3194 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3198 string assembly = null;
3199 string possible_name = Namespace.GetSignatureForError () + "." + name;
3201 // Only assembly unique name should be added
3202 switch (possible_name) {
3203 case "System.Drawing":
3204 case "System.Web.Services":
3207 case "System.Configuration":
3208 case "System.Data.Services":
3209 case "System.DirectoryServices":
3211 case "System.Net.Http":
3212 case "System.Numerics":
3213 case "System.Runtime.Caching":
3214 case "System.ServiceModel":
3215 case "System.Transactions":
3216 case "System.Web.Routing":
3217 case "System.Xml.Linq":
3219 assembly = possible_name;
3223 case "System.Linq.Expressions":
3224 assembly = "System.Core";
3227 case "System.Windows.Forms":
3228 case "System.Windows.Forms.Layout":
3229 assembly = "System.Windows.Forms";
3233 assembly = assembly == null ? "an" : "`" + assembly + "'";
3235 if (Namespace is GlobalRootNamespace) {
3236 ctx.Module.Compiler.Report.Error (400, loc,
3237 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3240 ctx.Module.Compiler.Report.Error (234, loc,
3241 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3242 name, GetSignatureForError (), assembly);
3246 public override string GetSignatureForError ()
3248 return ns.GetSignatureForError ();
3251 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3253 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3256 public override string ToString ()
3258 return Namespace.Name;
3263 /// This class denotes an expression which evaluates to a member
3264 /// of a struct or a class.
3266 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3268 protected bool conditional_access_receiver;
3271 // An instance expression associated with this member, if it's a
3272 // non-static member
3274 public Expression InstanceExpression;
3277 /// The name of this member.
3279 public abstract string Name {
3284 // When base.member is used
3286 public bool IsBase {
3287 get { return InstanceExpression is BaseThis; }
3291 /// Whether this is an instance member.
3293 public abstract bool IsInstance {
3298 /// Whether this is a static member.
3300 public abstract bool IsStatic {
3304 public abstract string KindName {
3308 public bool ConditionalAccess { get; set; }
3310 protected abstract TypeSpec DeclaringType {
3314 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3316 return InstanceExpression.Type;
3321 // Converts best base candidate for virtual method starting from QueriedBaseType
3323 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3326 // Only when base.member is used and method is virtual
3332 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3333 // means for base.member access we have to find the closest match after we found best candidate
3335 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3337 // The method could already be what we are looking for
3339 TypeSpec[] targs = null;
3340 if (method.DeclaringType != InstanceExpression.Type) {
3342 // Candidate can have inflated MVAR parameters and we need to find
3343 // base match for original definition not inflated parameter types
3345 var parameters = method.Parameters;
3346 if (method.Arity > 0) {
3347 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3348 var inflated = method.DeclaringType as InflatedTypeSpec;
3349 if (inflated != null) {
3350 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3354 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3355 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3356 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3357 if (base_override.IsGeneric)
3358 targs = method.TypeArguments;
3360 method = base_override;
3365 // When base access is used inside anonymous method/iterator/etc we need to
3366 // get back to the context of original type. We do it by emiting proxy
3367 // method in original class and rewriting base call to this compiler
3368 // generated method call which does the actual base invocation. This may
3369 // introduce redundant storey but with `this' only but it's tricky to avoid
3370 // at this stage as we don't know what expressions follow base
3372 if (rc.CurrentAnonymousMethod != null) {
3373 if (targs == null && method.IsGeneric) {
3374 targs = method.TypeArguments;
3375 method = method.GetGenericMethodDefinition ();
3378 if (method.Parameters.HasArglist)
3379 throw new NotImplementedException ("__arglist base call proxy");
3381 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3383 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3384 // get/set member expressions second call would fail to proxy because left expression
3385 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3386 // FIXME: The async check is another hack but will probably fail with mutators
3387 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3388 InstanceExpression = new This (loc).Resolve (rc);
3392 method = method.MakeGenericMethod (rc, targs);
3396 // Only base will allow this invocation to happen.
3398 if (method.IsAbstract) {
3399 rc.Report.SymbolRelatedToPreviousError (method);
3400 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3406 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3408 if (InstanceExpression == null)
3411 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3412 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3413 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3418 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3420 if (InstanceExpression == null)
3423 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3426 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3428 var ct = rc.CurrentType;
3429 if (ct == qualifier)
3432 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3435 qualifier = qualifier.GetDefinition ();
3436 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3443 public override bool ContainsEmitWithAwait ()
3445 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3448 public override bool HasConditionalAccess ()
3450 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3453 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3456 type = type.GetDefinition ();
3458 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3461 type = type.DeclaringType;
3462 } while (type != null);
3467 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3469 if (InstanceExpression != null) {
3470 InstanceExpression = InstanceExpression.Resolve (rc);
3471 CheckProtectedMemberAccess (rc, member);
3474 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3475 UnsafeError (rc, loc);
3478 var dep = member.GetMissingDependencies ();
3480 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3483 if (!rc.IsObsolete) {
3484 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3486 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3489 if (!(member is FieldSpec))
3490 member.MemberDefinition.SetIsUsed ();
3493 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3495 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3498 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3500 rc.Report.SymbolRelatedToPreviousError (member);
3501 rc.Report.Error (1540, loc,
3502 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3503 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3506 public override void FlowAnalysis (FlowAnalysisContext fc)
3508 if (InstanceExpression != null) {
3509 InstanceExpression.FlowAnalysis (fc);
3511 if (ConditionalAccess) {
3512 fc.BranchConditionalAccessDefiniteAssignment ();
3517 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3519 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3520 if (HasConditionalAccess ()) {
3521 conditional_access_receiver = true;
3522 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3527 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3529 if (!ResolveInstanceExpressionCore (rc, rhs))
3533 // Check intermediate value modification which won't have any effect
3535 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3536 var fexpr = InstanceExpression as FieldExpr;
3537 if (fexpr != null) {
3538 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3541 if (fexpr.IsStatic) {
3542 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3543 fexpr.GetSignatureForError ());
3545 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3546 fexpr.GetSignatureForError ());
3552 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3553 if (rc.CurrentInitializerVariable != null) {
3554 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3555 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3557 rc.Report.Error (1612, loc,
3558 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3559 InstanceExpression.GetSignatureForError ());
3565 var lvr = InstanceExpression as LocalVariableReference;
3568 if (!lvr.local_info.IsReadonly)
3571 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3572 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3579 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3582 if (InstanceExpression != null) {
3583 if (InstanceExpression is TypeExpr) {
3584 var t = InstanceExpression.Type;
3586 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3587 if (oa != null && !rc.IsObsolete) {
3588 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3591 t = t.DeclaringType;
3592 } while (t != null);
3594 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3595 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3596 rc.Report.Error (176, loc,
3597 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3598 GetSignatureForError ());
3602 InstanceExpression = null;
3608 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3609 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3610 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3611 rc.Report.Error (236, loc,
3612 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3613 GetSignatureForError ());
3615 var fe = this as FieldExpr;
3616 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3617 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3618 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3620 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3624 rc.Report.Error (120, loc,
3625 "An object reference is required to access non-static member `{0}'",
3626 GetSignatureForError ());
3630 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3634 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3635 rc.Report.Error (38, loc,
3636 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3637 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3640 InstanceExpression = new This (loc).Resolve (rc);
3644 var me = InstanceExpression as MemberExpr;
3646 me.ResolveInstanceExpressionCore (rc, rhs);
3648 var fe = me as FieldExpr;
3649 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3650 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3651 rc.Report.Warning (1690, 1, loc,
3652 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3653 me.GetSignatureForError ());
3660 // Additional checks for l-value member access
3663 if (InstanceExpression is UnboxCast) {
3664 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3671 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3673 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3674 ec.Report.Warning (1720, 1, left.Location,
3675 "Expression will always cause a `{0}'", "System.NullReferenceException");
3678 InstanceExpression = left;
3682 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3684 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3685 inst.Emit (ec, ConditionalAccess);
3687 if (prepare_for_load)
3688 ec.Emit (OpCodes.Dup);
3691 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3694 public class ExtensionMethodCandidates
3696 readonly NamespaceContainer container;
3697 readonly IList<MethodSpec> methods;
3699 readonly IMemberContext context;
3701 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3703 this.context = context;
3704 this.methods = methods;
3705 this.container = nsContainer;
3706 this.index = lookupIndex;
3709 public NamespaceContainer Container {
3715 public IMemberContext Context {
3721 public int LookupIndex {
3727 public IList<MethodSpec> Methods {
3735 // Represents a group of extension method candidates for whole namespace
3737 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3739 ExtensionMethodCandidates candidates;
3740 public Expression ExtensionExpression;
3742 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3743 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3745 this.candidates = candidates;
3746 this.ExtensionExpression = extensionExpr;
3749 public override bool IsStatic {
3750 get { return true; }
3753 public override void FlowAnalysis (FlowAnalysisContext fc)
3755 if (ConditionalAccess) {
3756 fc.BranchConditionalAccessDefiniteAssignment ();
3761 // For extension methodgroup we are not looking for base members but parent
3762 // namespace extension methods
3764 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3766 // TODO: candidates are null only when doing error reporting, that's
3767 // incorrect. We have to discover same extension methods in error mode
3768 if (candidates == null)
3771 int arity = type_arguments == null ? 0 : type_arguments.Count;
3773 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3774 if (candidates == null)
3777 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3780 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3783 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3785 // LAMESPEC: or implicit type parameter conversion
3787 return argType == extensionType ||
3788 TypeSpecComparer.IsEqual (argType, extensionType) ||
3789 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3790 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3793 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3795 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3797 // Not included in C#6
3799 ExtensionExpression = ExtensionExpression.Resolve (rc);
3800 if (ExtensionExpression == null)
3803 var argType = ExtensionExpression.Type;
3804 foreach (MethodSpec candidate in Candidates) {
3805 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3809 // TODO: Scan full hierarchy
3811 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3816 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3818 // We are already here
3822 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3824 if (arguments == null)
3825 arguments = new Arguments (1);
3827 ExtensionExpression = ExtensionExpression.Resolve (ec);
3828 if (ExtensionExpression == null)
3831 var cand = candidates;
3832 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3833 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3834 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3836 // Restore candidates in case we are running in probing mode
3839 // Store resolved argument and restore original arguments
3841 // Clean-up modified arguments for error reporting
3842 arguments.RemoveAt (0);
3846 var me = ExtensionExpression as MemberExpr;
3848 me.ResolveInstanceExpression (ec, null);
3849 var fe = me as FieldExpr;
3851 fe.Spec.MemberDefinition.SetIsUsed ();
3854 InstanceExpression = null;
3858 #region IErrorHandler Members
3860 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3865 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3867 rc.Report.SymbolRelatedToPreviousError (best);
3870 rc.Report.Error (1929, loc,
3871 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3872 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3874 rc.Report.Error (1928, loc,
3875 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3876 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3882 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3887 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3896 /// MethodGroupExpr represents a group of method candidates which
3897 /// can be resolved to the best method overload
3899 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3901 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3903 protected IList<MemberSpec> Methods;
3904 MethodSpec best_candidate;
3905 TypeSpec best_candidate_return;
3906 protected TypeArguments type_arguments;
3908 SimpleName simple_name;
3909 protected TypeSpec queried_type;
3911 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3915 this.type = InternalType.MethodGroup;
3917 eclass = ExprClass.MethodGroup;
3918 queried_type = type;
3921 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3922 : this (new MemberSpec[] { m }, type, loc)
3928 public MethodSpec BestCandidate {
3930 return best_candidate;
3934 public TypeSpec BestCandidateReturnType {
3936 return best_candidate_return;
3940 public IList<MemberSpec> Candidates {
3946 protected override TypeSpec DeclaringType {
3948 return queried_type;
3952 public bool IsConditionallyExcluded {
3954 return Methods == Excluded;
3958 public override bool IsInstance {
3960 if (best_candidate != null)
3961 return !best_candidate.IsStatic;
3967 public override bool IsSideEffectFree {
3969 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3973 public override bool IsStatic {
3975 if (best_candidate != null)
3976 return best_candidate.IsStatic;
3982 public override string KindName {
3983 get { return "method"; }
3986 public override string Name {
3988 if (best_candidate != null)
3989 return best_candidate.Name;
3992 return Methods.First ().Name;
3999 // When best candidate is already know this factory can be used
4000 // to avoid expensive overload resolution to be called
4002 // NOTE: InstanceExpression has to be set manually
4004 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4006 return new MethodGroupExpr (best, queriedType, loc) {
4007 best_candidate = best,
4008 best_candidate_return = best.ReturnType
4012 public override string GetSignatureForError ()
4014 if (best_candidate != null)
4015 return best_candidate.GetSignatureForError ();
4017 return Methods.First ().GetSignatureForError ();
4020 public override Expression CreateExpressionTree (ResolveContext ec)
4022 if (best_candidate == null) {
4023 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4027 if (IsConditionallyExcluded)
4028 ec.Report.Error (765, loc,
4029 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4031 if (ConditionalAccess)
4032 Error_NullShortCircuitInsideExpressionTree (ec);
4034 return new TypeOfMethod (best_candidate, loc);
4037 protected override Expression DoResolve (ResolveContext ec)
4039 this.eclass = ExprClass.MethodGroup;
4041 if (InstanceExpression != null) {
4042 InstanceExpression = InstanceExpression.Resolve (ec);
4043 if (InstanceExpression == null)
4050 public override void Emit (EmitContext ec)
4052 throw new NotSupportedException ();
4055 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4057 var call = new CallEmitter ();
4058 call.InstanceExpression = InstanceExpression;
4059 call.ConditionalAccess = ConditionalAccess;
4062 call.EmitStatement (ec, best_candidate, arguments, loc);
4064 call.Emit (ec, best_candidate, arguments, loc);
4067 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4069 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4070 Statement = statement
4073 EmitCall (ec, arguments, statement);
4075 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4078 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4080 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4081 Name, target.GetSignatureForError ());
4084 public bool HasAccessibleCandidate (ResolveContext rc)
4086 foreach (var candidate in Candidates) {
4087 if (candidate.IsAccessible (rc))
4094 public static bool IsExtensionMethodArgument (Expression expr)
4097 // LAMESPEC: No details about which expressions are not allowed
4099 return !(expr is TypeExpr) && !(expr is BaseThis);
4103 /// Find the Applicable Function Members (7.4.2.1)
4105 /// me: Method Group expression with the members to select.
4106 /// it might contain constructors or methods (or anything
4107 /// that maps to a method).
4109 /// Arguments: ArrayList containing resolved Argument objects.
4111 /// loc: The location if we want an error to be reported, or a Null
4112 /// location for "probing" purposes.
4114 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4115 /// that is the best match of me on Arguments.
4118 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4120 // TODO: causes issues with probing mode, remove explicit Kind check
4121 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4124 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4125 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4126 r.BaseMembersProvider = this;
4127 r.InstanceQualifier = this;
4130 if (cerrors != null)
4131 r.CustomErrors = cerrors;
4133 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4134 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4135 if (best_candidate == null) {
4136 if (!r.BestCandidateIsDynamic)
4139 if (simple_name != null && ec.IsStatic)
4140 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4145 // Overload resolver had to create a new method group, all checks bellow have already been executed
4146 if (r.BestCandidateNewMethodGroup != null)
4147 return r.BestCandidateNewMethodGroup;
4149 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4150 if (InstanceExpression != null) {
4151 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4152 InstanceExpression = null;
4154 if (simple_name != null && best_candidate.IsStatic) {
4155 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4158 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4162 ResolveInstanceExpression (ec, null);
4165 var base_override = CandidateToBaseOverride (ec, best_candidate);
4166 if (base_override == best_candidate) {
4167 best_candidate_return = r.BestCandidateReturnType;
4169 best_candidate = base_override;
4170 best_candidate_return = best_candidate.ReturnType;
4173 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4174 ConstraintChecker cc = new ConstraintChecker (ec);
4175 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4179 // Additional check for possible imported base override method which
4180 // could not be done during IsOverrideMethodBaseTypeAccessible
4182 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4183 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4184 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4185 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4188 // Speed up the check by not doing it on disallowed targets
4189 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4195 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4197 var fe = left as FieldExpr;
4200 // Using method-group on struct fields makes the struct assigned. I am not sure
4201 // why but that's what .net does
4203 fe.Spec.MemberDefinition.SetIsAssigned ();
4206 simple_name = original;
4207 return base.ResolveMemberAccess (ec, left, original);
4210 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4212 type_arguments = ta;
4215 #region IBaseMembersProvider Members
4217 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4219 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4222 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4224 if (queried_type == member.DeclaringType)
4227 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4228 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4232 // Extension methods lookup after ordinary methods candidates failed to apply
4234 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4236 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4239 if (!IsExtensionMethodArgument (InstanceExpression))
4242 int arity = type_arguments == null ? 0 : type_arguments.Count;
4243 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4244 if (methods == null)
4247 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4248 emg.SetTypeArguments (rc, type_arguments);
4255 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4257 public ConstructorInstanceQualifier (TypeSpec type)
4260 InstanceType = type;
4263 public TypeSpec InstanceType { get; private set; }
4265 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4267 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4271 public struct OverloadResolver
4274 public enum Restrictions
4278 ProbingOnly = 1 << 1,
4279 CovariantDelegate = 1 << 2,
4280 NoBaseMembers = 1 << 3,
4281 BaseMembersIncluded = 1 << 4,
4282 GetEnumeratorLookup = 1 << 5
4285 public interface IBaseMembersProvider
4287 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4288 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4289 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4292 public interface IErrorHandler
4294 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4295 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4296 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4297 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4300 public interface IInstanceQualifier
4302 TypeSpec InstanceType { get; }
4303 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4306 sealed class NoBaseMembers : IBaseMembersProvider
4308 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4310 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4315 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4320 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4326 struct AmbiguousCandidate
4328 public readonly MemberSpec Member;
4329 public readonly bool Expanded;
4330 public readonly AParametersCollection Parameters;
4332 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4335 Parameters = parameters;
4336 Expanded = expanded;
4341 IList<MemberSpec> members;
4342 TypeArguments type_arguments;
4343 IBaseMembersProvider base_provider;
4344 IErrorHandler custom_errors;
4345 IInstanceQualifier instance_qualifier;
4346 Restrictions restrictions;
4347 MethodGroupExpr best_candidate_extension_group;
4348 TypeSpec best_candidate_return_type;
4350 SessionReportPrinter lambda_conv_msgs;
4352 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4353 : this (members, null, restrictions, loc)
4357 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4360 if (members == null || members.Count == 0)
4361 throw new ArgumentException ("empty members set");
4363 this.members = members;
4365 type_arguments = targs;
4366 this.restrictions = restrictions;
4367 if (IsDelegateInvoke)
4368 this.restrictions |= Restrictions.NoBaseMembers;
4370 base_provider = NoBaseMembers.Instance;
4375 public IBaseMembersProvider BaseMembersProvider {
4377 return base_provider;
4380 base_provider = value;
4384 public bool BestCandidateIsDynamic { get; set; }
4387 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4389 public MethodGroupExpr BestCandidateNewMethodGroup {
4391 return best_candidate_extension_group;
4396 // Return type can be different between best candidate and closest override
4398 public TypeSpec BestCandidateReturnType {
4400 return best_candidate_return_type;
4404 public IErrorHandler CustomErrors {
4406 return custom_errors;
4409 custom_errors = value;
4413 TypeSpec DelegateType {
4415 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4416 throw new InternalErrorException ("Not running in delegate mode", loc);
4418 return members [0].DeclaringType;
4422 public IInstanceQualifier InstanceQualifier {
4424 return instance_qualifier;
4427 instance_qualifier = value;
4431 bool IsProbingOnly {
4433 return (restrictions & Restrictions.ProbingOnly) != 0;
4437 bool IsDelegateInvoke {
4439 return (restrictions & Restrictions.DelegateInvoke) != 0;
4446 // 7.4.3.3 Better conversion from expression
4447 // Returns : 1 if a->p is better,
4448 // 2 if a->q is better,
4449 // 0 if neither is better
4451 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4453 TypeSpec argument_type = a.Type;
4456 // If argument is an anonymous function
4458 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4460 // p and q are delegate types or expression tree types
4462 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4463 if (q.MemberDefinition != p.MemberDefinition) {
4468 // Uwrap delegate from Expression<T>
4470 q = TypeManager.GetTypeArguments (q)[0];
4471 p = TypeManager.GetTypeArguments (p)[0];
4474 var p_m = Delegate.GetInvokeMethod (p);
4475 var q_m = Delegate.GetInvokeMethod (q);
4478 // With identical parameter lists
4480 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4488 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4490 if (p.Kind == MemberKind.Void) {
4491 return q.Kind != MemberKind.Void ? 2 : 0;
4495 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4497 if (q.Kind == MemberKind.Void) {
4498 return p.Kind != MemberKind.Void ? 1: 0;
4501 var am = (AnonymousMethodExpression) a.Expr;
4504 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4505 // better conversion is performed between underlying types Y1 and Y2
4507 if (p.IsGenericTask || q.IsGenericTask) {
4508 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4509 q = q.TypeArguments[0];
4510 p = p.TypeArguments[0];
4516 // An inferred return type X exists for E in the context of that parameter list, and
4517 // the conversion from X to Y1 is better than the conversion from X to Y2
4519 argument_type = am.InferReturnType (ec, null, orig_q);
4520 if (argument_type == null) {
4521 // TODO: Can this be hit?
4525 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4526 argument_type = ec.BuiltinTypes.Object;
4530 if (argument_type == p)
4533 if (argument_type == q)
4537 // The parameters are identicial and return type is not void, use better type conversion
4538 // on return type to determine better one
4540 return BetterTypeConversion (ec, p, q);
4544 // 7.4.3.4 Better conversion from type
4546 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4548 if (p == null || q == null)
4549 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4551 switch (p.BuiltinType) {
4552 case BuiltinTypeSpec.Type.Int:
4553 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4556 case BuiltinTypeSpec.Type.Long:
4557 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4560 case BuiltinTypeSpec.Type.SByte:
4561 switch (q.BuiltinType) {
4562 case BuiltinTypeSpec.Type.Byte:
4563 case BuiltinTypeSpec.Type.UShort:
4564 case BuiltinTypeSpec.Type.UInt:
4565 case BuiltinTypeSpec.Type.ULong:
4569 case BuiltinTypeSpec.Type.Short:
4570 switch (q.BuiltinType) {
4571 case BuiltinTypeSpec.Type.UShort:
4572 case BuiltinTypeSpec.Type.UInt:
4573 case BuiltinTypeSpec.Type.ULong:
4577 case BuiltinTypeSpec.Type.Dynamic:
4578 // Dynamic is never better
4582 switch (q.BuiltinType) {
4583 case BuiltinTypeSpec.Type.Int:
4584 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4587 case BuiltinTypeSpec.Type.Long:
4588 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4591 case BuiltinTypeSpec.Type.SByte:
4592 switch (p.BuiltinType) {
4593 case BuiltinTypeSpec.Type.Byte:
4594 case BuiltinTypeSpec.Type.UShort:
4595 case BuiltinTypeSpec.Type.UInt:
4596 case BuiltinTypeSpec.Type.ULong:
4600 case BuiltinTypeSpec.Type.Short:
4601 switch (p.BuiltinType) {
4602 case BuiltinTypeSpec.Type.UShort:
4603 case BuiltinTypeSpec.Type.UInt:
4604 case BuiltinTypeSpec.Type.ULong:
4608 case BuiltinTypeSpec.Type.Dynamic:
4609 // Dynamic is never better
4613 // FIXME: handle lifted operators
4615 // TODO: this is expensive
4616 Expression p_tmp = new EmptyExpression (p);
4617 Expression q_tmp = new EmptyExpression (q);
4619 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4620 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4622 if (p_to_q && !q_to_p)
4625 if (q_to_p && !p_to_q)
4632 /// Determines "Better function" between candidate
4633 /// and the current best match
4636 /// Returns a boolean indicating :
4637 /// false if candidate ain't better
4638 /// true if candidate is better than the current best match
4640 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4641 MemberSpec best, AParametersCollection bparam, bool best_params)
4643 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4644 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4646 bool better_at_least_one = false;
4647 bool are_equivalent = true;
4648 int args_count = args == null ? 0 : args.Count;
4652 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4655 // Default arguments are ignored for better decision
4656 if (a.IsDefaultArgument)
4660 // When comparing named argument the parameter type index has to be looked up
4661 // in original parameter set (override version for virtual members)
4663 NamedArgument na = a as NamedArgument;
4665 int idx = cparam.GetParameterIndexByName (na.Name);
4666 ct = candidate_pd.Types[idx];
4667 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4668 ct = TypeManager.GetElementType (ct);
4670 idx = bparam.GetParameterIndexByName (na.Name);
4671 bt = best_pd.Types[idx];
4672 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4673 bt = TypeManager.GetElementType (bt);
4675 ct = candidate_pd.Types[c_idx];
4676 bt = best_pd.Types[b_idx];
4678 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4679 ct = TypeManager.GetElementType (ct);
4683 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4684 bt = TypeManager.GetElementType (bt);
4689 if (TypeSpecComparer.IsEqual (ct, bt))
4692 are_equivalent = false;
4693 int result = BetterExpressionConversion (ec, a, ct, bt);
4695 // for each argument, the conversion to 'ct' should be no worse than
4696 // the conversion to 'bt'.
4700 // for at least one argument, the conversion to 'ct' should be better than
4701 // the conversion to 'bt'.
4703 better_at_least_one = true;
4706 if (better_at_least_one)
4710 // Tie-breaking rules are applied only for equivalent parameter types
4712 if (!are_equivalent) {
4714 // LAMESPEC: A candidate with less default parameters is still better when there
4715 // is no better expression conversion
4717 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4725 // If candidate is applicable in its normal form and best has a params array and is applicable
4726 // only in its expanded form, then candidate is better
4728 if (candidate_params != best_params)
4729 return !candidate_params;
4732 // We have not reached end of parameters list due to params or used default parameters
4734 while (j < candidate_pd.Count && j < best_pd.Count) {
4735 var cand_param = candidate_pd.FixedParameters [j];
4736 var best_param = best_pd.FixedParameters [j];
4738 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4739 return cand_param.HasDefaultValue;
4741 if (candidate_pd.Count == best_pd.Count) {
4745 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4746 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4749 if (cand_param.HasDefaultValue) {
4755 // Neither is better when not all arguments are provided
4757 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4758 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4759 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4767 if (candidate_pd.Count != best_pd.Count)
4768 return candidate_pd.Count < best_pd.Count;
4771 // One is a non-generic method and second is a generic method, then non-generic is better
4773 if (best.IsGeneric != candidate.IsGeneric)
4774 return best.IsGeneric;
4777 // Both methods have the same number of parameters, and the parameters have equal types
4778 // Pick the "more specific" signature using rules over original (non-inflated) types
4780 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4781 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4783 bool specific_at_least_once = false;
4784 for (j = 0; j < args_count; ++j) {
4785 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4787 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4788 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4790 ct = candidate_def_pd.Types[j];
4791 bt = best_def_pd.Types[j];
4796 TypeSpec specific = MoreSpecific (ct, bt);
4800 specific_at_least_once = true;
4803 if (specific_at_least_once)
4809 static bool CheckInflatedArguments (MethodSpec ms)
4811 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4814 // Setup constraint checker for probing only
4815 ConstraintChecker cc = new ConstraintChecker (null);
4817 var mp = ms.Parameters.Types;
4818 for (int i = 0; i < mp.Length; ++i) {
4819 var type = mp[i] as InflatedTypeSpec;
4823 var targs = type.TypeArguments;
4824 if (targs.Length == 0)
4827 // TODO: Checking inflated MVAR arguments should be enough
4828 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4835 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4837 rc.Report.Error (1729, loc,
4838 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4839 type.GetSignatureForError (), argCount.ToString ());
4843 // Determines if the candidate method is applicable to the given set of arguments
4844 // There could be two different set of parameters for same candidate where one
4845 // is the closest override for default values and named arguments checks and second
4846 // one being the virtual base for the parameter types and modifiers.
4848 // A return value rates candidate method compatibility,
4850 // 0 = the best, int.MaxValue = the worst
4852 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)
4855 // Each step has allocated 10 values, it can overflow for
4856 // more than 10 arguments but that's ok as it's used for
4857 // better error reporting only
4859 const int ArgumentCountMismatch = 1000000000;
4860 const int NamedArgumentsMismatch = 100000000;
4861 const int DefaultArgumentMismatch = 10000000;
4862 const int UnexpectedTypeArguments = 1000000;
4863 const int TypeArgumentsMismatch = 100000;
4864 const int InflatedTypesMismatch = 10000;
4866 // Parameters of most-derived type used mainly for named and optional parameters
4867 var pd = pm.Parameters;
4869 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4870 // params modifier instead of most-derived type
4871 var cpd = ((IParametersMember) candidate).Parameters;
4872 int param_count = pd.Count;
4873 int optional_count = 0;
4875 Arguments orig_args = arguments;
4877 if (arg_count != param_count) {
4879 // No arguments expansion when doing exact match for delegates
4881 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4882 for (int i = 0; i < pd.Count; ++i) {
4883 if (pd.FixedParameters[i].HasDefaultValue) {
4884 optional_count = pd.Count - i;
4890 if (optional_count != 0) {
4891 // Readjust expected number when params used
4892 if (cpd.HasParams) {
4894 if (arg_count < param_count)
4896 } else if (arg_count > param_count) {
4897 int args_gap = System.Math.Abs (arg_count - param_count);
4898 return ArgumentCountMismatch + args_gap;
4899 } else if (arg_count < param_count - optional_count) {
4900 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4901 return ArgumentCountMismatch + args_gap;
4903 } else if (arg_count != param_count) {
4904 int args_gap = System.Math.Abs (arg_count - param_count);
4906 return ArgumentCountMismatch + args_gap;
4907 if (arg_count < param_count - 1)
4908 return ArgumentCountMismatch + args_gap;
4911 // Resize to fit optional arguments
4912 if (optional_count != 0) {
4913 if (arguments == null) {
4914 arguments = new Arguments (optional_count);
4916 // Have to create a new container, so the next run can do same
4917 var resized = new Arguments (param_count);
4918 resized.AddRange (arguments);
4919 arguments = resized;
4922 for (int i = arg_count; i < param_count; ++i)
4923 arguments.Add (null);
4927 if (arg_count > 0) {
4929 // Shuffle named arguments to the right positions if there are any
4931 if (arguments[arg_count - 1] is NamedArgument) {
4932 arg_count = arguments.Count;
4934 for (int i = 0; i < arg_count; ++i) {
4935 bool arg_moved = false;
4937 NamedArgument na = arguments[i] as NamedArgument;
4941 int index = pd.GetParameterIndexByName (na.Name);
4943 // Named parameter not found
4945 return NamedArgumentsMismatch - i;
4947 // already reordered
4952 if (index >= param_count) {
4953 // When using parameters which should not be available to the user
4954 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4957 arguments.Add (null);
4961 if (index == arg_count)
4962 return NamedArgumentsMismatch - i - 1;
4964 temp = arguments [index];
4966 // The slot has been taken by positional argument
4967 if (temp != null && !(temp is NamedArgument))
4972 arguments = arguments.MarkOrderedArgument (na);
4976 if (arguments == orig_args) {
4977 arguments = new Arguments (orig_args.Count);
4978 arguments.AddRange (orig_args);
4981 arguments[index] = arguments[i];
4982 arguments[i] = temp;
4989 arg_count = arguments.Count;
4991 } else if (arguments != null) {
4992 arg_count = arguments.Count;
4996 // Don't do any expensive checks when the candidate cannot succeed
4998 if (arg_count != param_count && !cpd.HasParams)
4999 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5001 var dep = candidate.GetMissingDependencies ();
5003 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5008 // 1. Handle generic method using type arguments when specified or type inference
5011 var ms = candidate as MethodSpec;
5012 if (ms != null && ms.IsGeneric) {
5013 if (type_arguments != null) {
5014 var g_args_count = ms.Arity;
5015 if (g_args_count != type_arguments.Count)
5016 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5018 if (type_arguments.Arguments != null)
5019 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5022 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5023 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5024 // candidate was found use the set to report more details about what was wrong with lambda body.
5025 // The general idea is to distinguish between code errors and errors caused by
5026 // trial-and-error type inference
5028 if (lambda_conv_msgs == null) {
5029 for (int i = 0; i < arg_count; i++) {
5030 Argument a = arguments[i];
5034 var am = a.Expr as AnonymousMethodExpression;
5036 if (lambda_conv_msgs == null)
5037 lambda_conv_msgs = new SessionReportPrinter ();
5039 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5044 var ti = new TypeInference (arguments);
5045 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5048 return TypeArgumentsMismatch - ti.InferenceScore;
5051 // Clear any error messages when the result was success
5053 if (lambda_conv_msgs != null)
5054 lambda_conv_msgs.ClearSession ();
5056 if (i_args.Length != 0) {
5058 for (int i = 0; i < i_args.Length; ++i) {
5059 var ta = i_args [i];
5060 if (!ta.IsAccessible (ec))
5061 return TypeArgumentsMismatch - i;
5065 ms = ms.MakeGenericMethod (ec, i_args);
5070 // Type arguments constraints have to match for the method to be applicable
5072 if (!CheckInflatedArguments (ms)) {
5074 return InflatedTypesMismatch;
5078 // We have a generic return type and at same time the method is override which
5079 // means we have to also inflate override return type in case the candidate is
5080 // best candidate and override return type is different to base return type.
5082 // virtual Foo<T, object> with override Foo<T, dynamic>
5084 if (candidate != pm) {
5085 MethodSpec override_ms = (MethodSpec) pm;
5086 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5087 returnType = inflator.Inflate (returnType);
5089 returnType = ms.ReturnType;
5096 if (type_arguments != null)
5097 return UnexpectedTypeArguments;
5103 // 2. Each argument has to be implicitly convertible to method parameter
5105 Parameter.Modifier p_mod = 0;
5108 for (int i = 0; i < arg_count; i++) {
5109 Argument a = arguments[i];
5111 var fp = pd.FixedParameters[i];
5112 if (!fp.HasDefaultValue) {
5113 arguments = orig_args;
5114 return arg_count * 2 + 2;
5118 // Get the default value expression, we can use the same expression
5119 // if the type matches
5121 Expression e = fp.DefaultValue;
5123 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5125 // Restore for possible error reporting
5126 for (int ii = i; ii < arg_count; ++ii)
5127 arguments.RemoveAt (i);
5129 return (arg_count - i) * 2 + 1;
5133 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5135 // LAMESPEC: Attributes can be mixed together with build-in priority
5137 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5138 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5139 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5140 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5141 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5142 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5146 arguments[i] = new Argument (e, Argument.AType.Default);
5150 if (p_mod != Parameter.Modifier.PARAMS) {
5151 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5153 } else if (!params_expanded_form) {
5154 params_expanded_form = true;
5155 pt = ((ElementTypeSpec) pt).Element;
5161 if (!params_expanded_form) {
5162 if (a.IsExtensionType) {
5163 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5168 score = IsArgumentCompatible (ec, a, p_mod, pt);
5171 dynamicArgument = true;
5176 // It can be applicable in expanded form (when not doing exact match like for delegates)
5178 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5179 if (!params_expanded_form) {
5180 pt = ((ElementTypeSpec) pt).Element;
5184 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5187 params_expanded_form = true;
5188 dynamicArgument = true;
5189 } else if (score == 0 || arg_count > pd.Count) {
5190 params_expanded_form = true;
5195 if (params_expanded_form)
5197 return (arg_count - i) * 2 + score;
5202 // Restore original arguments for dynamic binder to keep the intention of original source code
5204 if (dynamicArgument)
5205 arguments = orig_args;
5210 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5212 if (e is Constant && e.Type == ptype)
5216 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5218 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5219 e = new MemberAccess (new MemberAccess (new MemberAccess (
5220 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5221 } else if (e is Constant) {
5223 // Handles int to int? conversions, DefaultParameterValue check
5225 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5229 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5232 return e.Resolve (ec);
5236 // Tests argument compatibility with the parameter
5237 // The possible return values are
5239 // 1 - modifier mismatch
5240 // 2 - type mismatch
5241 // -1 - dynamic binding required
5243 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5246 // Types have to be identical when ref or out modifer
5247 // is used and argument is not of dynamic type
5249 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5250 var arg_type = argument.Type;
5252 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5254 // Using dynamic for ref/out parameter can still succeed at runtime
5256 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5262 if (arg_type != parameter) {
5263 if (arg_type == InternalType.VarOutType)
5267 // Do full equality check after quick path
5269 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5271 // Using dynamic for ref/out parameter can still succeed at runtime
5273 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5281 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5285 // Use implicit conversion in all modes to return same candidates when the expression
5286 // is used as argument or delegate conversion
5288 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5289 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5296 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5298 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5300 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5303 var ac_p = p as ArrayContainer;
5305 var ac_q = q as ArrayContainer;
5309 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5310 if (specific == ac_p.Element)
5312 if (specific == ac_q.Element)
5314 } else if (p.IsGeneric && q.IsGeneric) {
5315 var pargs = TypeManager.GetTypeArguments (p);
5316 var qargs = TypeManager.GetTypeArguments (q);
5318 bool p_specific_at_least_once = false;
5319 bool q_specific_at_least_once = false;
5321 for (int i = 0; i < pargs.Length; i++) {
5322 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5323 if (specific == pargs[i])
5324 p_specific_at_least_once = true;
5325 if (specific == qargs[i])
5326 q_specific_at_least_once = true;
5329 if (p_specific_at_least_once && !q_specific_at_least_once)
5331 if (!p_specific_at_least_once && q_specific_at_least_once)
5339 // Find the best method from candidate list
5341 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5343 List<AmbiguousCandidate> ambiguous_candidates = null;
5345 MemberSpec best_candidate;
5346 Arguments best_candidate_args = null;
5347 bool best_candidate_params = false;
5348 bool best_candidate_dynamic = false;
5349 int best_candidate_rate;
5350 IParametersMember best_parameter_member = null;
5352 int args_count = args != null ? args.Count : 0;
5354 Arguments candidate_args = args;
5355 bool error_mode = false;
5356 MemberSpec invocable_member = null;
5357 int applicable_candidates = 0;
5360 best_candidate = null;
5361 best_candidate_rate = int.MaxValue;
5363 var type_members = members;
5365 for (int i = 0; i < type_members.Count; ++i) {
5366 var member = type_members[i];
5369 // Methods in a base class are not candidates if any method in a derived
5370 // class is applicable
5372 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5376 if (!member.IsAccessible (rc))
5379 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5382 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5383 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5388 IParametersMember pm = member as IParametersMember;
5391 // Will use it later to report ambiguity between best method and invocable member
5393 if (Invocation.IsMemberInvocable (member))
5394 invocable_member = member;
5400 // Overload resolution is looking for base member but using parameter names
5401 // and default values from the closest member. That means to do expensive lookup
5402 // for the closest override for virtual or abstract members
5404 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5405 var override_params = base_provider.GetOverrideMemberParameters (member);
5406 if (override_params != null)
5407 pm = override_params;
5411 // Check if the member candidate is applicable
5413 bool params_expanded_form = false;
5414 bool dynamic_argument = false;
5415 TypeSpec rt = pm.MemberType;
5416 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5418 if (lambda_conv_msgs != null)
5419 lambda_conv_msgs.EndSession ();
5422 // How does it score compare to others
5424 if (candidate_rate < best_candidate_rate) {
5426 // Fatal error (missing dependency), cannot continue
5427 if (candidate_rate < 0)
5430 applicable_candidates = 1;
5431 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5432 // Only parameterless methods are considered
5434 best_candidate_rate = candidate_rate;
5435 best_candidate = member;
5436 best_candidate_args = candidate_args;
5437 best_candidate_params = params_expanded_form;
5438 best_candidate_dynamic = dynamic_argument;
5439 best_parameter_member = pm;
5440 best_candidate_return_type = rt;
5442 } else if (candidate_rate == 0) {
5444 // The member look is done per type for most operations but sometimes
5445 // it's not possible like for binary operators overload because they
5446 // are unioned between 2 sides
5448 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5449 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5453 ++applicable_candidates;
5455 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5457 // We pack all interface members into top level type which makes the overload resolution
5458 // more complicated for interfaces. We compensate it by removing methods with same
5459 // signature when building the cache hence this path should not really be hit often
5462 // interface IA { void Foo (int arg); }
5463 // interface IB : IA { void Foo (params int[] args); }
5465 // IB::Foo is the best overload when calling IB.Foo (1)
5468 if (ambiguous_candidates != null) {
5469 foreach (var amb_cand in ambiguous_candidates) {
5470 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5479 ambiguous_candidates = null;
5482 // Is the new candidate better
5483 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5487 best_candidate = member;
5488 best_candidate_args = candidate_args;
5489 best_candidate_params = params_expanded_form;
5490 best_candidate_dynamic = dynamic_argument;
5491 best_parameter_member = pm;
5492 best_candidate_return_type = rt;
5494 // It's not better but any other found later could be but we are not sure yet
5495 if (ambiguous_candidates == null)
5496 ambiguous_candidates = new List<AmbiguousCandidate> ();
5498 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5502 // Restore expanded arguments
5503 candidate_args = args;
5505 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5508 // We've found exact match
5510 if (best_candidate_rate == 0)
5514 // Try extension methods lookup when no ordinary method match was found and provider enables it
5517 var emg = base_provider.LookupExtensionMethod (rc);
5519 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5521 best_candidate_extension_group = emg;
5522 return (T) (MemberSpec) emg.BestCandidate;
5527 // Don't run expensive error reporting mode for probing
5534 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5537 lambda_conv_msgs = null;
5542 // No best member match found, report an error
5544 if (best_candidate_rate != 0 || error_mode) {
5545 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5549 if (best_candidate_dynamic) {
5550 if (args[0].IsExtensionType) {
5551 rc.Report.Error (1973, loc,
5552 "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",
5553 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5557 // Check type constraints only when explicit type arguments are used
5559 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5560 MethodSpec bc = best_candidate as MethodSpec;
5561 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5562 ConstraintChecker cc = new ConstraintChecker (rc);
5563 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5567 BestCandidateIsDynamic = true;
5572 // These flags indicates we are running delegate probing conversion. No need to
5573 // do more expensive checks
5575 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5576 return (T) best_candidate;
5578 if (ambiguous_candidates != null) {
5580 // Now check that there are no ambiguities i.e the selected method
5581 // should be better than all the others
5583 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5584 var candidate = ambiguous_candidates [ix];
5586 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5587 var ambiguous = candidate.Member;
5588 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5589 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5590 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5591 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5592 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5595 return (T) best_candidate;
5600 if (invocable_member != null && !IsProbingOnly) {
5601 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5602 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5603 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5604 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5608 // And now check if the arguments are all
5609 // compatible, perform conversions if
5610 // necessary etc. and return if everything is
5613 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5616 if (best_candidate == null)
5620 // Don't run possibly expensive checks in probing mode
5622 if (!IsProbingOnly && !rc.IsInProbingMode) {
5624 // Check ObsoleteAttribute on the best method
5626 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5627 if (oa != null && !rc.IsObsolete)
5628 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5630 best_candidate.MemberDefinition.SetIsUsed ();
5633 args = best_candidate_args;
5634 return (T) best_candidate;
5637 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5639 return ResolveMember<MethodSpec> (rc, ref args);
5642 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5643 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5645 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5648 if (a.Type == InternalType.ErrorType)
5651 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5652 ec.Report.SymbolRelatedToPreviousError (method);
5653 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5654 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5655 TypeManager.CSharpSignature (method));
5658 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5659 TypeManager.CSharpSignature (method));
5660 } else if (IsDelegateInvoke) {
5661 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5662 DelegateType.GetSignatureForError ());
5664 ec.Report.SymbolRelatedToPreviousError (method);
5665 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5666 method.GetSignatureForError ());
5669 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5671 string index = (idx + 1).ToString ();
5672 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5673 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5674 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5675 index, Parameter.GetModifierSignature (a.Modifier));
5677 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5678 index, Parameter.GetModifierSignature (mod));
5680 string p1 = a.GetSignatureForError ();
5681 string p2 = paramType.GetSignatureForError ();
5684 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5685 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5688 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5689 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5690 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5693 ec.Report.Error (1503, a.Expr.Location,
5694 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5699 // We have failed to find exact match so we return error info about the closest match
5701 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5703 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5704 int arg_count = args == null ? 0 : args.Count;
5706 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5707 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5708 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5712 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5717 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5718 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5719 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5723 // For candidates which match on parameters count report more details about incorrect arguments
5726 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5727 // Reject any inaccessible member
5728 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5729 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5730 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5734 var ms = best_candidate as MethodSpec;
5735 if (ms != null && ms.IsGeneric) {
5736 bool constr_ok = true;
5737 if (ms.TypeArguments != null)
5738 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5740 if (ta_count == 0 && ms.TypeArguments == null) {
5741 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5745 rc.Report.Error (411, loc,
5746 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5747 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5754 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5760 // We failed to find any method with correct argument count, report best candidate
5762 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5765 if (best_candidate.Kind == MemberKind.Constructor) {
5766 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5767 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5768 } else if (IsDelegateInvoke) {
5769 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5770 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5771 DelegateType.GetSignatureForError (), arg_count.ToString ());
5773 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5774 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5775 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5776 name, arg_count.ToString ());
5780 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5782 var p = ((IParametersMember)best_candidate).Parameters;
5787 for (int i = p.Count - 1; i != 0; --i) {
5788 var fp = p.FixedParameters [i];
5789 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5799 foreach (var arg in args) {
5800 var na = arg as NamedArgument;
5804 if (na.Name == name) {
5813 return args.Count + 1 == pm.Parameters.Count;
5816 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5818 var pd = pm.Parameters;
5819 var cpd = ((IParametersMember) member).Parameters;
5820 var ptypes = cpd.Types;
5822 Parameter.Modifier p_mod = 0;
5824 int a_idx = 0, a_pos = 0;
5826 ArrayInitializer params_initializers = null;
5827 bool has_unsafe_arg = pm.MemberType.IsPointer;
5828 int arg_count = args == null ? 0 : args.Count;
5830 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5835 if (p_mod != Parameter.Modifier.PARAMS) {
5836 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5838 has_unsafe_arg |= pt.IsPointer;
5840 if (p_mod == Parameter.Modifier.PARAMS) {
5841 if (chose_params_expanded) {
5842 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5843 pt = TypeManager.GetElementType (pt);
5849 // Types have to be identical when ref or out modifer is used
5851 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5852 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5855 var arg_type = a.Type;
5859 if (arg_type == InternalType.VarOutType) {
5861 // Set underlying variable type based on parameter type
5863 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5867 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5871 NamedArgument na = a as NamedArgument;
5873 int name_index = pd.GetParameterIndexByName (na.Name);
5874 if (name_index < 0 || name_index >= pd.Count) {
5875 if (IsDelegateInvoke) {
5876 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5877 ec.Report.Error (1746, na.Location,
5878 "The delegate `{0}' does not contain a parameter named `{1}'",
5879 DelegateType.GetSignatureForError (), na.Name);
5881 ec.Report.SymbolRelatedToPreviousError (member);
5882 ec.Report.Error (1739, na.Location,
5883 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5884 TypeManager.CSharpSignature (member), na.Name);
5886 } else if (args[name_index] != a && args[name_index] != null) {
5887 if (IsDelegateInvoke)
5888 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5890 ec.Report.SymbolRelatedToPreviousError (member);
5892 ec.Report.Error (1744, na.Location,
5893 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5898 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5901 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5902 if (a.IsExtensionType) {
5903 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5904 // CS1061 but that still better than confusing CS0123
5905 var ma = new MemberAccess (a.Expr, member.Name, loc);
5906 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5908 custom_errors.NoArgumentMatch (ec, member);
5914 if (a.IsExtensionType) {
5915 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5918 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5920 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5923 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5930 // Convert params arguments to an array initializer
5932 if (params_initializers != null) {
5933 // we choose to use 'a.Expr' rather than 'conv' so that
5934 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5935 params_initializers.Add (a.Expr);
5936 args.RemoveAt (a_idx--);
5942 // Update the argument with the implicit conversion
5946 if (a_idx != arg_count) {
5948 // Convert all var out argument to error type for less confusing error reporting
5949 // when no matching overload is found
5951 for (; a_idx < arg_count; a_idx++) {
5952 var arg = args [a_idx];
5956 if (arg.Type == InternalType.VarOutType) {
5957 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5961 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5966 // Fill not provided arguments required by params modifier
5968 if (params_initializers == null && arg_count + 1 == pd.Count) {
5970 args = new Arguments (1);
5972 pt = ptypes[pd.Count - 1];
5973 pt = TypeManager.GetElementType (pt);
5974 has_unsafe_arg |= pt.IsPointer;
5975 params_initializers = new ArrayInitializer (0, loc);
5979 // Append an array argument with all params arguments
5981 if (params_initializers != null) {
5982 args.Add (new Argument (
5983 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5987 if (has_unsafe_arg && !ec.IsUnsafe) {
5988 Expression.UnsafeError (ec, loc);
5992 // We could infer inaccesible type arguments
5994 if (type_arguments == null && member.IsGeneric) {
5995 var ms = (MethodSpec) member;
5996 foreach (var ta in ms.TypeArguments) {
5997 if (!ta.IsAccessible (ec)) {
5998 ec.Report.SymbolRelatedToPreviousError (ta);
5999 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6009 public class ConstantExpr : MemberExpr
6011 readonly ConstSpec constant;
6013 public ConstantExpr (ConstSpec constant, Location loc)
6015 this.constant = constant;
6019 public override string Name {
6020 get { throw new NotImplementedException (); }
6023 public override string KindName {
6024 get { return "constant"; }
6027 public override bool IsInstance {
6028 get { return !IsStatic; }
6031 public override bool IsStatic {
6032 get { return true; }
6035 protected override TypeSpec DeclaringType {
6036 get { return constant.DeclaringType; }
6039 public override Expression CreateExpressionTree (ResolveContext ec)
6041 throw new NotSupportedException ("ET");
6044 protected override Expression DoResolve (ResolveContext rc)
6046 ResolveInstanceExpression (rc, null);
6047 DoBestMemberChecks (rc, constant);
6049 var c = constant.GetConstant (rc);
6051 // Creates reference expression to the constant value
6052 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6055 public override void Emit (EmitContext ec)
6057 throw new NotSupportedException ();
6060 public override string GetSignatureForError ()
6062 return constant.GetSignatureForError ();
6065 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6067 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6072 // Fully resolved expression that references a Field
6074 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6076 protected FieldSpec spec;
6077 VariableInfo variable_info;
6079 LocalTemporary temp;
6082 protected FieldExpr (Location l)
6087 public FieldExpr (FieldSpec spec, Location loc)
6092 type = spec.MemberType;
6095 public FieldExpr (FieldBase fi, Location l)
6102 public override string Name {
6108 public bool IsHoisted {
6110 IVariableReference hv = InstanceExpression as IVariableReference;
6111 return hv != null && hv.IsHoisted;
6115 public override bool IsInstance {
6117 return !spec.IsStatic;
6121 public override bool IsStatic {
6123 return spec.IsStatic;
6127 public override string KindName {
6128 get { return "field"; }
6131 public FieldSpec Spec {
6137 protected override TypeSpec DeclaringType {
6139 return spec.DeclaringType;
6143 public VariableInfo VariableInfo {
6145 return variable_info;
6151 public override string GetSignatureForError ()
6153 return spec.GetSignatureForError ();
6156 public bool IsMarshalByRefAccess (ResolveContext rc)
6158 // Checks possible ldflda of field access expression
6159 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6160 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6161 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6164 public void SetHasAddressTaken ()
6166 IVariableReference vr = InstanceExpression as IVariableReference;
6168 vr.SetHasAddressTaken ();
6172 protected override void CloneTo (CloneContext clonectx, Expression target)
6174 var t = (FieldExpr) target;
6176 if (InstanceExpression != null)
6177 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6180 public override Expression CreateExpressionTree (ResolveContext ec)
6182 if (ConditionalAccess) {
6183 Error_NullShortCircuitInsideExpressionTree (ec);
6186 return CreateExpressionTree (ec, true);
6189 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6192 Expression instance;
6194 if (InstanceExpression == null) {
6195 instance = new NullLiteral (loc);
6196 } else if (convertInstance) {
6197 instance = InstanceExpression.CreateExpressionTree (ec);
6199 args = new Arguments (1);
6200 args.Add (new Argument (InstanceExpression));
6201 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6204 args = Arguments.CreateForExpressionTree (ec, null,
6206 CreateTypeOfExpression ());
6208 return CreateExpressionFactoryCall (ec, "Field", args);
6211 public Expression CreateTypeOfExpression ()
6213 return new TypeOfField (spec, loc);
6216 protected override Expression DoResolve (ResolveContext ec)
6218 spec.MemberDefinition.SetIsUsed ();
6220 return DoResolve (ec, null);
6223 Expression DoResolve (ResolveContext ec, Expression rhs)
6225 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6228 ResolveConditionalAccessReceiver (ec);
6230 if (ResolveInstanceExpression (ec, rhs)) {
6231 // Resolve the field's instance expression while flow analysis is turned
6232 // off: when accessing a field "a.b", we must check whether the field
6233 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6235 if (lvalue_instance) {
6236 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6238 Expression right_side =
6239 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6241 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6243 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6246 if (InstanceExpression == null)
6250 DoBestMemberChecks (ec, spec);
6252 if (conditional_access_receiver)
6253 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6256 var fb = spec as FixedFieldSpec;
6257 IVariableReference var = InstanceExpression as IVariableReference;
6260 IFixedExpression fe = InstanceExpression as IFixedExpression;
6261 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6262 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6265 if (InstanceExpression.eclass != ExprClass.Variable) {
6266 ec.Report.SymbolRelatedToPreviousError (spec);
6267 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6268 TypeManager.GetFullNameSignature (spec));
6269 } else if (var != null && var.IsHoisted) {
6270 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6273 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6277 // Set flow-analysis variable info for struct member access. It will be check later
6278 // for precise error reporting
6280 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6281 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6284 if (ConditionalAccess) {
6285 if (conditional_access_receiver)
6286 type = LiftMemberType (ec, type);
6288 if (InstanceExpression.IsNull)
6289 return Constant.CreateConstantFromValue (type, null, loc);
6292 eclass = ExprClass.Variable;
6296 public void SetFieldAssigned (FlowAnalysisContext fc)
6301 bool lvalue_instance = spec.DeclaringType.IsStruct;
6302 if (lvalue_instance) {
6303 var var = InstanceExpression as IVariableReference;
6304 if (var != null && var.VariableInfo != null) {
6305 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6309 var fe = InstanceExpression as FieldExpr;
6311 Expression instance;
6314 instance = fe.InstanceExpression;
6315 var fe_instance = instance as FieldExpr;
6316 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6317 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6318 var var = InstanceExpression as IVariableReference;
6319 if (var != null && var.VariableInfo == null) {
6320 var var_inst = instance as IVariableReference;
6321 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6322 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6326 if (fe_instance != null) {
6335 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6336 instance.FlowAnalysis (fc);
6338 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6339 InstanceExpression.FlowAnalysis (fc);
6343 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6345 // The return value is always null. Returning a value simplifies calling code.
6347 if (right_side == EmptyExpression.OutAccess) {
6349 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6350 GetSignatureForError ());
6352 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6353 GetSignatureForError ());
6359 if (right_side == EmptyExpression.LValueMemberAccess) {
6360 // Already reported as CS1648/CS1650
6364 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6366 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6367 GetSignatureForError ());
6369 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6370 GetSignatureForError ());
6376 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6377 GetSignatureForError ());
6379 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6380 GetSignatureForError ());
6386 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6388 if (HasConditionalAccess ())
6389 Error_NullPropagatingLValue (ec);
6391 if (spec is FixedFieldSpec) {
6392 // It could be much better error message but we want to be error compatible
6393 Error_ValueAssignment (ec, right_side);
6396 Expression e = DoResolve (ec, right_side);
6401 spec.MemberDefinition.SetIsAssigned ();
6403 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6404 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6405 ec.Report.Warning (420, 1, loc,
6406 "`{0}': A volatile field references will not be treated as volatile",
6407 spec.GetSignatureForError ());
6410 if (spec.IsReadOnly) {
6411 // InitOnly fields can only be assigned in constructors or initializers
6412 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6413 return Error_AssignToReadonly (ec, right_side);
6415 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6417 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6418 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6419 return Error_AssignToReadonly (ec, right_side);
6420 // static InitOnly fields cannot be assigned-to in an instance constructor
6421 if (IsStatic && !ec.IsStatic)
6422 return Error_AssignToReadonly (ec, right_side);
6423 // instance constructors can't modify InitOnly fields of other instances of the same type
6424 if (!IsStatic && !(InstanceExpression is This))
6425 return Error_AssignToReadonly (ec, right_side);
6429 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6430 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6431 ec.Report.Warning (197, 1, loc,
6432 "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",
6433 GetSignatureForError ());
6436 eclass = ExprClass.Variable;
6440 public override void FlowAnalysis (FlowAnalysisContext fc)
6442 var var = InstanceExpression as IVariableReference;
6444 var vi = var.VariableInfo;
6445 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6446 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6450 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6451 var le = SkipLeftValueTypeAccess (InstanceExpression);
6453 le.FlowAnalysis (fc);
6459 base.FlowAnalysis (fc);
6461 if (conditional_access_receiver)
6462 fc.ConditionalAccessEnd ();
6465 static Expression SkipLeftValueTypeAccess (Expression expr)
6467 if (!TypeSpec.IsValueType (expr.Type))
6470 if (expr is VariableReference)
6473 var fe = expr as FieldExpr;
6477 if (fe.InstanceExpression == null)
6480 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6483 public override int GetHashCode ()
6485 return spec.GetHashCode ();
6488 public bool IsFixed {
6491 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6493 IVariableReference variable = InstanceExpression as IVariableReference;
6494 if (variable != null)
6495 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6497 IFixedExpression fe = InstanceExpression as IFixedExpression;
6498 return fe != null && fe.IsFixed;
6502 public override bool Equals (object obj)
6504 FieldExpr fe = obj as FieldExpr;
6508 if (spec != fe.spec)
6511 if (InstanceExpression == null || fe.InstanceExpression == null)
6514 return InstanceExpression.Equals (fe.InstanceExpression);
6517 public void Emit (EmitContext ec, bool leave_copy)
6519 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6523 ec.Emit (OpCodes.Volatile);
6525 ec.Emit (OpCodes.Ldsfld, spec);
6528 if (conditional_access_receiver)
6529 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6531 EmitInstance (ec, false);
6534 // Optimization for build-in types
6535 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6536 ec.EmitLoadFromPtr (type);
6538 var ff = spec as FixedFieldSpec;
6540 ec.Emit (OpCodes.Ldflda, spec);
6541 ec.Emit (OpCodes.Ldflda, ff.Element);
6544 ec.Emit (OpCodes.Volatile);
6546 ec.Emit (OpCodes.Ldfld, spec);
6550 if (conditional_access_receiver) {
6551 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6556 ec.Emit (OpCodes.Dup);
6558 temp = new LocalTemporary (this.Type);
6564 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6566 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6567 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6572 if (ConditionalAccess)
6573 throw new NotImplementedException ("null operator assignment");
6575 if (has_await_source)
6576 source = source.EmitToField (ec);
6578 EmitInstance (ec, prepared);
6583 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6584 ec.Emit (OpCodes.Dup);
6586 temp = new LocalTemporary (this.Type);
6591 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6592 ec.Emit (OpCodes.Volatile);
6594 spec.MemberDefinition.SetIsAssigned ();
6597 ec.Emit (OpCodes.Stsfld, spec);
6599 ec.Emit (OpCodes.Stfld, spec);
6601 if (ec.NotifyEvaluatorOnStore) {
6603 throw new NotImplementedException ("instance field write");
6606 ec.Emit (OpCodes.Dup);
6608 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6619 // Emits store to field with prepared values on stack
6621 public void EmitAssignFromStack (EmitContext ec)
6624 ec.Emit (OpCodes.Stsfld, spec);
6626 ec.Emit (OpCodes.Stfld, spec);
6630 public override void Emit (EmitContext ec)
6635 public override void EmitSideEffect (EmitContext ec)
6637 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6639 if (is_volatile) // || is_marshal_by_ref ())
6640 base.EmitSideEffect (ec);
6643 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6645 if ((mode & AddressOp.Store) != 0)
6646 spec.MemberDefinition.SetIsAssigned ();
6647 if ((mode & AddressOp.Load) != 0)
6648 spec.MemberDefinition.SetIsUsed ();
6651 // Handle initonly fields specially: make a copy and then
6652 // get the address of the copy.
6655 if (spec.IsReadOnly){
6657 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6669 var temp = ec.GetTemporaryLocal (type);
6670 ec.Emit (OpCodes.Stloc, temp);
6671 ec.Emit (OpCodes.Ldloca, temp);
6677 ec.Emit (OpCodes.Ldsflda, spec);
6680 EmitInstance (ec, false);
6681 ec.Emit (OpCodes.Ldflda, spec);
6685 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6687 return MakeExpression (ctx);
6690 public override SLE.Expression MakeExpression (BuilderContext ctx)
6693 return base.MakeExpression (ctx);
6695 return SLE.Expression.Field (
6696 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6697 spec.GetMetaInfo ());
6701 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6703 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6709 // Expression that evaluates to a Property.
6711 // This is not an LValue because we need to re-write the expression. We
6712 // can not take data from the stack and store it.
6714 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6716 Arguments arguments;
6717 FieldExpr backing_field;
6719 public PropertyExpr (PropertySpec spec, Location l)
6722 best_candidate = spec;
6723 type = spec.MemberType;
6728 protected override Arguments Arguments {
6737 protected override TypeSpec DeclaringType {
6739 return best_candidate.DeclaringType;
6743 public override string Name {
6745 return best_candidate.Name;
6749 public bool IsAutoPropertyAccess {
6751 var prop = best_candidate.MemberDefinition as Property;
6752 return prop != null && prop.BackingField != null;
6756 public override bool IsInstance {
6762 public override bool IsStatic {
6764 return best_candidate.IsStatic;
6768 public override string KindName {
6769 get { return "property"; }
6772 public PropertySpec PropertyInfo {
6774 return best_candidate;
6780 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6782 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6785 var args_count = arguments == null ? 0 : arguments.Count;
6786 if (args_count != body.Parameters.Count && args_count == 0)
6789 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6790 mg.InstanceExpression = InstanceExpression;
6795 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6797 return new PropertyExpr (spec, loc) {
6803 public override Expression CreateExpressionTree (ResolveContext ec)
6805 if (ConditionalAccess) {
6806 Error_NullShortCircuitInsideExpressionTree (ec);
6810 if (IsSingleDimensionalArrayLength ()) {
6811 args = new Arguments (1);
6812 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6813 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6816 args = new Arguments (2);
6817 if (InstanceExpression == null)
6818 args.Add (new Argument (new NullLiteral (loc)));
6820 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6821 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6822 return CreateExpressionFactoryCall (ec, "Property", args);
6825 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6827 DoResolveLValue (rc, null);
6828 return new TypeOfMethod (Setter, loc);
6831 public override string GetSignatureForError ()
6833 return best_candidate.GetSignatureForError ();
6836 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6839 return base.MakeExpression (ctx);
6841 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6845 public override SLE.Expression MakeExpression (BuilderContext ctx)
6848 return base.MakeExpression (ctx);
6850 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6854 void Error_PropertyNotValid (ResolveContext ec)
6856 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6857 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6858 GetSignatureForError ());
6861 bool IsSingleDimensionalArrayLength ()
6863 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6866 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6867 return ac != null && ac.Rank == 1;
6870 public override void Emit (EmitContext ec, bool leave_copy)
6873 // Special case: length of single dimension array property is turned into ldlen
6875 if (IsSingleDimensionalArrayLength ()) {
6876 if (conditional_access_receiver) {
6877 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6880 EmitInstance (ec, false);
6882 ec.Emit (OpCodes.Ldlen);
6883 ec.Emit (OpCodes.Conv_I4);
6885 if (conditional_access_receiver) {
6886 ec.CloseConditionalAccess (type);
6892 base.Emit (ec, leave_copy);
6895 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6897 if (backing_field != null) {
6898 backing_field.EmitAssign (ec, source, false, false);
6903 LocalTemporary await_source_arg = null;
6905 if (isCompound && !(source is DynamicExpressionStatement)) {
6906 emitting_compound_assignment = true;
6909 if (has_await_arguments) {
6910 await_source_arg = new LocalTemporary (Type);
6911 await_source_arg.Store (ec);
6913 args = new Arguments (1);
6914 args.Add (new Argument (await_source_arg));
6917 temp = await_source_arg;
6920 has_await_arguments = false;
6925 ec.Emit (OpCodes.Dup);
6926 temp = new LocalTemporary (this.Type);
6931 args = arguments ?? new Arguments (1);
6935 temp = new LocalTemporary (this.Type);
6937 args.Add (new Argument (temp));
6939 args.Add (new Argument (source));
6943 emitting_compound_assignment = false;
6945 var call = new CallEmitter ();
6946 call.InstanceExpression = InstanceExpression;
6948 call.InstanceExpressionOnStack = true;
6950 if (ConditionalAccess) {
6951 call.ConditionalAccess = true;
6955 call.Emit (ec, Setter, args, loc);
6957 call.EmitStatement (ec, Setter, args, loc);
6964 if (await_source_arg != null) {
6965 await_source_arg.Release (ec);
6969 public override void FlowAnalysis (FlowAnalysisContext fc)
6971 var prop = best_candidate.MemberDefinition as Property;
6972 if (prop != null && prop.BackingField != null) {
6973 var var = InstanceExpression as IVariableReference;
6975 var vi = var.VariableInfo;
6976 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6977 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6981 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6986 base.FlowAnalysis (fc);
6988 if (conditional_access_receiver)
6989 fc.ConditionalAccessEnd ();
6992 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6994 eclass = ExprClass.PropertyAccess;
6996 if (best_candidate.IsNotCSharpCompatible) {
6997 Error_PropertyNotValid (rc);
7000 ResolveInstanceExpression (rc, right_side);
7002 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7003 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7004 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7006 type = p.MemberType;
7010 DoBestMemberChecks (rc, best_candidate);
7012 // Handling of com-imported properties with any number of default property parameters
7013 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7014 var p = best_candidate.Get.Parameters;
7015 arguments = new Arguments (p.Count);
7016 for (int i = 0; i < p.Count; ++i) {
7017 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7019 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7020 var p = best_candidate.Set.Parameters;
7021 arguments = new Arguments (p.Count - 1);
7022 for (int i = 0; i < p.Count - 1; ++i) {
7023 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7030 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7032 var prop = best_candidate.MemberDefinition as Property;
7036 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7039 var spec = prop.BackingField;
7043 if (rc.IsStatic != spec.IsStatic)
7046 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7049 backing_field = new FieldExpr (prop.BackingField, loc);
7050 backing_field.ResolveLValue (rc, rhs);
7054 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7056 if (backing_field != null) {
7057 backing_field.SetFieldAssigned (fc);
7061 if (!IsAutoPropertyAccess)
7064 var prop = best_candidate.MemberDefinition as Property;
7065 if (prop != null && prop.BackingField != null) {
7066 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7067 if (lvalue_instance) {
7068 var var = InstanceExpression as IVariableReference;
7069 if (var != null && var.VariableInfo != null) {
7070 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7076 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7078 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7082 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7084 // getter and setter can be different for base calls
7085 MethodSpec getter, setter;
7086 protected T best_candidate;
7088 protected LocalTemporary temp;
7089 protected bool emitting_compound_assignment;
7090 protected bool has_await_arguments;
7092 protected PropertyOrIndexerExpr (Location l)
7099 protected abstract Arguments Arguments { get; set; }
7101 public MethodSpec Getter {
7110 public MethodSpec Setter {
7121 protected override Expression DoResolve (ResolveContext ec)
7123 if (eclass == ExprClass.Unresolved) {
7124 ResolveConditionalAccessReceiver (ec);
7126 var expr = OverloadResolve (ec, null);
7131 return expr.Resolve (ec);
7133 if (conditional_access_receiver) {
7134 type = LiftMemberType (ec, type);
7135 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7139 if (!ResolveGetter (ec))
7145 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7147 if (HasConditionalAccess ())
7148 Error_NullPropagatingLValue (rc);
7150 if (right_side == EmptyExpression.OutAccess) {
7151 // TODO: best_candidate can be null at this point
7152 INamedBlockVariable variable = null;
7153 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7154 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7155 best_candidate.Name);
7157 right_side.DoResolveLValue (rc, this);
7162 if (eclass == ExprClass.Unresolved) {
7163 var expr = OverloadResolve (rc, right_side);
7168 return expr.ResolveLValue (rc, right_side);
7170 ResolveInstanceExpression (rc, right_side);
7173 if (!best_candidate.HasSet) {
7174 if (ResolveAutopropertyAssignment (rc, right_side))
7177 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7178 GetSignatureForError ());
7182 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7183 if (best_candidate.HasDifferentAccessibility) {
7184 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7185 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7186 GetSignatureForError ());
7188 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7189 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7193 if (best_candidate.HasDifferentAccessibility)
7194 CheckProtectedMemberAccess (rc, best_candidate.Set);
7196 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7200 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7202 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7204 call.Emit (ec, method, arguments, loc);
7206 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7210 // Implements the IAssignMethod interface for assignments
7212 public virtual void Emit (EmitContext ec, bool leave_copy)
7214 var call = new CallEmitter ();
7215 call.ConditionalAccess = ConditionalAccess;
7216 call.InstanceExpression = InstanceExpression;
7217 if (has_await_arguments)
7218 call.HasAwaitArguments = true;
7220 call.DuplicateArguments = emitting_compound_assignment;
7222 if (conditional_access_receiver)
7223 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7225 call.Emit (ec, Getter, Arguments, loc);
7227 if (call.HasAwaitArguments) {
7228 InstanceExpression = call.InstanceExpression;
7229 Arguments = call.EmittedArguments;
7230 has_await_arguments = true;
7234 ec.Emit (OpCodes.Dup);
7235 temp = new LocalTemporary (Type);
7240 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7242 public override void Emit (EmitContext ec)
7247 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7249 has_await_arguments = true;
7254 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7256 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7258 bool ResolveGetter (ResolveContext rc)
7260 if (!best_candidate.HasGet) {
7261 if (InstanceExpression != EmptyExpression.Null) {
7262 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7263 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7264 best_candidate.GetSignatureForError ());
7267 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7268 if (best_candidate.HasDifferentAccessibility) {
7269 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7270 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7271 TypeManager.CSharpSignature (best_candidate));
7273 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7274 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7278 if (best_candidate.HasDifferentAccessibility) {
7279 CheckProtectedMemberAccess (rc, best_candidate.Get);
7282 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7286 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7293 /// Fully resolved expression that evaluates to an Event
7295 public class EventExpr : MemberExpr, IAssignMethod
7297 readonly EventSpec spec;
7300 public EventExpr (EventSpec spec, Location loc)
7308 protected override TypeSpec DeclaringType {
7310 return spec.DeclaringType;
7314 public override string Name {
7320 public override bool IsInstance {
7322 return !spec.IsStatic;
7326 public override bool IsStatic {
7328 return spec.IsStatic;
7332 public override string KindName {
7333 get { return "event"; }
7336 public MethodSpec Operator {
7344 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7347 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7349 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7350 if (spec.BackingField != null &&
7351 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7353 spec.MemberDefinition.SetIsUsed ();
7355 if (!ec.IsObsolete) {
7356 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7358 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7361 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7362 Error_AssignmentEventOnly (ec);
7364 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7366 InstanceExpression = null;
7368 return ml.ResolveMemberAccess (ec, left, original);
7372 return base.ResolveMemberAccess (ec, left, original);
7375 public override Expression CreateExpressionTree (ResolveContext ec)
7377 throw new NotSupportedException ("ET");
7380 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7382 if (right_side == EmptyExpression.EventAddition) {
7383 op = spec.AccessorAdd;
7384 } else if (right_side == EmptyExpression.EventSubtraction) {
7385 op = spec.AccessorRemove;
7389 Error_AssignmentEventOnly (ec);
7393 if (HasConditionalAccess ())
7394 Error_NullPropagatingLValue (ec);
7396 op = CandidateToBaseOverride (ec, op);
7400 protected override Expression DoResolve (ResolveContext ec)
7402 eclass = ExprClass.EventAccess;
7403 type = spec.MemberType;
7405 ResolveInstanceExpression (ec, null);
7407 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7408 Error_AssignmentEventOnly (ec);
7411 DoBestMemberChecks (ec, spec);
7415 public override void Emit (EmitContext ec)
7417 throw new NotSupportedException ();
7418 //Error_CannotAssign ();
7421 #region IAssignMethod Members
7423 public void Emit (EmitContext ec, bool leave_copy)
7425 throw new NotImplementedException ();
7428 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7430 if (leave_copy || !isCompound)
7431 throw new NotImplementedException ("EventExpr::EmitAssign");
7433 Arguments args = new Arguments (1);
7434 args.Add (new Argument (source));
7436 // TODO: Wrong, needs receiver
7437 // if (NullShortCircuit) {
7438 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7441 var call = new CallEmitter ();
7442 call.InstanceExpression = InstanceExpression;
7443 call.ConditionalAccess = ConditionalAccess;
7444 call.EmitStatement (ec, op, args, loc);
7446 // if (NullShortCircuit)
7447 // ec.CloseConditionalAccess (null);
7452 void Error_AssignmentEventOnly (ResolveContext ec)
7454 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7455 ec.Report.Error (79, loc,
7456 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7457 GetSignatureForError ());
7459 ec.Report.Error (70, loc,
7460 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7461 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7465 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7467 name = name.Substring (0, name.LastIndexOf ('.'));
7468 base.Error_CannotCallAbstractBase (rc, name);
7471 public override string GetSignatureForError ()
7473 return TypeManager.CSharpSignature (spec);
7476 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7478 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7482 public class TemporaryVariableReference : VariableReference
7484 public class Declarator : Statement
7486 TemporaryVariableReference variable;
7488 public Declarator (TemporaryVariableReference variable)
7490 this.variable = variable;
7494 protected override void DoEmit (EmitContext ec)
7496 variable.li.CreateBuilder (ec);
7499 public override void Emit (EmitContext ec)
7501 // Don't create sequence point
7505 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7510 protected override void CloneTo (CloneContext clonectx, Statement target)
7518 public TemporaryVariableReference (LocalVariable li, Location loc)
7521 this.type = li.Type;
7525 public override bool IsLockedByStatement {
7533 public LocalVariable LocalInfo {
7539 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7541 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7542 return new TemporaryVariableReference (li, loc);
7545 protected override Expression DoResolve (ResolveContext ec)
7547 eclass = ExprClass.Variable;
7550 // Don't capture temporary variables except when using
7551 // state machine redirection and block yields
7553 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7554 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7555 ec.IsVariableCapturingRequired) {
7556 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7557 storey.CaptureLocalVariable (ec, li);
7563 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7565 return Resolve (ec);
7568 public override void Emit (EmitContext ec)
7570 li.CreateBuilder (ec);
7575 public void EmitAssign (EmitContext ec, Expression source)
7577 li.CreateBuilder (ec);
7579 EmitAssign (ec, source, false, false);
7582 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7584 return li.HoistedVariant;
7587 public override bool IsFixed {
7588 get { return true; }
7591 public override bool IsRef {
7592 get { return false; }
7595 public override string Name {
7596 get { throw new NotImplementedException (); }
7599 public override void SetHasAddressTaken ()
7601 throw new NotImplementedException ();
7604 protected override ILocalVariable Variable {
7608 public override VariableInfo VariableInfo {
7609 get { return null; }
7614 /// Handles `var' contextual keyword; var becomes a keyword only
7615 /// if no type called var exists in a variable scope
7617 class VarExpr : SimpleName
7619 public VarExpr (Location loc)
7624 public bool InferType (ResolveContext ec, Expression right_side)
7627 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7629 type = right_side.Type;
7630 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7631 ec.Report.Error (815, loc,
7632 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7633 type.GetSignatureForError ());
7634 type = InternalType.ErrorType;
7638 eclass = ExprClass.Variable;
7642 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7644 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7645 base.Error_TypeOrNamespaceNotFound (ec);
7647 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");