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 var reduced = e as IReducedExpressionStatement;
1343 if (reduced != null) {
1344 return EmptyExpressionStatement.Instance;
1347 Error_InvalidExpressionStatement (ec);
1351 // This is quite expensive warning, try to limit the damage
1353 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1354 WarningAsyncWithoutWait (ec, e);
1360 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1362 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1363 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1368 // Need to do full resolve because GetAwaiter can be extension method
1369 // available only in this context
1371 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1375 var arguments = new Arguments (0);
1376 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1381 // Use same check rules as for real await
1383 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1384 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1387 bc.Report.Warning (4014, 1, e.Location,
1388 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1392 var inv = e as Invocation;
1393 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1394 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1395 bc.Report.Warning (4014, 1, e.Location,
1396 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1402 /// Requests the expression to be emitted in a `statement'
1403 /// context. This means that no new value is left on the
1404 /// stack after invoking this method (constrasted with
1405 /// Emit that will always leave a value on the stack).
1407 public abstract void EmitStatement (EmitContext ec);
1409 public override void EmitSideEffect (EmitContext ec)
1415 interface IReducedExpressionStatement
1420 /// This kind of cast is used to encapsulate the child
1421 /// whose type is child.Type into an expression that is
1422 /// reported to return "return_type". This is used to encapsulate
1423 /// expressions which have compatible types, but need to be dealt
1424 /// at higher levels with.
1426 /// For example, a "byte" expression could be encapsulated in one
1427 /// of these as an "unsigned int". The type for the expression
1428 /// would be "unsigned int".
1431 public abstract class TypeCast : Expression
1433 protected readonly Expression child;
1435 protected TypeCast (Expression child, TypeSpec return_type)
1437 eclass = child.eclass;
1438 loc = child.Location;
1443 public Expression Child {
1449 public override bool ContainsEmitWithAwait ()
1451 return child.ContainsEmitWithAwait ();
1454 public override Expression CreateExpressionTree (ResolveContext ec)
1456 Arguments args = new Arguments (2);
1457 args.Add (new Argument (child.CreateExpressionTree (ec)));
1458 args.Add (new Argument (new TypeOf (type, loc)));
1460 if (type.IsPointer || child.Type.IsPointer)
1461 Error_PointerInsideExpressionTree (ec);
1463 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1466 protected override Expression DoResolve (ResolveContext ec)
1468 // This should never be invoked, we are born in fully
1469 // initialized state.
1474 public override void Emit (EmitContext ec)
1479 public override void FlowAnalysis (FlowAnalysisContext fc)
1481 child.FlowAnalysis (fc);
1484 public override SLE.Expression MakeExpression (BuilderContext ctx)
1487 return base.MakeExpression (ctx);
1489 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1490 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1491 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1495 protected override void CloneTo (CloneContext clonectx, Expression t)
1500 public override bool IsNull {
1501 get { return child.IsNull; }
1505 public class EmptyCast : TypeCast {
1506 EmptyCast (Expression child, TypeSpec target_type)
1507 : base (child, target_type)
1511 public static Expression Create (Expression child, TypeSpec type)
1513 Constant c = child as Constant;
1515 var enum_constant = c as EnumConstant;
1516 if (enum_constant != null)
1517 c = enum_constant.Child;
1519 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1523 var res = c.ConvertImplicitly (type);
1529 EmptyCast e = child as EmptyCast;
1531 return new EmptyCast (e.child, type);
1533 return new EmptyCast (child, type);
1536 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1538 child.EmitBranchable (ec, label, on_true);
1541 public override void EmitSideEffect (EmitContext ec)
1543 child.EmitSideEffect (ec);
1548 // Used for predefined type user operator (no obsolete check, etc.)
1550 public class OperatorCast : TypeCast
1552 readonly MethodSpec conversion_operator;
1554 public OperatorCast (Expression expr, TypeSpec target_type)
1555 : this (expr, target_type, target_type, false)
1559 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1560 : this (expr, target_type, target_type, find_explicit)
1564 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1565 : base (expr, returnType)
1567 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1568 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1571 foreach (MethodSpec oper in mi) {
1572 if (oper.ReturnType != returnType)
1575 if (oper.Parameters.Types[0] == expr.Type) {
1576 conversion_operator = oper;
1582 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1583 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1586 public override void Emit (EmitContext ec)
1589 ec.Emit (OpCodes.Call, conversion_operator);
1594 // Constant specialization of EmptyCast.
1595 // We need to special case this since an empty cast of
1596 // a constant is still a constant.
1598 public class EmptyConstantCast : Constant
1600 public readonly Constant child;
1602 public EmptyConstantCast (Constant child, TypeSpec type)
1603 : base (child.Location)
1606 throw new ArgumentNullException ("child");
1609 this.eclass = child.eclass;
1613 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1615 if (child.Type == target_type)
1618 // FIXME: check that 'type' can be converted to 'target_type' first
1619 return child.ConvertExplicitly (in_checked_context, target_type);
1622 public override Expression CreateExpressionTree (ResolveContext ec)
1624 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1625 child.CreateExpressionTree (ec),
1626 new TypeOf (type, loc));
1629 Error_PointerInsideExpressionTree (ec);
1631 return CreateExpressionFactoryCall (ec, "Convert", args);
1634 public override bool IsDefaultValue {
1635 get { return child.IsDefaultValue; }
1638 public override bool IsNegative {
1639 get { return child.IsNegative; }
1642 public override bool IsNull {
1643 get { return child.IsNull; }
1646 public override bool IsOneInteger {
1647 get { return child.IsOneInteger; }
1650 public override bool IsSideEffectFree {
1652 return child.IsSideEffectFree;
1656 public override bool IsZeroInteger {
1657 get { return child.IsZeroInteger; }
1660 public override void Emit (EmitContext ec)
1665 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1667 child.EmitBranchable (ec, label, on_true);
1669 // Only to make verifier happy
1670 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1671 ec.Emit (OpCodes.Unbox_Any, type);
1674 public override void EmitSideEffect (EmitContext ec)
1676 child.EmitSideEffect (ec);
1679 public override object GetValue ()
1681 return child.GetValue ();
1684 public override string GetValueAsLiteral ()
1686 return child.GetValueAsLiteral ();
1689 public override long GetValueAsLong ()
1691 return child.GetValueAsLong ();
1694 public override Constant ConvertImplicitly (TypeSpec target_type)
1696 if (type == target_type)
1699 // FIXME: Do we need to check user conversions?
1700 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1703 return child.ConvertImplicitly (target_type);
1708 /// This class is used to wrap literals which belong inside Enums
1710 public class EnumConstant : Constant
1712 public Constant Child;
1714 public EnumConstant (Constant child, TypeSpec enum_type)
1715 : base (child.Location)
1719 this.eclass = ExprClass.Value;
1720 this.type = enum_type;
1723 protected EnumConstant (Location loc)
1728 public override void Emit (EmitContext ec)
1733 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1735 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1738 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1740 Child.EmitBranchable (ec, label, on_true);
1743 public override void EmitSideEffect (EmitContext ec)
1745 Child.EmitSideEffect (ec);
1748 public override string GetSignatureForError()
1750 return Type.GetSignatureForError ();
1753 public override object GetValue ()
1755 return Child.GetValue ();
1759 public override object GetTypedValue ()
1762 // The method can be used in dynamic context only (on closed types)
1764 // System.Enum.ToObject cannot be called on dynamic types
1765 // EnumBuilder has to be used, but we cannot use EnumBuilder
1766 // because it does not properly support generics
1768 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1772 public override string GetValueAsLiteral ()
1774 return Child.GetValueAsLiteral ();
1777 public override long GetValueAsLong ()
1779 return Child.GetValueAsLong ();
1782 public EnumConstant Increment()
1784 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1787 public override bool IsDefaultValue {
1789 return Child.IsDefaultValue;
1793 public override bool IsSideEffectFree {
1795 return Child.IsSideEffectFree;
1799 public override bool IsZeroInteger {
1800 get { return Child.IsZeroInteger; }
1803 public override bool IsNegative {
1805 return Child.IsNegative;
1809 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1811 if (Child.Type == target_type)
1814 return Child.ConvertExplicitly (in_checked_context, target_type);
1817 public override Constant ConvertImplicitly (TypeSpec type)
1819 if (this.type == type) {
1823 if (!Convert.ImplicitStandardConversionExists (this, type)){
1827 return Child.ConvertImplicitly (type);
1832 /// This kind of cast is used to encapsulate Value Types in objects.
1834 /// The effect of it is to box the value type emitted by the previous
1837 public class BoxedCast : TypeCast {
1839 public BoxedCast (Expression expr, TypeSpec target_type)
1840 : base (expr, target_type)
1842 eclass = ExprClass.Value;
1845 protected override Expression DoResolve (ResolveContext ec)
1847 // This should never be invoked, we are born in fully
1848 // initialized state.
1853 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1855 // Only boxing to object type is supported
1856 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1857 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1861 enc.Encode (child.Type);
1862 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1865 public override void Emit (EmitContext ec)
1869 ec.Emit (OpCodes.Box, child.Type);
1872 public override void EmitSideEffect (EmitContext ec)
1874 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1875 // so, we need to emit the box+pop instructions in most cases
1876 if (child.Type.IsStruct &&
1877 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1878 child.EmitSideEffect (ec);
1880 base.EmitSideEffect (ec);
1884 public class UnboxCast : TypeCast {
1885 public UnboxCast (Expression expr, TypeSpec return_type)
1886 : base (expr, return_type)
1890 protected override Expression DoResolve (ResolveContext ec)
1892 // This should never be invoked, we are born in fully
1893 // initialized state.
1898 public override void Emit (EmitContext ec)
1902 ec.Emit (OpCodes.Unbox_Any, type);
1907 /// This is used to perform explicit numeric conversions.
1909 /// Explicit numeric conversions might trigger exceptions in a checked
1910 /// context, so they should generate the conv.ovf opcodes instead of
1913 public class ConvCast : TypeCast {
1914 public enum Mode : byte {
1915 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1917 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1918 U2_I1, U2_U1, U2_I2, U2_CH,
1919 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1920 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1921 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1922 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1923 CH_I1, CH_U1, CH_I2,
1924 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1925 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1931 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1932 : base (child, return_type)
1937 protected override Expression DoResolve (ResolveContext ec)
1939 // This should never be invoked, we are born in fully
1940 // initialized state.
1945 public override string ToString ()
1947 return String.Format ("ConvCast ({0}, {1})", mode, child);
1950 public override void Emit (EmitContext ec)
1956 public static void Emit (EmitContext ec, Mode mode)
1958 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1960 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1963 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1964 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1966 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1967 case Mode.U1_CH: /* nothing */ break;
1969 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1970 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1971 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1973 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1979 case Mode.U2_CH: /* nothing */ break;
1981 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1982 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1983 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1984 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1985 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1986 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1987 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1989 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1990 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1991 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1992 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1993 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1994 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1996 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1997 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1998 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1999 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2001 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2002 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2003 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2004 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2006 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2007 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2008 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2009 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2010 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2011 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2012 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2013 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2014 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2016 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2017 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2018 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2020 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2021 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2022 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2023 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2024 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2025 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2026 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2027 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2028 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2030 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2031 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2032 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2033 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2034 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2035 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2036 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2037 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2038 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2039 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2041 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2045 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2048 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2049 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2051 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2052 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2054 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2055 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2056 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2057 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2058 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2059 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2061 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2062 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2063 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2064 case Mode.U2_CH: /* nothing */ break;
2066 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2067 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2068 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2069 case Mode.I4_U4: /* nothing */ break;
2070 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2071 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2072 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2074 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2075 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2076 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2077 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2078 case Mode.U4_I4: /* nothing */ break;
2079 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2081 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2082 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2083 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2084 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2085 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2086 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2087 case Mode.I8_U8: /* nothing */ break;
2088 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2089 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2091 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2092 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2093 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2094 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2095 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2096 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2097 case Mode.U8_I8: /* nothing */ break;
2098 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2099 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2101 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2102 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2103 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2105 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2106 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2107 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2108 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2109 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2110 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2111 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2112 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2113 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2115 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2116 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2117 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2118 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2119 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2120 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2121 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2122 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2123 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2124 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2126 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2132 class OpcodeCast : TypeCast
2136 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2137 : base (child, return_type)
2142 protected override Expression DoResolve (ResolveContext ec)
2144 // This should never be invoked, we are born in fully
2145 // initialized state.
2150 public override void Emit (EmitContext ec)
2156 public TypeSpec UnderlyingType {
2157 get { return child.Type; }
2162 // Opcode casts expression with 2 opcodes but only
2163 // single expression tree node
2165 class OpcodeCastDuplex : OpcodeCast
2167 readonly OpCode second;
2169 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2170 : base (child, returnType, first)
2172 this.second = second;
2175 public override void Emit (EmitContext ec)
2183 /// This kind of cast is used to encapsulate a child and cast it
2184 /// to the class requested
2186 public sealed class ClassCast : TypeCast {
2187 readonly bool forced;
2189 public ClassCast (Expression child, TypeSpec return_type)
2190 : base (child, return_type)
2194 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2195 : base (child, return_type)
2197 this.forced = forced;
2200 public override void Emit (EmitContext ec)
2204 bool gen = TypeManager.IsGenericParameter (child.Type);
2206 ec.Emit (OpCodes.Box, child.Type);
2208 if (type.IsGenericParameter) {
2209 ec.Emit (OpCodes.Unbox_Any, type);
2216 ec.Emit (OpCodes.Castclass, type);
2221 // Created during resolving pahse when an expression is wrapped or constantified
2222 // and original expression can be used later (e.g. for expression trees)
2224 public class ReducedExpression : Expression
2226 public class ReducedConstantExpression : EmptyConstantCast
2228 readonly Expression orig_expr;
2230 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2231 : base (expr, expr.Type)
2233 this.orig_expr = orig_expr;
2236 public Expression OriginalExpression {
2242 public override Constant ConvertImplicitly (TypeSpec target_type)
2244 Constant c = base.ConvertImplicitly (target_type);
2246 c = new ReducedConstantExpression (c, orig_expr);
2251 public override Expression CreateExpressionTree (ResolveContext ec)
2253 return orig_expr.CreateExpressionTree (ec);
2256 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2258 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2260 c = new ReducedConstantExpression (c, orig_expr);
2264 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2267 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2269 if (orig_expr is Conditional)
2270 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2272 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2276 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2278 public ReducedConstantStatement (Constant expr, Expression origExpr)
2279 : base (expr, origExpr)
2284 sealed class ReducedExpressionStatement : ExpressionStatement
2286 readonly Expression orig_expr;
2287 readonly ExpressionStatement stm;
2289 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2291 this.orig_expr = orig;
2293 this.eclass = stm.eclass;
2294 this.type = stm.Type;
2296 this.loc = orig.Location;
2299 public override bool ContainsEmitWithAwait ()
2301 return stm.ContainsEmitWithAwait ();
2304 public override Expression CreateExpressionTree (ResolveContext ec)
2306 return orig_expr.CreateExpressionTree (ec);
2309 protected override Expression DoResolve (ResolveContext ec)
2314 public override void Emit (EmitContext ec)
2319 public override void EmitStatement (EmitContext ec)
2321 stm.EmitStatement (ec);
2324 public override void FlowAnalysis (FlowAnalysisContext fc)
2326 stm.FlowAnalysis (fc);
2330 readonly Expression expr, orig_expr;
2332 private ReducedExpression (Expression expr, Expression orig_expr)
2335 this.eclass = expr.eclass;
2336 this.type = expr.Type;
2337 this.orig_expr = orig_expr;
2338 this.loc = orig_expr.Location;
2343 public override bool IsSideEffectFree {
2345 return expr.IsSideEffectFree;
2349 public Expression OriginalExpression {
2357 public override bool ContainsEmitWithAwait ()
2359 return expr.ContainsEmitWithAwait ();
2363 // Creates fully resolved expression switcher
2365 public static Constant Create (Constant expr, Expression originalExpr)
2367 if (expr.eclass == ExprClass.Unresolved)
2368 throw new ArgumentException ("Unresolved expression");
2370 if (originalExpr is ExpressionStatement)
2371 return new ReducedConstantStatement (expr, originalExpr);
2373 return new ReducedConstantExpression (expr, originalExpr);
2376 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2378 return new ReducedExpressionStatement (s, orig);
2381 public static Expression Create (Expression expr, Expression original_expr)
2383 return Create (expr, original_expr, true);
2387 // Creates unresolved reduce expression. The original expression has to be
2388 // already resolved. Created expression is constant based based on `expr'
2389 // value unless canBeConstant is used
2391 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2393 if (canBeConstant) {
2394 Constant c = expr as Constant;
2396 return Create (c, original_expr);
2399 ExpressionStatement s = expr as ExpressionStatement;
2401 return Create (s, original_expr);
2403 if (expr.eclass == ExprClass.Unresolved)
2404 throw new ArgumentException ("Unresolved expression");
2406 return new ReducedExpression (expr, original_expr);
2409 public override Expression CreateExpressionTree (ResolveContext ec)
2411 return orig_expr.CreateExpressionTree (ec);
2414 protected override Expression DoResolve (ResolveContext ec)
2419 public override void Emit (EmitContext ec)
2424 public override Expression EmitToField (EmitContext ec)
2426 return expr.EmitToField(ec);
2429 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2431 expr.EmitBranchable (ec, target, on_true);
2434 public override void FlowAnalysis (FlowAnalysisContext fc)
2436 expr.FlowAnalysis (fc);
2439 public override SLE.Expression MakeExpression (BuilderContext ctx)
2441 return orig_expr.MakeExpression (ctx);
2446 // Standard composite pattern
2448 public abstract class CompositeExpression : Expression
2450 protected Expression expr;
2452 protected CompositeExpression (Expression expr)
2455 this.loc = expr.Location;
2458 public override bool ContainsEmitWithAwait ()
2460 return expr.ContainsEmitWithAwait ();
2463 public override Expression CreateExpressionTree (ResolveContext rc)
2465 return expr.CreateExpressionTree (rc);
2468 public Expression Child {
2469 get { return expr; }
2472 protected override Expression DoResolve (ResolveContext rc)
2474 expr = expr.Resolve (rc);
2479 eclass = expr.eclass;
2483 public override void Emit (EmitContext ec)
2488 public override bool IsNull {
2489 get { return expr.IsNull; }
2494 // Base of expressions used only to narrow resolve flow
2496 public abstract class ShimExpression : Expression
2498 protected Expression expr;
2500 protected ShimExpression (Expression expr)
2505 public Expression Expr {
2511 protected override void CloneTo (CloneContext clonectx, Expression t)
2516 ShimExpression target = (ShimExpression) t;
2517 target.expr = expr.Clone (clonectx);
2520 public override bool ContainsEmitWithAwait ()
2522 return expr.ContainsEmitWithAwait ();
2525 public override Expression CreateExpressionTree (ResolveContext ec)
2527 throw new NotSupportedException ("ET");
2530 public override void Emit (EmitContext ec)
2532 throw new InternalErrorException ("Missing Resolve call");
2536 public class UnreachableExpression : Expression
2538 public UnreachableExpression (Expression expr)
2540 this.loc = expr.Location;
2543 public override Expression CreateExpressionTree (ResolveContext ec)
2546 throw new NotImplementedException ();
2549 protected override Expression DoResolve (ResolveContext rc)
2551 throw new NotSupportedException ();
2554 public override void FlowAnalysis (FlowAnalysisContext fc)
2556 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2559 public override void Emit (EmitContext ec)
2563 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2569 // Unresolved type name expressions
2571 public abstract class ATypeNameExpression : FullNamedExpression
2574 protected TypeArguments targs;
2576 protected ATypeNameExpression (string name, Location l)
2582 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2589 protected ATypeNameExpression (string name, int arity, Location l)
2590 : this (name, new UnboundTypeArguments (arity, l), l)
2598 return targs == null ? 0 : targs.Count;
2602 public bool HasTypeArguments {
2604 return targs != null && !targs.IsEmpty;
2608 public string Name {
2617 public TypeArguments TypeArguments {
2625 public override bool Equals (object obj)
2627 ATypeNameExpression atne = obj as ATypeNameExpression;
2628 return atne != null && atne.Name == Name &&
2629 (targs == null || targs.Equals (atne.targs));
2632 public override int GetHashCode ()
2634 return Name.GetHashCode ();
2637 // TODO: Move it to MemberCore
2638 public static string GetMemberType (MemberCore mc)
2644 if (mc is FieldBase)
2646 if (mc is MethodCore)
2648 if (mc is EnumMember)
2656 public override string GetSignatureForError ()
2658 if (targs != null) {
2659 return Name + "<" + targs.GetSignatureForError () + ">";
2665 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2669 /// SimpleName expressions are formed of a single word and only happen at the beginning
2670 /// of a dotted-name.
2672 public class SimpleName : ATypeNameExpression
2674 public SimpleName (string name, Location l)
2679 public SimpleName (string name, TypeArguments args, Location l)
2680 : base (name, args, l)
2684 public SimpleName (string name, int arity, Location l)
2685 : base (name, arity, l)
2689 public SimpleName GetMethodGroup ()
2691 return new SimpleName (Name, targs, loc);
2694 protected override Expression DoResolve (ResolveContext rc)
2696 return SimpleNameResolve (rc, null);
2699 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2701 return SimpleNameResolve (ec, right_side);
2704 public void Error_NameDoesNotExist (ResolveContext rc)
2706 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2709 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2711 if (ctx.CurrentType != null) {
2712 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2713 if (member != null) {
2714 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2719 var report = ctx.Module.Compiler.Report;
2721 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2722 if (retval != null) {
2723 report.SymbolRelatedToPreviousError (retval.Type);
2724 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2728 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2729 if (retval != null) {
2730 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2734 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2735 if (ns_candidates != null) {
2736 if (ctx is UsingAliasNamespace.AliasContext) {
2737 report.Error (246, loc,
2738 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2739 ns_candidates[0], Name);
2741 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2742 report.Error (246, loc,
2743 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2747 report.Error (246, loc,
2748 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2753 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2755 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2758 if (fne.Type != null && Arity > 0) {
2759 if (HasTypeArguments) {
2760 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2761 if (ct.ResolveAsType (mc) == null)
2767 targs.Resolve (mc, allowUnboundTypeArguments);
2769 return new GenericOpenTypeExpr (fne.Type, loc);
2773 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2775 if (!(fne is NamespaceExpression))
2779 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2780 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2781 mc.Module.Compiler.Report.Error (1980, Location,
2782 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2783 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2786 fne = new DynamicTypeExpr (loc);
2787 fne.ResolveAsType (mc);
2793 Error_TypeOrNamespaceNotFound (mc);
2797 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2799 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2802 public bool IsPossibleType (IMemberContext mc)
2804 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2807 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2809 int lookup_arity = Arity;
2810 bool errorMode = false;
2812 Block current_block = rc.CurrentBlock;
2813 INamedBlockVariable variable = null;
2814 bool variable_found = false;
2818 // Stage 1: binding to local variables or parameters
2820 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2822 if (current_block != null && lookup_arity == 0) {
2823 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2824 if (!variable.IsDeclared) {
2825 // We found local name in accessible block but it's not
2826 // initialized yet, maybe the user wanted to bind to something else
2828 variable_found = true;
2830 e = variable.CreateReferenceExpression (rc, loc);
2833 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2842 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2844 TypeSpec member_type = rc.CurrentType;
2845 for (; member_type != null; member_type = member_type.DeclaringType) {
2846 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2850 var me = e as MemberExpr;
2852 // The name matches a type, defer to ResolveAsTypeStep
2860 if (variable != null) {
2861 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2862 rc.Report.Error (844, loc,
2863 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2864 Name, me.GetSignatureForError ());
2868 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2869 // Leave it to overload resolution to report correct error
2871 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2872 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2876 // MemberLookup does not check accessors availability, this is actually needed for properties only
2878 var pe = me as PropertyExpr;
2881 // Break as there is no other overload available anyway
2882 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2883 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2886 pe.Getter = pe.PropertyInfo.Get;
2888 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2889 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2890 var p = (Property) pe.PropertyInfo.MemberDefinition;
2891 return new FieldExpr (p.BackingField, loc);
2894 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc)) {
2895 variable_found = true;
2899 pe.Setter = pe.PropertyInfo.Set;
2904 // TODO: It's used by EventExpr -> FieldExpr transformation only
2905 // TODO: Should go to MemberAccess
2906 me = me.ResolveMemberAccess (rc, null, null);
2909 targs.Resolve (rc, false);
2910 me.SetTypeArguments (rc, targs);
2917 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2919 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2920 if (IsPossibleTypeOrNamespace (rc)) {
2921 return ResolveAsTypeOrNamespace (rc, false);
2925 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2928 targs.Resolve (rc, false);
2930 var me = expr as MemberExpr;
2932 me.SetTypeArguments (rc, targs);
2937 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2938 return new NameOf (this);
2941 if (variable_found) {
2942 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2945 var tparams = rc.CurrentTypeParameters;
2946 if (tparams != null) {
2947 if (tparams.Find (Name) != null) {
2948 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2953 var ct = rc.CurrentType;
2955 if (ct.MemberDefinition.TypeParametersCount > 0) {
2956 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2957 if (ctp.Name == Name) {
2958 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2964 ct = ct.DeclaringType;
2965 } while (ct != null);
2968 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2969 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2971 rc.Report.SymbolRelatedToPreviousError (e.Type);
2972 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2976 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2978 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2979 return ErrorExpression.Instance;
2983 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2985 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2986 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2990 if (e is TypeExpr) {
2991 // TypeExpression does not have correct location
2992 if (e is TypeExpression)
2993 e = new TypeExpression (e.Type, loc);
2999 Error_NameDoesNotExist (rc);
3002 return ErrorExpression.Instance;
3005 if (rc.Module.Evaluator != null) {
3006 var fi = rc.Module.Evaluator.LookupField (Name);
3008 return new FieldExpr (fi.Item1, loc);
3016 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3018 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3023 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3024 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3028 if (right_side != null) {
3029 e = e.ResolveLValue (ec, right_side);
3037 public override object Accept (StructuralVisitor visitor)
3039 return visitor.Visit (this);
3044 /// Represents a namespace or a type. The name of the class was inspired by
3045 /// section 10.8.1 (Fully Qualified Names).
3047 public abstract class FullNamedExpression : Expression
3049 protected override void CloneTo (CloneContext clonectx, Expression target)
3051 // Do nothing, most unresolved type expressions cannot be
3052 // resolved to different type
3055 public override bool ContainsEmitWithAwait ()
3060 public override Expression CreateExpressionTree (ResolveContext ec)
3062 throw new NotSupportedException ("ET");
3065 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3068 // This is used to resolve the expression as a type, a null
3069 // value will be returned if the expression is not a type
3072 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3074 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3079 TypeExpr te = fne as TypeExpr;
3081 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3089 var dep = type.GetMissingDependencies ();
3091 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3094 if (type.Kind == MemberKind.Void) {
3095 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3099 // Obsolete checks cannot be done when resolving base context as they
3100 // require type dependencies to be set but we are in process of resolving them
3102 if (mc is ResolveContext) {
3103 var oa = type.GetAttributeObsolete ();
3104 if (oa != null && !mc.IsObsolete)
3105 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3112 public override void Emit (EmitContext ec)
3114 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3115 GetSignatureForError ());
3120 /// Expression that evaluates to a type
3122 public abstract class TypeExpr : FullNamedExpression
3124 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3130 protected sealed override Expression DoResolve (ResolveContext ec)
3136 public override bool Equals (object obj)
3138 TypeExpr tobj = obj as TypeExpr;
3142 return Type == tobj.Type;
3145 public override int GetHashCode ()
3147 return Type.GetHashCode ();
3152 /// Fully resolved Expression that already evaluated to a type
3154 public class TypeExpression : TypeExpr
3156 public TypeExpression (TypeSpec t, Location l)
3159 eclass = ExprClass.Type;
3163 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3169 public class NamespaceExpression : FullNamedExpression
3171 readonly Namespace ns;
3173 public NamespaceExpression (Namespace ns, Location loc)
3176 this.Type = InternalType.Namespace;
3177 this.eclass = ExprClass.Namespace;
3181 public Namespace Namespace {
3187 protected override Expression DoResolve (ResolveContext rc)
3189 throw new NotImplementedException ();
3192 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3197 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3199 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3200 if (retval != null) {
3201 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3202 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3206 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3207 if (retval != null) {
3208 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3213 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3214 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3218 string assembly = null;
3219 string possible_name = Namespace.GetSignatureForError () + "." + name;
3221 // Only assembly unique name should be added
3222 switch (possible_name) {
3223 case "System.Drawing":
3224 case "System.Web.Services":
3227 case "System.Configuration":
3228 case "System.Data.Services":
3229 case "System.DirectoryServices":
3231 case "System.Net.Http":
3232 case "System.Numerics":
3233 case "System.Runtime.Caching":
3234 case "System.ServiceModel":
3235 case "System.Transactions":
3236 case "System.Web.Routing":
3237 case "System.Xml.Linq":
3239 assembly = possible_name;
3243 case "System.Linq.Expressions":
3244 assembly = "System.Core";
3247 case "System.Windows.Forms":
3248 case "System.Windows.Forms.Layout":
3249 assembly = "System.Windows.Forms";
3253 assembly = assembly == null ? "an" : "`" + assembly + "'";
3255 if (Namespace is GlobalRootNamespace) {
3256 ctx.Module.Compiler.Report.Error (400, loc,
3257 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3260 ctx.Module.Compiler.Report.Error (234, loc,
3261 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3262 name, GetSignatureForError (), assembly);
3266 public override string GetSignatureForError ()
3268 return ns.GetSignatureForError ();
3271 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3273 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3276 public override string ToString ()
3278 return Namespace.Name;
3283 /// This class denotes an expression which evaluates to a member
3284 /// of a struct or a class.
3286 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3288 protected bool conditional_access_receiver;
3291 // An instance expression associated with this member, if it's a
3292 // non-static member
3294 public Expression InstanceExpression;
3297 /// The name of this member.
3299 public abstract string Name {
3304 // When base.member is used
3306 public bool IsBase {
3307 get { return InstanceExpression is BaseThis; }
3311 /// Whether this is an instance member.
3313 public abstract bool IsInstance {
3318 /// Whether this is a static member.
3320 public abstract bool IsStatic {
3324 public abstract string KindName {
3328 public bool ConditionalAccess { get; set; }
3330 protected abstract TypeSpec DeclaringType {
3334 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3336 return InstanceExpression.Type;
3341 // Converts best base candidate for virtual method starting from QueriedBaseType
3343 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3346 // Only when base.member is used and method is virtual
3352 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3353 // means for base.member access we have to find the closest match after we found best candidate
3355 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3357 // The method could already be what we are looking for
3359 TypeSpec[] targs = null;
3360 if (method.DeclaringType != InstanceExpression.Type) {
3362 // Candidate can have inflated MVAR parameters and we need to find
3363 // base match for original definition not inflated parameter types
3365 var parameters = method.Parameters;
3366 if (method.Arity > 0) {
3367 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3368 var inflated = method.DeclaringType as InflatedTypeSpec;
3369 if (inflated != null) {
3370 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3374 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3375 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3376 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3377 if (base_override.IsGeneric)
3378 targs = method.TypeArguments;
3380 method = base_override;
3385 // When base access is used inside anonymous method/iterator/etc we need to
3386 // get back to the context of original type. We do it by emiting proxy
3387 // method in original class and rewriting base call to this compiler
3388 // generated method call which does the actual base invocation. This may
3389 // introduce redundant storey but with `this' only but it's tricky to avoid
3390 // at this stage as we don't know what expressions follow base
3392 if (rc.CurrentAnonymousMethod != null) {
3393 if (targs == null && method.IsGeneric) {
3394 targs = method.TypeArguments;
3395 method = method.GetGenericMethodDefinition ();
3398 if (method.Parameters.HasArglist)
3399 throw new NotImplementedException ("__arglist base call proxy");
3401 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3403 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3404 // get/set member expressions second call would fail to proxy because left expression
3405 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3406 // FIXME: The async check is another hack but will probably fail with mutators
3407 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3408 InstanceExpression = new This (loc).Resolve (rc);
3412 method = method.MakeGenericMethod (rc, targs);
3416 // Only base will allow this invocation to happen.
3418 if (method.IsAbstract) {
3419 rc.Report.SymbolRelatedToPreviousError (method);
3420 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3426 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3428 if (InstanceExpression == null)
3431 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3432 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3433 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3438 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3440 if (InstanceExpression == null)
3443 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3446 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3448 var ct = rc.CurrentType;
3449 if (ct == qualifier)
3452 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3455 qualifier = qualifier.GetDefinition ();
3456 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3463 public override bool ContainsEmitWithAwait ()
3465 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3468 public override bool HasConditionalAccess ()
3470 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3473 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3476 type = type.GetDefinition ();
3478 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3481 type = type.DeclaringType;
3482 } while (type != null);
3487 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3489 if (InstanceExpression != null) {
3490 InstanceExpression = InstanceExpression.Resolve (rc);
3491 CheckProtectedMemberAccess (rc, member);
3494 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3495 UnsafeError (rc, loc);
3498 var dep = member.GetMissingDependencies ();
3500 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3503 member.CheckObsoleteness (rc, loc);
3505 if (!(member is FieldSpec))
3506 member.MemberDefinition.SetIsUsed ();
3509 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3511 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3514 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3516 rc.Report.SymbolRelatedToPreviousError (member);
3517 rc.Report.Error (1540, loc,
3518 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3519 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3522 public override void FlowAnalysis (FlowAnalysisContext fc)
3524 if (InstanceExpression != null) {
3525 InstanceExpression.FlowAnalysis (fc);
3527 if (ConditionalAccess) {
3528 fc.BranchConditionalAccessDefiniteAssignment ();
3533 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3535 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3536 if (HasConditionalAccess ()) {
3537 conditional_access_receiver = true;
3538 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3543 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3545 if (!ResolveInstanceExpressionCore (rc, rhs))
3549 // Check intermediate value modification which won't have any effect
3551 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3552 var fexpr = InstanceExpression as FieldExpr;
3553 if (fexpr != null) {
3554 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3557 if (fexpr.IsStatic) {
3558 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3559 fexpr.GetSignatureForError ());
3561 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3562 fexpr.GetSignatureForError ());
3568 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3569 if (rc.CurrentInitializerVariable != null) {
3570 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3571 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3573 rc.Report.Error (1612, loc,
3574 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3575 InstanceExpression.GetSignatureForError ());
3581 var lvr = InstanceExpression as LocalVariableReference;
3584 if (!lvr.local_info.IsReadonly)
3587 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3588 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3595 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3598 if (InstanceExpression != null) {
3599 if (InstanceExpression is TypeExpr) {
3600 var t = InstanceExpression.Type;
3602 t.CheckObsoleteness (rc, loc);
3604 t = t.DeclaringType;
3605 } while (t != null);
3607 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3608 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3609 rc.Report.Error (176, loc,
3610 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3611 GetSignatureForError ());
3615 InstanceExpression = null;
3621 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3622 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3623 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3624 rc.Report.Error (236, loc,
3625 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3626 GetSignatureForError ());
3628 var fe = this as FieldExpr;
3629 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3630 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3631 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3633 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3637 rc.Report.Error (120, loc,
3638 "An object reference is required to access non-static member `{0}'",
3639 GetSignatureForError ());
3643 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3647 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3648 rc.Report.Error (38, loc,
3649 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3650 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3653 InstanceExpression = new This (loc).Resolve (rc);
3657 var me = InstanceExpression as MemberExpr;
3659 me.ResolveInstanceExpressionCore (rc, rhs);
3661 var fe = me as FieldExpr;
3662 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3663 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3664 rc.Report.Warning (1690, 1, loc,
3665 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3666 me.GetSignatureForError ());
3673 // Additional checks for l-value member access
3676 if (InstanceExpression is UnboxCast) {
3677 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3684 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3686 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3687 ec.Report.Warning (1720, 1, left.Location,
3688 "Expression will always cause a `{0}'", "System.NullReferenceException");
3691 InstanceExpression = left;
3695 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3697 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3698 inst.Emit (ec, ConditionalAccess);
3700 if (prepare_for_load)
3701 ec.Emit (OpCodes.Dup);
3704 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3707 public class ExtensionMethodCandidates
3709 readonly NamespaceContainer container;
3710 readonly IList<MethodSpec> methods;
3712 readonly IMemberContext context;
3714 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3716 this.context = context;
3717 this.methods = methods;
3718 this.container = nsContainer;
3719 this.index = lookupIndex;
3722 public NamespaceContainer Container {
3728 public IMemberContext Context {
3734 public int LookupIndex {
3740 public IList<MethodSpec> Methods {
3748 // Represents a group of extension method candidates for whole namespace
3750 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3752 ExtensionMethodCandidates candidates;
3753 public Expression ExtensionExpression;
3755 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3756 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3758 this.candidates = candidates;
3759 this.ExtensionExpression = extensionExpr;
3762 public override bool IsStatic {
3763 get { return true; }
3766 public override void FlowAnalysis (FlowAnalysisContext fc)
3768 if (ConditionalAccess) {
3769 fc.BranchConditionalAccessDefiniteAssignment ();
3774 // For extension methodgroup we are not looking for base members but parent
3775 // namespace extension methods
3777 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3779 // TODO: candidates are null only when doing error reporting, that's
3780 // incorrect. We have to discover same extension methods in error mode
3781 if (candidates == null)
3784 int arity = type_arguments == null ? 0 : type_arguments.Count;
3786 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3787 if (candidates == null)
3790 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3793 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3796 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3798 // LAMESPEC: or implicit type parameter conversion
3800 return argType == extensionType ||
3801 TypeSpecComparer.IsEqual (argType, extensionType) ||
3802 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3803 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3806 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3808 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3810 // Not included in C#6
3812 ExtensionExpression = ExtensionExpression.Resolve (rc);
3813 if (ExtensionExpression == null)
3816 var argType = ExtensionExpression.Type;
3817 foreach (MethodSpec candidate in Candidates) {
3818 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3822 // TODO: Scan full hierarchy
3824 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3829 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3831 // We are already here
3835 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3837 if (arguments == null)
3838 arguments = new Arguments (1);
3840 ExtensionExpression = ExtensionExpression.Resolve (ec);
3841 if (ExtensionExpression == null)
3844 var cand = candidates;
3845 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3846 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3847 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3849 // Restore candidates in case we are running in probing mode
3852 // Store resolved argument and restore original arguments
3854 // Clean-up modified arguments for error reporting
3855 arguments.RemoveAt (0);
3859 var me = ExtensionExpression as MemberExpr;
3861 me.ResolveInstanceExpression (ec, null);
3862 var fe = me as FieldExpr;
3864 fe.Spec.MemberDefinition.SetIsUsed ();
3867 InstanceExpression = null;
3871 #region IErrorHandler Members
3873 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3878 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3880 rc.Report.SymbolRelatedToPreviousError (best);
3883 rc.Report.Error (1929, loc,
3884 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3885 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3887 rc.Report.Error (1928, loc,
3888 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3889 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3895 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3900 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3909 /// MethodGroupExpr represents a group of method candidates which
3910 /// can be resolved to the best method overload
3912 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3914 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3916 protected IList<MemberSpec> Methods;
3917 MethodSpec best_candidate;
3918 TypeSpec best_candidate_return;
3919 protected TypeArguments type_arguments;
3921 SimpleName simple_name;
3922 protected TypeSpec queried_type;
3924 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3928 this.type = InternalType.MethodGroup;
3930 eclass = ExprClass.MethodGroup;
3931 queried_type = type;
3934 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3935 : this (new MemberSpec[] { m }, type, loc)
3941 public MethodSpec BestCandidate {
3943 return best_candidate;
3947 public TypeSpec BestCandidateReturnType {
3949 return best_candidate_return;
3953 public IList<MemberSpec> Candidates {
3959 protected override TypeSpec DeclaringType {
3961 return queried_type;
3965 public bool IsConditionallyExcluded {
3967 return Methods == Excluded;
3971 public override bool IsInstance {
3973 if (best_candidate != null)
3974 return !best_candidate.IsStatic;
3980 public override bool IsSideEffectFree {
3982 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3986 public override bool IsStatic {
3988 if (best_candidate != null)
3989 return best_candidate.IsStatic;
3995 public override string KindName {
3996 get { return "method"; }
3999 public override string Name {
4001 if (best_candidate != null)
4002 return best_candidate.Name;
4005 return Methods.First ().Name;
4012 // When best candidate is already know this factory can be used
4013 // to avoid expensive overload resolution to be called
4015 // NOTE: InstanceExpression has to be set manually
4017 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4019 return new MethodGroupExpr (best, queriedType, loc) {
4020 best_candidate = best,
4021 best_candidate_return = best.ReturnType
4025 public override string GetSignatureForError ()
4027 if (best_candidate != null)
4028 return best_candidate.GetSignatureForError ();
4030 return Methods.First ().GetSignatureForError ();
4033 public override Expression CreateExpressionTree (ResolveContext ec)
4035 if (best_candidate == null) {
4036 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4040 if (IsConditionallyExcluded)
4041 ec.Report.Error (765, loc,
4042 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4044 if (ConditionalAccess)
4045 Error_NullShortCircuitInsideExpressionTree (ec);
4047 return new TypeOfMethod (best_candidate, loc);
4050 protected override Expression DoResolve (ResolveContext ec)
4052 this.eclass = ExprClass.MethodGroup;
4054 if (InstanceExpression != null) {
4055 InstanceExpression = InstanceExpression.Resolve (ec);
4056 if (InstanceExpression == null)
4063 public override void Emit (EmitContext ec)
4065 throw new NotSupportedException ();
4068 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4070 var call = new CallEmitter ();
4071 call.InstanceExpression = InstanceExpression;
4072 call.ConditionalAccess = ConditionalAccess;
4075 call.EmitStatement (ec, best_candidate, arguments, loc);
4077 call.Emit (ec, best_candidate, arguments, loc);
4080 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4082 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4083 Statement = statement
4086 EmitCall (ec, arguments, statement);
4088 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4091 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4093 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4094 Name, target.GetSignatureForError ());
4097 public bool HasAccessibleCandidate (ResolveContext rc)
4099 foreach (var candidate in Candidates) {
4100 if (candidate.IsAccessible (rc))
4107 public static bool IsExtensionMethodArgument (Expression expr)
4110 // LAMESPEC: No details about which expressions are not allowed
4112 return !(expr is TypeExpr) && !(expr is BaseThis);
4116 /// Find the Applicable Function Members (7.4.2.1)
4118 /// me: Method Group expression with the members to select.
4119 /// it might contain constructors or methods (or anything
4120 /// that maps to a method).
4122 /// Arguments: ArrayList containing resolved Argument objects.
4124 /// loc: The location if we want an error to be reported, or a Null
4125 /// location for "probing" purposes.
4127 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4128 /// that is the best match of me on Arguments.
4131 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4133 // TODO: causes issues with probing mode, remove explicit Kind check
4134 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4137 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4138 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4139 r.BaseMembersProvider = this;
4140 r.InstanceQualifier = this;
4143 if (cerrors != null)
4144 r.CustomErrors = cerrors;
4146 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4147 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4148 if (best_candidate == null) {
4149 if (!r.BestCandidateIsDynamic)
4152 if (simple_name != null && ec.IsStatic)
4153 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4158 // Overload resolver had to create a new method group, all checks bellow have already been executed
4159 if (r.BestCandidateNewMethodGroup != null)
4160 return r.BestCandidateNewMethodGroup;
4162 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4163 if (InstanceExpression != null) {
4164 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4165 InstanceExpression = null;
4167 if (simple_name != null && best_candidate.IsStatic) {
4168 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4171 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4175 ResolveInstanceExpression (ec, null);
4178 var base_override = CandidateToBaseOverride (ec, best_candidate);
4179 if (base_override == best_candidate) {
4180 best_candidate_return = r.BestCandidateReturnType;
4182 best_candidate = base_override;
4183 best_candidate_return = best_candidate.ReturnType;
4186 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4187 ConstraintChecker cc = new ConstraintChecker (ec);
4188 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4192 // Additional check for possible imported base override method which
4193 // could not be done during IsOverrideMethodBaseTypeAccessible
4195 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4196 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4197 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4198 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4201 // Speed up the check by not doing it on disallowed targets
4202 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4208 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4210 var fe = left as FieldExpr;
4213 // Using method-group on struct fields makes the struct assigned. I am not sure
4214 // why but that's what .net does
4216 fe.Spec.MemberDefinition.SetIsAssigned ();
4219 simple_name = original;
4220 return base.ResolveMemberAccess (ec, left, original);
4223 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4225 type_arguments = ta;
4228 #region IBaseMembersProvider Members
4230 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4232 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4235 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4237 if (queried_type == member.DeclaringType)
4240 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4241 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4245 // Extension methods lookup after ordinary methods candidates failed to apply
4247 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4249 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4252 if (!IsExtensionMethodArgument (InstanceExpression))
4255 int arity = type_arguments == null ? 0 : type_arguments.Count;
4256 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4257 if (methods == null)
4260 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4261 emg.SetTypeArguments (rc, type_arguments);
4268 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4270 public ConstructorInstanceQualifier (TypeSpec type)
4273 InstanceType = type;
4276 public TypeSpec InstanceType { get; private set; }
4278 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4280 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4284 public struct OverloadResolver
4287 public enum Restrictions
4291 ProbingOnly = 1 << 1,
4292 CovariantDelegate = 1 << 2,
4293 NoBaseMembers = 1 << 3,
4294 BaseMembersIncluded = 1 << 4,
4295 GetEnumeratorLookup = 1 << 5
4298 public interface IBaseMembersProvider
4300 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4301 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4302 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4305 public interface IErrorHandler
4307 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4308 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4309 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4310 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4313 public interface IInstanceQualifier
4315 TypeSpec InstanceType { get; }
4316 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4319 sealed class NoBaseMembers : IBaseMembersProvider
4321 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4323 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4328 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4333 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4339 struct AmbiguousCandidate
4341 public readonly MemberSpec Member;
4342 public readonly bool Expanded;
4343 public readonly AParametersCollection Parameters;
4345 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4348 Parameters = parameters;
4349 Expanded = expanded;
4354 IList<MemberSpec> members;
4355 TypeArguments type_arguments;
4356 IBaseMembersProvider base_provider;
4357 IErrorHandler custom_errors;
4358 IInstanceQualifier instance_qualifier;
4359 Restrictions restrictions;
4360 MethodGroupExpr best_candidate_extension_group;
4361 TypeSpec best_candidate_return_type;
4363 SessionReportPrinter lambda_conv_msgs;
4365 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4366 : this (members, null, restrictions, loc)
4370 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4373 if (members == null || members.Count == 0)
4374 throw new ArgumentException ("empty members set");
4376 this.members = members;
4378 type_arguments = targs;
4379 this.restrictions = restrictions;
4380 if (IsDelegateInvoke)
4381 this.restrictions |= Restrictions.NoBaseMembers;
4383 base_provider = NoBaseMembers.Instance;
4388 public IBaseMembersProvider BaseMembersProvider {
4390 return base_provider;
4393 base_provider = value;
4397 public bool BestCandidateIsDynamic { get; set; }
4400 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4402 public MethodGroupExpr BestCandidateNewMethodGroup {
4404 return best_candidate_extension_group;
4409 // Return type can be different between best candidate and closest override
4411 public TypeSpec BestCandidateReturnType {
4413 return best_candidate_return_type;
4417 public IErrorHandler CustomErrors {
4419 return custom_errors;
4422 custom_errors = value;
4426 TypeSpec DelegateType {
4428 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4429 throw new InternalErrorException ("Not running in delegate mode", loc);
4431 return members [0].DeclaringType;
4435 public IInstanceQualifier InstanceQualifier {
4437 return instance_qualifier;
4440 instance_qualifier = value;
4444 bool IsProbingOnly {
4446 return (restrictions & Restrictions.ProbingOnly) != 0;
4450 bool IsDelegateInvoke {
4452 return (restrictions & Restrictions.DelegateInvoke) != 0;
4459 // 7.4.3.3 Better conversion from expression
4460 // Returns : 1 if a->p is better,
4461 // 2 if a->q is better,
4462 // 0 if neither is better
4464 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4466 TypeSpec argument_type = a.Type;
4469 // If argument is an anonymous function
4471 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4473 // p and q are delegate types or expression tree types
4475 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4476 if (q.MemberDefinition != p.MemberDefinition) {
4481 // Uwrap delegate from Expression<T>
4483 q = TypeManager.GetTypeArguments (q)[0];
4484 p = TypeManager.GetTypeArguments (p)[0];
4487 var p_m = Delegate.GetInvokeMethod (p);
4488 var q_m = Delegate.GetInvokeMethod (q);
4491 // With identical parameter lists
4493 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4501 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4503 if (p.Kind == MemberKind.Void) {
4504 return q.Kind != MemberKind.Void ? 2 : 0;
4508 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4510 if (q.Kind == MemberKind.Void) {
4511 return p.Kind != MemberKind.Void ? 1: 0;
4514 var am = (AnonymousMethodExpression) a.Expr;
4517 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4518 // better conversion is performed between underlying types Y1 and Y2
4520 if (p.IsGenericTask || q.IsGenericTask) {
4521 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4522 q = q.TypeArguments[0];
4523 p = p.TypeArguments[0];
4529 // An inferred return type X exists for E in the context of that parameter list, and
4530 // the conversion from X to Y1 is better than the conversion from X to Y2
4532 argument_type = am.InferReturnType (ec, null, orig_q);
4533 if (argument_type == null) {
4534 // TODO: Can this be hit?
4538 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4539 argument_type = ec.BuiltinTypes.Object;
4543 if (argument_type == p)
4546 if (argument_type == q)
4550 // The parameters are identicial and return type is not void, use better type conversion
4551 // on return type to determine better one
4553 return BetterTypeConversion (ec, p, q);
4557 // 7.4.3.4 Better conversion from type
4559 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4561 if (p == null || q == null)
4562 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4564 switch (p.BuiltinType) {
4565 case BuiltinTypeSpec.Type.Int:
4566 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4569 case BuiltinTypeSpec.Type.Long:
4570 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4573 case BuiltinTypeSpec.Type.SByte:
4574 switch (q.BuiltinType) {
4575 case BuiltinTypeSpec.Type.Byte:
4576 case BuiltinTypeSpec.Type.UShort:
4577 case BuiltinTypeSpec.Type.UInt:
4578 case BuiltinTypeSpec.Type.ULong:
4582 case BuiltinTypeSpec.Type.Short:
4583 switch (q.BuiltinType) {
4584 case BuiltinTypeSpec.Type.UShort:
4585 case BuiltinTypeSpec.Type.UInt:
4586 case BuiltinTypeSpec.Type.ULong:
4590 case BuiltinTypeSpec.Type.Dynamic:
4591 // Dynamic is never better
4595 switch (q.BuiltinType) {
4596 case BuiltinTypeSpec.Type.Int:
4597 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4600 case BuiltinTypeSpec.Type.Long:
4601 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4604 case BuiltinTypeSpec.Type.SByte:
4605 switch (p.BuiltinType) {
4606 case BuiltinTypeSpec.Type.Byte:
4607 case BuiltinTypeSpec.Type.UShort:
4608 case BuiltinTypeSpec.Type.UInt:
4609 case BuiltinTypeSpec.Type.ULong:
4613 case BuiltinTypeSpec.Type.Short:
4614 switch (p.BuiltinType) {
4615 case BuiltinTypeSpec.Type.UShort:
4616 case BuiltinTypeSpec.Type.UInt:
4617 case BuiltinTypeSpec.Type.ULong:
4621 case BuiltinTypeSpec.Type.Dynamic:
4622 // Dynamic is never better
4626 // FIXME: handle lifted operators
4628 // TODO: this is expensive
4629 Expression p_tmp = new EmptyExpression (p);
4630 Expression q_tmp = new EmptyExpression (q);
4632 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4633 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4635 if (p_to_q && !q_to_p)
4638 if (q_to_p && !p_to_q)
4645 /// Determines "Better function" between candidate
4646 /// and the current best match
4649 /// Returns a boolean indicating :
4650 /// false if candidate ain't better
4651 /// true if candidate is better than the current best match
4653 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4654 MemberSpec best, AParametersCollection bparam, bool best_params)
4656 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4657 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4659 bool better_at_least_one = false;
4660 bool are_equivalent = true;
4661 int args_count = args == null ? 0 : args.Count;
4665 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4668 // Default arguments are ignored for better decision
4669 if (a.IsDefaultArgument)
4673 // When comparing named argument the parameter type index has to be looked up
4674 // in original parameter set (override version for virtual members)
4676 NamedArgument na = a as NamedArgument;
4678 int idx = cparam.GetParameterIndexByName (na.Name);
4679 ct = candidate_pd.Types[idx];
4680 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4681 ct = TypeManager.GetElementType (ct);
4683 idx = bparam.GetParameterIndexByName (na.Name);
4684 bt = best_pd.Types[idx];
4685 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4686 bt = TypeManager.GetElementType (bt);
4688 ct = candidate_pd.Types[c_idx];
4689 bt = best_pd.Types[b_idx];
4691 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4692 ct = TypeManager.GetElementType (ct);
4696 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4697 bt = TypeManager.GetElementType (bt);
4702 if (TypeSpecComparer.IsEqual (ct, bt))
4705 are_equivalent = false;
4706 int result = BetterExpressionConversion (ec, a, ct, bt);
4708 // for each argument, the conversion to 'ct' should be no worse than
4709 // the conversion to 'bt'.
4713 // for at least one argument, the conversion to 'ct' should be better than
4714 // the conversion to 'bt'.
4716 better_at_least_one = true;
4719 if (better_at_least_one)
4723 // Tie-breaking rules are applied only for equivalent parameter types
4725 if (!are_equivalent) {
4727 // LAMESPEC: A candidate with less default parameters is still better when there
4728 // is no better expression conversion
4730 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4738 // If candidate is applicable in its normal form and best has a params array and is applicable
4739 // only in its expanded form, then candidate is better
4741 if (candidate_params != best_params)
4742 return !candidate_params;
4745 // We have not reached end of parameters list due to params or used default parameters
4747 while (j < candidate_pd.Count && j < best_pd.Count) {
4748 var cand_param = candidate_pd.FixedParameters [j];
4749 var best_param = best_pd.FixedParameters [j];
4751 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4752 return cand_param.HasDefaultValue;
4754 if (candidate_pd.Count == best_pd.Count) {
4758 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4759 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4762 if (cand_param.HasDefaultValue) {
4768 // Neither is better when not all arguments are provided
4770 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4771 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4772 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4780 if (candidate_pd.Count != best_pd.Count)
4781 return candidate_pd.Count < best_pd.Count;
4784 // One is a non-generic method and second is a generic method, then non-generic is better
4786 if (best.IsGeneric != candidate.IsGeneric)
4787 return best.IsGeneric;
4790 // Both methods have the same number of parameters, and the parameters have equal types
4791 // Pick the "more specific" signature using rules over original (non-inflated) types
4793 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4794 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4796 bool specific_at_least_once = false;
4797 for (j = 0; j < args_count; ++j) {
4798 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4800 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4801 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4803 ct = candidate_def_pd.Types[j];
4804 bt = best_def_pd.Types[j];
4809 TypeSpec specific = MoreSpecific (ct, bt);
4813 specific_at_least_once = true;
4816 if (specific_at_least_once)
4822 static bool CheckInflatedArguments (MethodSpec ms)
4824 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4827 // Setup constraint checker for probing only
4828 ConstraintChecker cc = new ConstraintChecker (null);
4830 var mp = ms.Parameters.Types;
4831 for (int i = 0; i < mp.Length; ++i) {
4832 var type = mp[i] as InflatedTypeSpec;
4836 var targs = type.TypeArguments;
4837 if (targs.Length == 0)
4840 // TODO: Checking inflated MVAR arguments should be enough
4841 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4848 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4850 rc.Report.Error (1729, loc,
4851 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4852 type.GetSignatureForError (), argCount.ToString ());
4856 // Determines if the candidate method is applicable to the given set of arguments
4857 // There could be two different set of parameters for same candidate where one
4858 // is the closest override for default values and named arguments checks and second
4859 // one being the virtual base for the parameter types and modifiers.
4861 // A return value rates candidate method compatibility,
4863 // 0 = the best, int.MaxValue = the worst
4865 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)
4868 // Each step has allocated 10 values, it can overflow for
4869 // more than 10 arguments but that's ok as it's used for
4870 // better error reporting only
4872 const int ArgumentCountMismatch = 1000000000;
4873 const int NamedArgumentsMismatch = 100000000;
4874 const int DefaultArgumentMismatch = 10000000;
4875 const int UnexpectedTypeArguments = 1000000;
4876 const int TypeArgumentsMismatch = 100000;
4877 const int InflatedTypesMismatch = 10000;
4879 // Parameters of most-derived type used mainly for named and optional parameters
4880 var pd = pm.Parameters;
4882 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4883 // params modifier instead of most-derived type
4884 var cpd = ((IParametersMember) candidate).Parameters;
4885 int param_count = pd.Count;
4886 int optional_count = 0;
4888 Arguments orig_args = arguments;
4890 if (arg_count != param_count) {
4892 // No arguments expansion when doing exact match for delegates
4894 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4895 for (int i = 0; i < pd.Count; ++i) {
4896 if (pd.FixedParameters[i].HasDefaultValue) {
4897 optional_count = pd.Count - i;
4903 if (optional_count != 0) {
4904 // Readjust expected number when params used
4905 if (cpd.HasParams) {
4907 if (arg_count < param_count)
4909 } else if (arg_count > param_count) {
4910 int args_gap = System.Math.Abs (arg_count - param_count);
4911 return ArgumentCountMismatch + args_gap;
4912 } else if (arg_count < param_count - optional_count) {
4913 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4914 return ArgumentCountMismatch + args_gap;
4916 } else if (arg_count != param_count) {
4917 int args_gap = System.Math.Abs (arg_count - param_count);
4919 return ArgumentCountMismatch + args_gap;
4920 if (arg_count < param_count - 1)
4921 return ArgumentCountMismatch + args_gap;
4924 // Resize to fit optional arguments
4925 if (optional_count != 0) {
4926 if (arguments == null) {
4927 arguments = new Arguments (optional_count);
4929 // Have to create a new container, so the next run can do same
4930 var resized = new Arguments (param_count);
4931 resized.AddRange (arguments);
4932 arguments = resized;
4935 for (int i = arg_count; i < param_count; ++i)
4936 arguments.Add (null);
4940 if (arg_count > 0) {
4942 // Shuffle named arguments to the right positions if there are any
4944 if (arguments[arg_count - 1] is NamedArgument) {
4945 arg_count = arguments.Count;
4947 for (int i = 0; i < arg_count; ++i) {
4948 bool arg_moved = false;
4950 NamedArgument na = arguments[i] as NamedArgument;
4954 int index = pd.GetParameterIndexByName (na.Name);
4956 // Named parameter not found
4958 return NamedArgumentsMismatch - i;
4960 // already reordered
4965 if (index >= param_count) {
4966 // When using parameters which should not be available to the user
4967 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4970 arguments.Add (null);
4974 if (index == arg_count)
4975 return NamedArgumentsMismatch - i - 1;
4977 temp = arguments [index];
4979 // The slot has been taken by positional argument
4980 if (temp != null && !(temp is NamedArgument))
4985 arguments = arguments.MarkOrderedArgument (na);
4989 if (arguments == orig_args) {
4990 arguments = new Arguments (orig_args.Count);
4991 arguments.AddRange (orig_args);
4994 arguments[index] = arguments[i];
4995 arguments[i] = temp;
5002 arg_count = arguments.Count;
5004 } else if (arguments != null) {
5005 arg_count = arguments.Count;
5009 // Don't do any expensive checks when the candidate cannot succeed
5011 if (arg_count != param_count && !cpd.HasParams)
5012 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5014 var dep = candidate.GetMissingDependencies ();
5016 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5021 // 1. Handle generic method using type arguments when specified or type inference
5024 var ms = candidate as MethodSpec;
5025 if (ms != null && ms.IsGeneric) {
5026 if (type_arguments != null) {
5027 var g_args_count = ms.Arity;
5028 if (g_args_count != type_arguments.Count)
5029 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5031 if (type_arguments.Arguments != null)
5032 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5035 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5036 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5037 // candidate was found use the set to report more details about what was wrong with lambda body.
5038 // The general idea is to distinguish between code errors and errors caused by
5039 // trial-and-error type inference
5041 if (lambda_conv_msgs == null) {
5042 for (int i = 0; i < arg_count; i++) {
5043 Argument a = arguments[i];
5047 var am = a.Expr as AnonymousMethodExpression;
5049 if (lambda_conv_msgs == null)
5050 lambda_conv_msgs = new SessionReportPrinter ();
5052 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5057 var ti = new TypeInference (arguments);
5058 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5061 return TypeArgumentsMismatch - ti.InferenceScore;
5064 // Clear any error messages when the result was success
5066 if (lambda_conv_msgs != null)
5067 lambda_conv_msgs.ClearSession ();
5069 if (i_args.Length != 0) {
5071 for (int i = 0; i < i_args.Length; ++i) {
5072 var ta = i_args [i];
5073 if (!ta.IsAccessible (ec))
5074 return TypeArgumentsMismatch - i;
5078 ms = ms.MakeGenericMethod (ec, i_args);
5083 // Type arguments constraints have to match for the method to be applicable
5085 if (!CheckInflatedArguments (ms)) {
5087 return InflatedTypesMismatch;
5091 // We have a generic return type and at same time the method is override which
5092 // means we have to also inflate override return type in case the candidate is
5093 // best candidate and override return type is different to base return type.
5095 // virtual Foo<T, object> with override Foo<T, dynamic>
5097 if (candidate != pm) {
5098 MethodSpec override_ms = (MethodSpec) pm;
5099 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5100 returnType = inflator.Inflate (returnType);
5102 returnType = ms.ReturnType;
5109 if (type_arguments != null)
5110 return UnexpectedTypeArguments;
5116 // 2. Each argument has to be implicitly convertible to method parameter
5118 Parameter.Modifier p_mod = 0;
5121 for (int i = 0; i < arg_count; i++) {
5122 Argument a = arguments[i];
5124 var fp = pd.FixedParameters[i];
5125 if (!fp.HasDefaultValue) {
5126 arguments = orig_args;
5127 return arg_count * 2 + 2;
5131 // Get the default value expression, we can use the same expression
5132 // if the type matches
5134 Expression e = fp.DefaultValue;
5136 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5138 // Restore for possible error reporting
5139 for (int ii = i; ii < arg_count; ++ii)
5140 arguments.RemoveAt (i);
5142 return (arg_count - i) * 2 + 1;
5146 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5148 // LAMESPEC: Attributes can be mixed together with build-in priority
5150 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5151 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5152 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5153 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5154 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5155 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5159 arguments[i] = new Argument (e, Argument.AType.Default);
5163 if (p_mod != Parameter.Modifier.PARAMS) {
5164 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5166 } else if (!params_expanded_form) {
5167 params_expanded_form = true;
5168 pt = ((ElementTypeSpec) pt).Element;
5174 if (!params_expanded_form) {
5175 if (a.IsExtensionType) {
5176 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5181 score = IsArgumentCompatible (ec, a, p_mod, pt);
5184 dynamicArgument = true;
5189 // It can be applicable in expanded form (when not doing exact match like for delegates)
5191 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5192 if (!params_expanded_form) {
5193 pt = ((ElementTypeSpec) pt).Element;
5197 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5200 params_expanded_form = true;
5201 dynamicArgument = true;
5202 } else if (score == 0 || arg_count > pd.Count) {
5203 params_expanded_form = true;
5208 if (params_expanded_form)
5210 return (arg_count - i) * 2 + score;
5215 // Restore original arguments for dynamic binder to keep the intention of original source code
5217 if (dynamicArgument)
5218 arguments = orig_args;
5223 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5225 if (e is Constant && e.Type == ptype)
5229 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5231 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5232 e = new MemberAccess (new MemberAccess (new MemberAccess (
5233 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5234 } else if (e is Constant) {
5236 // Handles int to int? conversions, DefaultParameterValue check
5238 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5242 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5245 return e.Resolve (ec);
5249 // Tests argument compatibility with the parameter
5250 // The possible return values are
5252 // 1 - modifier mismatch
5253 // 2 - type mismatch
5254 // -1 - dynamic binding required
5256 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5259 // Types have to be identical when ref or out modifer
5260 // is used and argument is not of dynamic type
5262 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5263 var arg_type = argument.Type;
5265 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5267 // Using dynamic for ref/out parameter can still succeed at runtime
5269 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5275 if (arg_type != parameter) {
5276 if (arg_type == InternalType.VarOutType)
5280 // Do full equality check after quick path
5282 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5284 // Using dynamic for ref/out parameter can still succeed at runtime
5286 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5294 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5298 // Use implicit conversion in all modes to return same candidates when the expression
5299 // is used as argument or delegate conversion
5301 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5302 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5309 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5311 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5313 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5316 var ac_p = p as ArrayContainer;
5318 var ac_q = q as ArrayContainer;
5322 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5323 if (specific == ac_p.Element)
5325 if (specific == ac_q.Element)
5327 } else if (p.IsGeneric && q.IsGeneric) {
5328 var pargs = TypeManager.GetTypeArguments (p);
5329 var qargs = TypeManager.GetTypeArguments (q);
5331 bool p_specific_at_least_once = false;
5332 bool q_specific_at_least_once = false;
5334 for (int i = 0; i < pargs.Length; i++) {
5335 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5336 if (specific == pargs[i])
5337 p_specific_at_least_once = true;
5338 if (specific == qargs[i])
5339 q_specific_at_least_once = true;
5342 if (p_specific_at_least_once && !q_specific_at_least_once)
5344 if (!p_specific_at_least_once && q_specific_at_least_once)
5352 // Find the best method from candidate list
5354 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5356 List<AmbiguousCandidate> ambiguous_candidates = null;
5358 MemberSpec best_candidate;
5359 Arguments best_candidate_args = null;
5360 bool best_candidate_params = false;
5361 bool best_candidate_dynamic = false;
5362 int best_candidate_rate;
5363 IParametersMember best_parameter_member = null;
5365 int args_count = args != null ? args.Count : 0;
5367 Arguments candidate_args = args;
5368 bool error_mode = false;
5369 MemberSpec invocable_member = null;
5370 int applicable_candidates = 0;
5373 best_candidate = null;
5374 best_candidate_rate = int.MaxValue;
5376 var type_members = members;
5378 for (int i = 0; i < type_members.Count; ++i) {
5379 var member = type_members[i];
5382 // Methods in a base class are not candidates if any method in a derived
5383 // class is applicable
5385 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5389 if (!member.IsAccessible (rc))
5392 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5395 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5396 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5401 IParametersMember pm = member as IParametersMember;
5404 // Will use it later to report ambiguity between best method and invocable member
5406 if (Invocation.IsMemberInvocable (member))
5407 invocable_member = member;
5413 // Overload resolution is looking for base member but using parameter names
5414 // and default values from the closest member. That means to do expensive lookup
5415 // for the closest override for virtual or abstract members
5417 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5418 var override_params = base_provider.GetOverrideMemberParameters (member);
5419 if (override_params != null)
5420 pm = override_params;
5424 // Check if the member candidate is applicable
5426 bool params_expanded_form = false;
5427 bool dynamic_argument = false;
5428 TypeSpec rt = pm.MemberType;
5429 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5431 if (lambda_conv_msgs != null)
5432 lambda_conv_msgs.EndSession ();
5435 // How does it score compare to others
5437 if (candidate_rate < best_candidate_rate) {
5439 // Fatal error (missing dependency), cannot continue
5440 if (candidate_rate < 0)
5443 applicable_candidates = 1;
5444 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5445 // Only parameterless methods are considered
5447 best_candidate_rate = candidate_rate;
5448 best_candidate = member;
5449 best_candidate_args = candidate_args;
5450 best_candidate_params = params_expanded_form;
5451 best_candidate_dynamic = dynamic_argument;
5452 best_parameter_member = pm;
5453 best_candidate_return_type = rt;
5455 } else if (candidate_rate == 0) {
5457 // The member look is done per type for most operations but sometimes
5458 // it's not possible like for binary operators overload because they
5459 // are unioned between 2 sides
5461 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5462 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5466 ++applicable_candidates;
5468 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5470 // We pack all interface members into top level type which makes the overload resolution
5471 // more complicated for interfaces. We compensate it by removing methods with same
5472 // signature when building the cache hence this path should not really be hit often
5475 // interface IA { void Foo (int arg); }
5476 // interface IB : IA { void Foo (params int[] args); }
5478 // IB::Foo is the best overload when calling IB.Foo (1)
5481 if (ambiguous_candidates != null) {
5482 foreach (var amb_cand in ambiguous_candidates) {
5483 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5492 ambiguous_candidates = null;
5495 // Is the new candidate better
5496 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5500 best_candidate = member;
5501 best_candidate_args = candidate_args;
5502 best_candidate_params = params_expanded_form;
5503 best_candidate_dynamic = dynamic_argument;
5504 best_parameter_member = pm;
5505 best_candidate_return_type = rt;
5507 // It's not better but any other found later could be but we are not sure yet
5508 if (ambiguous_candidates == null)
5509 ambiguous_candidates = new List<AmbiguousCandidate> ();
5511 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5515 // Restore expanded arguments
5516 candidate_args = args;
5518 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5521 // We've found exact match
5523 if (best_candidate_rate == 0)
5527 // Try extension methods lookup when no ordinary method match was found and provider enables it
5530 var emg = base_provider.LookupExtensionMethod (rc);
5532 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5534 best_candidate_extension_group = emg;
5535 return (T) (MemberSpec) emg.BestCandidate;
5540 // Don't run expensive error reporting mode for probing
5547 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5550 lambda_conv_msgs = null;
5555 // No best member match found, report an error
5557 if (best_candidate_rate != 0 || error_mode) {
5558 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5562 if (best_candidate_dynamic) {
5563 if (args[0].IsExtensionType) {
5564 rc.Report.Error (1973, loc,
5565 "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",
5566 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5570 // Check type constraints only when explicit type arguments are used
5572 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5573 MethodSpec bc = best_candidate as MethodSpec;
5574 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5575 ConstraintChecker cc = new ConstraintChecker (rc);
5576 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5580 BestCandidateIsDynamic = true;
5585 // These flags indicates we are running delegate probing conversion. No need to
5586 // do more expensive checks
5588 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5589 return (T) best_candidate;
5591 if (ambiguous_candidates != null) {
5593 // Now check that there are no ambiguities i.e the selected method
5594 // should be better than all the others
5596 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5597 var candidate = ambiguous_candidates [ix];
5599 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5600 var ambiguous = candidate.Member;
5601 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5602 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5603 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5604 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5605 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5608 return (T) best_candidate;
5613 if (invocable_member != null && !IsProbingOnly) {
5614 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5615 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5616 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5617 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5621 // And now check if the arguments are all
5622 // compatible, perform conversions if
5623 // necessary etc. and return if everything is
5626 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5629 if (best_candidate == null)
5633 // Don't run possibly expensive checks in probing mode
5635 if (!IsProbingOnly && !rc.IsInProbingMode) {
5637 // Check ObsoleteAttribute on the best method
5639 best_candidate.CheckObsoleteness (rc, loc);
5641 best_candidate.MemberDefinition.SetIsUsed ();
5644 args = best_candidate_args;
5645 return (T) best_candidate;
5648 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5650 return ResolveMember<MethodSpec> (rc, ref args);
5653 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5654 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5656 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5659 if (a.Type == InternalType.ErrorType)
5662 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5663 ec.Report.SymbolRelatedToPreviousError (method);
5664 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5665 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5666 TypeManager.CSharpSignature (method));
5669 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5670 TypeManager.CSharpSignature (method));
5671 } else if (IsDelegateInvoke) {
5672 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5673 DelegateType.GetSignatureForError ());
5675 ec.Report.SymbolRelatedToPreviousError (method);
5676 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5677 method.GetSignatureForError ());
5680 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5682 string index = (idx + 1).ToString ();
5683 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5684 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5685 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5686 index, Parameter.GetModifierSignature (a.Modifier));
5688 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5689 index, Parameter.GetModifierSignature (mod));
5691 string p1 = a.GetSignatureForError ();
5692 string p2 = paramType.GetSignatureForError ();
5695 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5696 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5699 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5700 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5701 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5704 ec.Report.Error (1503, a.Expr.Location,
5705 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5710 // We have failed to find exact match so we return error info about the closest match
5712 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5714 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5715 int arg_count = args == null ? 0 : args.Count;
5717 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5718 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5719 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5723 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5728 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5729 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5730 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5734 // For candidates which match on parameters count report more details about incorrect arguments
5737 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5738 // Reject any inaccessible member
5739 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5740 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5741 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5745 var ms = best_candidate as MethodSpec;
5746 if (ms != null && ms.IsGeneric) {
5747 bool constr_ok = true;
5748 if (ms.TypeArguments != null)
5749 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5751 if (ta_count == 0 && ms.TypeArguments == null) {
5752 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5756 rc.Report.Error (411, loc,
5757 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5758 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5765 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5771 // We failed to find any method with correct argument count, report best candidate
5773 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5776 if (best_candidate.Kind == MemberKind.Constructor) {
5777 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5778 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5779 } else if (IsDelegateInvoke) {
5780 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5781 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5782 DelegateType.GetSignatureForError (), arg_count.ToString ());
5784 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5785 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5786 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5787 name, arg_count.ToString ());
5791 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5793 var p = ((IParametersMember)best_candidate).Parameters;
5798 for (int i = p.Count - 1; i != 0; --i) {
5799 var fp = p.FixedParameters [i];
5800 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5810 foreach (var arg in args) {
5811 var na = arg as NamedArgument;
5815 if (na.Name == name) {
5824 return args.Count + 1 == pm.Parameters.Count;
5827 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5829 var pd = pm.Parameters;
5830 var cpd = ((IParametersMember) member).Parameters;
5831 var ptypes = cpd.Types;
5833 Parameter.Modifier p_mod = 0;
5835 int a_idx = 0, a_pos = 0;
5837 ArrayInitializer params_initializers = null;
5838 bool has_unsafe_arg = pm.MemberType.IsPointer;
5839 int arg_count = args == null ? 0 : args.Count;
5841 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5846 if (p_mod != Parameter.Modifier.PARAMS) {
5847 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5849 has_unsafe_arg |= pt.IsPointer;
5851 if (p_mod == Parameter.Modifier.PARAMS) {
5852 if (chose_params_expanded) {
5853 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5854 pt = TypeManager.GetElementType (pt);
5860 // Types have to be identical when ref or out modifer is used
5862 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5863 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5866 var arg_type = a.Type;
5870 if (arg_type == InternalType.VarOutType) {
5872 // Set underlying variable type based on parameter type
5874 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5878 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5882 NamedArgument na = a as NamedArgument;
5884 int name_index = pd.GetParameterIndexByName (na.Name);
5885 if (name_index < 0 || name_index >= pd.Count) {
5886 if (IsDelegateInvoke) {
5887 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5888 ec.Report.Error (1746, na.Location,
5889 "The delegate `{0}' does not contain a parameter named `{1}'",
5890 DelegateType.GetSignatureForError (), na.Name);
5892 ec.Report.SymbolRelatedToPreviousError (member);
5893 ec.Report.Error (1739, na.Location,
5894 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5895 TypeManager.CSharpSignature (member), na.Name);
5897 } else if (args[name_index] != a && args[name_index] != null) {
5898 if (IsDelegateInvoke)
5899 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5901 ec.Report.SymbolRelatedToPreviousError (member);
5903 ec.Report.Error (1744, na.Location,
5904 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5909 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5912 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5913 if (a.IsExtensionType) {
5914 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5915 // CS1061 but that still better than confusing CS0123
5916 var ma = new MemberAccess (a.Expr, member.Name, loc);
5917 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5919 custom_errors.NoArgumentMatch (ec, member);
5925 if (a.IsExtensionType) {
5926 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5929 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5931 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5934 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5941 // Convert params arguments to an array initializer
5943 if (params_initializers != null) {
5944 // we choose to use 'a.Expr' rather than 'conv' so that
5945 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5946 params_initializers.Add (a.Expr);
5947 args.RemoveAt (a_idx--);
5953 // Update the argument with the implicit conversion
5957 if (a_idx != arg_count) {
5959 // Convert all var out argument to error type for less confusing error reporting
5960 // when no matching overload is found
5962 for (; a_idx < arg_count; a_idx++) {
5963 var arg = args [a_idx];
5967 if (arg.Type == InternalType.VarOutType) {
5968 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5972 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5977 // Fill not provided arguments required by params modifier
5979 if (params_initializers == null && arg_count + 1 == pd.Count) {
5981 args = new Arguments (1);
5983 pt = ptypes[pd.Count - 1];
5984 pt = TypeManager.GetElementType (pt);
5985 has_unsafe_arg |= pt.IsPointer;
5986 params_initializers = new ArrayInitializer (0, loc);
5990 // Append an array argument with all params arguments
5992 if (params_initializers != null) {
5993 args.Add (new Argument (
5994 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5998 if (has_unsafe_arg && !ec.IsUnsafe) {
5999 Expression.UnsafeError (ec, loc);
6003 // We could infer inaccesible type arguments
6005 if (type_arguments == null && member.IsGeneric) {
6006 var ms = (MethodSpec) member;
6007 foreach (var ta in ms.TypeArguments) {
6008 if (!ta.IsAccessible (ec)) {
6009 ec.Report.SymbolRelatedToPreviousError (ta);
6010 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6020 public class ConstantExpr : MemberExpr
6022 readonly ConstSpec constant;
6024 public ConstantExpr (ConstSpec constant, Location loc)
6026 this.constant = constant;
6030 public override string Name {
6031 get { throw new NotImplementedException (); }
6034 public override string KindName {
6035 get { return "constant"; }
6038 public override bool IsInstance {
6039 get { return !IsStatic; }
6042 public override bool IsStatic {
6043 get { return true; }
6046 protected override TypeSpec DeclaringType {
6047 get { return constant.DeclaringType; }
6050 public override Expression CreateExpressionTree (ResolveContext ec)
6052 throw new NotSupportedException ("ET");
6055 protected override Expression DoResolve (ResolveContext rc)
6057 ResolveInstanceExpression (rc, null);
6058 DoBestMemberChecks (rc, constant);
6060 var c = constant.GetConstant (rc);
6062 // Creates reference expression to the constant value
6063 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6066 public override void Emit (EmitContext ec)
6068 throw new NotSupportedException ();
6071 public override string GetSignatureForError ()
6073 return constant.GetSignatureForError ();
6076 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6078 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6083 // Fully resolved expression that references a Field
6085 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6087 protected FieldSpec spec;
6088 VariableInfo variable_info;
6090 LocalTemporary temp;
6093 protected FieldExpr (Location l)
6098 public FieldExpr (FieldSpec spec, Location loc)
6103 type = spec.MemberType;
6106 public FieldExpr (FieldBase fi, Location l)
6113 public override string Name {
6119 public bool IsHoisted {
6121 IVariableReference hv = InstanceExpression as IVariableReference;
6122 return hv != null && hv.IsHoisted;
6126 public override bool IsInstance {
6128 return !spec.IsStatic;
6132 public override bool IsStatic {
6134 return spec.IsStatic;
6138 public override string KindName {
6139 get { return "field"; }
6142 public FieldSpec Spec {
6148 protected override TypeSpec DeclaringType {
6150 return spec.DeclaringType;
6154 public VariableInfo VariableInfo {
6156 return variable_info;
6162 public override string GetSignatureForError ()
6164 return spec.GetSignatureForError ();
6167 public bool IsMarshalByRefAccess (ResolveContext rc)
6169 // Checks possible ldflda of field access expression
6170 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6171 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6172 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6175 public void SetHasAddressTaken ()
6177 IVariableReference vr = InstanceExpression as IVariableReference;
6179 vr.SetHasAddressTaken ();
6183 protected override void CloneTo (CloneContext clonectx, Expression target)
6185 var t = (FieldExpr) target;
6187 if (InstanceExpression != null)
6188 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6191 public override Expression CreateExpressionTree (ResolveContext ec)
6193 if (ConditionalAccess) {
6194 Error_NullShortCircuitInsideExpressionTree (ec);
6197 return CreateExpressionTree (ec, true);
6200 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6203 Expression instance;
6205 if (InstanceExpression == null) {
6206 instance = new NullLiteral (loc);
6207 } else if (convertInstance) {
6208 instance = InstanceExpression.CreateExpressionTree (ec);
6210 args = new Arguments (1);
6211 args.Add (new Argument (InstanceExpression));
6212 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6215 args = Arguments.CreateForExpressionTree (ec, null,
6217 CreateTypeOfExpression ());
6219 return CreateExpressionFactoryCall (ec, "Field", args);
6222 public Expression CreateTypeOfExpression ()
6224 return new TypeOfField (spec, loc);
6227 protected override Expression DoResolve (ResolveContext ec)
6229 spec.MemberDefinition.SetIsUsed ();
6231 return DoResolve (ec, null);
6234 Expression DoResolve (ResolveContext ec, Expression rhs)
6236 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6239 ResolveConditionalAccessReceiver (ec);
6241 if (ResolveInstanceExpression (ec, rhs)) {
6242 // Resolve the field's instance expression while flow analysis is turned
6243 // off: when accessing a field "a.b", we must check whether the field
6244 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6246 if (lvalue_instance) {
6247 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6249 Expression right_side =
6250 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6252 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6254 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6257 if (InstanceExpression == null)
6261 DoBestMemberChecks (ec, spec);
6263 if (conditional_access_receiver)
6264 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6267 var fb = spec as FixedFieldSpec;
6268 IVariableReference var = InstanceExpression as IVariableReference;
6271 IFixedExpression fe = InstanceExpression as IFixedExpression;
6272 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6273 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6276 if (InstanceExpression.eclass != ExprClass.Variable) {
6277 ec.Report.SymbolRelatedToPreviousError (spec);
6278 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6279 TypeManager.GetFullNameSignature (spec));
6280 } else if (var != null && var.IsHoisted) {
6281 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6284 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6288 // Set flow-analysis variable info for struct member access. It will be check later
6289 // for precise error reporting
6291 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6292 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6295 if (ConditionalAccess) {
6296 if (conditional_access_receiver)
6297 type = LiftMemberType (ec, type);
6299 if (InstanceExpression.IsNull)
6300 return Constant.CreateConstantFromValue (type, null, loc);
6303 eclass = ExprClass.Variable;
6307 public void SetFieldAssigned (FlowAnalysisContext fc)
6312 bool lvalue_instance = spec.DeclaringType.IsStruct;
6313 if (lvalue_instance) {
6314 var var = InstanceExpression as IVariableReference;
6315 if (var != null && var.VariableInfo != null) {
6316 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6320 var fe = InstanceExpression as FieldExpr;
6322 Expression instance;
6325 instance = fe.InstanceExpression;
6326 var fe_instance = instance as FieldExpr;
6327 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6328 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6329 var var = InstanceExpression as IVariableReference;
6330 if (var != null && var.VariableInfo == null) {
6331 var var_inst = instance as IVariableReference;
6332 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6333 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6337 if (fe_instance != null) {
6346 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6347 instance.FlowAnalysis (fc);
6349 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6350 InstanceExpression.FlowAnalysis (fc);
6354 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6356 // The return value is always null. Returning a value simplifies calling code.
6358 if (right_side == EmptyExpression.OutAccess) {
6360 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6361 GetSignatureForError ());
6363 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6364 GetSignatureForError ());
6370 if (right_side == EmptyExpression.LValueMemberAccess) {
6371 // Already reported as CS1648/CS1650
6375 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6377 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6378 GetSignatureForError ());
6380 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6381 GetSignatureForError ());
6387 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6388 GetSignatureForError ());
6390 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6391 GetSignatureForError ());
6397 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6399 if (HasConditionalAccess ())
6400 Error_NullPropagatingLValue (ec);
6402 if (spec is FixedFieldSpec) {
6403 // It could be much better error message but we want to be error compatible
6404 Error_ValueAssignment (ec, right_side);
6407 Expression e = DoResolve (ec, right_side);
6412 spec.MemberDefinition.SetIsAssigned ();
6414 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6415 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6416 ec.Report.Warning (420, 1, loc,
6417 "`{0}': A volatile field references will not be treated as volatile",
6418 spec.GetSignatureForError ());
6421 if (spec.IsReadOnly) {
6422 // InitOnly fields can only be assigned in constructors or initializers
6423 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6424 return Error_AssignToReadonly (ec, right_side);
6426 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6428 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6429 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6430 return Error_AssignToReadonly (ec, right_side);
6431 // static InitOnly fields cannot be assigned-to in an instance constructor
6432 if (IsStatic && !ec.IsStatic)
6433 return Error_AssignToReadonly (ec, right_side);
6434 // instance constructors can't modify InitOnly fields of other instances of the same type
6435 if (!IsStatic && !(InstanceExpression is This))
6436 return Error_AssignToReadonly (ec, right_side);
6440 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6441 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6442 ec.Report.Warning (197, 1, loc,
6443 "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",
6444 GetSignatureForError ());
6447 eclass = ExprClass.Variable;
6451 public override void FlowAnalysis (FlowAnalysisContext fc)
6453 var var = InstanceExpression as IVariableReference;
6455 var vi = var.VariableInfo;
6456 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6457 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6461 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6462 var le = SkipLeftValueTypeAccess (InstanceExpression);
6464 le.FlowAnalysis (fc);
6470 base.FlowAnalysis (fc);
6472 if (conditional_access_receiver)
6473 fc.ConditionalAccessEnd ();
6476 static Expression SkipLeftValueTypeAccess (Expression expr)
6478 if (!TypeSpec.IsValueType (expr.Type))
6481 if (expr is VariableReference)
6484 var fe = expr as FieldExpr;
6488 if (fe.InstanceExpression == null)
6491 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6494 public override int GetHashCode ()
6496 return spec.GetHashCode ();
6499 public bool IsFixed {
6502 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6504 IVariableReference variable = InstanceExpression as IVariableReference;
6505 if (variable != null)
6506 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6508 IFixedExpression fe = InstanceExpression as IFixedExpression;
6509 return fe != null && fe.IsFixed;
6513 public override bool Equals (object obj)
6515 FieldExpr fe = obj as FieldExpr;
6519 if (spec != fe.spec)
6522 if (InstanceExpression == null || fe.InstanceExpression == null)
6525 return InstanceExpression.Equals (fe.InstanceExpression);
6528 public void Emit (EmitContext ec, bool leave_copy)
6530 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6534 ec.Emit (OpCodes.Volatile);
6536 ec.Emit (OpCodes.Ldsfld, spec);
6539 if (conditional_access_receiver)
6540 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6542 EmitInstance (ec, false);
6545 // Optimization for build-in types
6546 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6547 ec.EmitLoadFromPtr (type);
6549 var ff = spec as FixedFieldSpec;
6551 ec.Emit (OpCodes.Ldflda, spec);
6552 ec.Emit (OpCodes.Ldflda, ff.Element);
6555 ec.Emit (OpCodes.Volatile);
6557 ec.Emit (OpCodes.Ldfld, spec);
6561 if (conditional_access_receiver) {
6562 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6567 ec.Emit (OpCodes.Dup);
6569 temp = new LocalTemporary (this.Type);
6575 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6577 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6578 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6583 if (ConditionalAccess)
6584 throw new NotImplementedException ("null operator assignment");
6586 if (has_await_source)
6587 source = source.EmitToField (ec);
6589 EmitInstance (ec, prepared);
6594 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6595 ec.Emit (OpCodes.Dup);
6597 temp = new LocalTemporary (this.Type);
6602 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6603 ec.Emit (OpCodes.Volatile);
6605 spec.MemberDefinition.SetIsAssigned ();
6608 ec.Emit (OpCodes.Stsfld, spec);
6610 ec.Emit (OpCodes.Stfld, spec);
6612 if (ec.NotifyEvaluatorOnStore) {
6614 throw new NotImplementedException ("instance field write");
6617 ec.Emit (OpCodes.Dup);
6619 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6630 // Emits store to field with prepared values on stack
6632 public void EmitAssignFromStack (EmitContext ec)
6635 ec.Emit (OpCodes.Stsfld, spec);
6637 ec.Emit (OpCodes.Stfld, spec);
6641 public override void Emit (EmitContext ec)
6646 public override void EmitSideEffect (EmitContext ec)
6648 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6650 if (is_volatile) // || is_marshal_by_ref ())
6651 base.EmitSideEffect (ec);
6654 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6656 if ((mode & AddressOp.Store) != 0)
6657 spec.MemberDefinition.SetIsAssigned ();
6658 if ((mode & AddressOp.Load) != 0)
6659 spec.MemberDefinition.SetIsUsed ();
6662 // Handle initonly fields specially: make a copy and then
6663 // get the address of the copy.
6666 if (spec.IsReadOnly){
6668 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6680 var temp = ec.GetTemporaryLocal (type);
6681 ec.Emit (OpCodes.Stloc, temp);
6682 ec.Emit (OpCodes.Ldloca, temp);
6688 ec.Emit (OpCodes.Ldsflda, spec);
6691 EmitInstance (ec, false);
6692 ec.Emit (OpCodes.Ldflda, spec);
6696 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6698 return MakeExpression (ctx);
6701 public override SLE.Expression MakeExpression (BuilderContext ctx)
6704 return base.MakeExpression (ctx);
6706 return SLE.Expression.Field (
6707 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6708 spec.GetMetaInfo ());
6712 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6714 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6720 // Expression that evaluates to a Property.
6722 // This is not an LValue because we need to re-write the expression. We
6723 // can not take data from the stack and store it.
6725 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6727 Arguments arguments;
6728 FieldExpr backing_field;
6730 public PropertyExpr (PropertySpec spec, Location l)
6733 best_candidate = spec;
6734 type = spec.MemberType;
6739 protected override Arguments Arguments {
6748 protected override TypeSpec DeclaringType {
6750 return best_candidate.DeclaringType;
6754 public override string Name {
6756 return best_candidate.Name;
6760 public bool IsAutoPropertyAccess {
6762 var prop = best_candidate.MemberDefinition as Property;
6763 return prop != null && prop.BackingField != null;
6767 public override bool IsInstance {
6773 public override bool IsStatic {
6775 return best_candidate.IsStatic;
6779 public override string KindName {
6780 get { return "property"; }
6783 public PropertySpec PropertyInfo {
6785 return best_candidate;
6791 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6793 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6796 var args_count = arguments == null ? 0 : arguments.Count;
6797 if (args_count != body.Parameters.Count && args_count == 0)
6800 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6801 mg.InstanceExpression = InstanceExpression;
6806 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6808 return new PropertyExpr (spec, loc) {
6814 public override Expression CreateExpressionTree (ResolveContext ec)
6816 if (ConditionalAccess) {
6817 Error_NullShortCircuitInsideExpressionTree (ec);
6821 if (IsSingleDimensionalArrayLength ()) {
6822 args = new Arguments (1);
6823 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6824 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6827 args = new Arguments (2);
6828 if (InstanceExpression == null)
6829 args.Add (new Argument (new NullLiteral (loc)));
6831 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6832 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6833 return CreateExpressionFactoryCall (ec, "Property", args);
6836 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6838 DoResolveLValue (rc, null);
6839 return new TypeOfMethod (Setter, loc);
6842 public override string GetSignatureForError ()
6844 return best_candidate.GetSignatureForError ();
6847 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6850 return base.MakeExpression (ctx);
6852 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6856 public override SLE.Expression MakeExpression (BuilderContext ctx)
6859 return base.MakeExpression (ctx);
6861 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6865 void Error_PropertyNotValid (ResolveContext ec)
6867 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6868 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6869 GetSignatureForError ());
6872 bool IsSingleDimensionalArrayLength ()
6874 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6877 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6878 return ac != null && ac.Rank == 1;
6881 public override void Emit (EmitContext ec, bool leave_copy)
6884 // Special case: length of single dimension array property is turned into ldlen
6886 if (IsSingleDimensionalArrayLength ()) {
6887 if (conditional_access_receiver) {
6888 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6891 EmitInstance (ec, false);
6893 ec.Emit (OpCodes.Ldlen);
6894 ec.Emit (OpCodes.Conv_I4);
6896 if (conditional_access_receiver) {
6897 ec.CloseConditionalAccess (type);
6903 base.Emit (ec, leave_copy);
6906 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6908 if (backing_field != null) {
6909 backing_field.EmitAssign (ec, source, false, false);
6914 LocalTemporary await_source_arg = null;
6916 if (isCompound && !(source is DynamicExpressionStatement)) {
6917 emitting_compound_assignment = true;
6920 if (has_await_arguments) {
6921 await_source_arg = new LocalTemporary (Type);
6922 await_source_arg.Store (ec);
6924 args = new Arguments (1);
6925 args.Add (new Argument (await_source_arg));
6928 temp = await_source_arg;
6931 has_await_arguments = false;
6936 ec.Emit (OpCodes.Dup);
6937 temp = new LocalTemporary (this.Type);
6942 args = arguments ?? new Arguments (1);
6946 temp = new LocalTemporary (this.Type);
6948 args.Add (new Argument (temp));
6950 args.Add (new Argument (source));
6954 emitting_compound_assignment = false;
6956 var call = new CallEmitter ();
6957 call.InstanceExpression = InstanceExpression;
6959 call.InstanceExpressionOnStack = true;
6961 if (ConditionalAccess) {
6962 call.ConditionalAccess = true;
6966 call.Emit (ec, Setter, args, loc);
6968 call.EmitStatement (ec, Setter, args, loc);
6975 if (await_source_arg != null) {
6976 await_source_arg.Release (ec);
6980 public override void FlowAnalysis (FlowAnalysisContext fc)
6982 var prop = best_candidate.MemberDefinition as Property;
6983 if (prop != null && prop.BackingField != null) {
6984 var var = InstanceExpression as IVariableReference;
6986 var vi = var.VariableInfo;
6987 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6988 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6992 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6997 base.FlowAnalysis (fc);
6999 if (conditional_access_receiver)
7000 fc.ConditionalAccessEnd ();
7003 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7005 eclass = ExprClass.PropertyAccess;
7007 if (best_candidate.IsNotCSharpCompatible) {
7008 Error_PropertyNotValid (rc);
7011 ResolveInstanceExpression (rc, right_side);
7013 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7014 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7015 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7017 type = p.MemberType;
7021 DoBestMemberChecks (rc, best_candidate);
7023 // Handling of com-imported properties with any number of default property parameters
7024 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7025 var p = best_candidate.Get.Parameters;
7026 arguments = new Arguments (p.Count);
7027 for (int i = 0; i < p.Count; ++i) {
7028 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7030 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7031 var p = best_candidate.Set.Parameters;
7032 arguments = new Arguments (p.Count - 1);
7033 for (int i = 0; i < p.Count - 1; ++i) {
7034 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7041 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7043 var prop = best_candidate.MemberDefinition as Property;
7047 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7050 if (prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7051 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (prop.ShortName, prop.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7055 prop = (Property) ps.MemberDefinition;
7058 var spec = prop.BackingField;
7062 if (rc.IsStatic != spec.IsStatic)
7065 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7068 backing_field = new FieldExpr (prop.BackingField, loc);
7069 backing_field.ResolveLValue (rc, rhs);
7073 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7075 if (backing_field != null) {
7076 backing_field.SetFieldAssigned (fc);
7080 if (!IsAutoPropertyAccess)
7083 var prop = best_candidate.MemberDefinition as Property;
7084 if (prop != null && prop.BackingField != null) {
7085 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7086 if (lvalue_instance) {
7087 var var = InstanceExpression as IVariableReference;
7088 if (var != null && var.VariableInfo != null) {
7089 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7095 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7097 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7101 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7103 // getter and setter can be different for base calls
7104 MethodSpec getter, setter;
7105 protected T best_candidate;
7107 protected LocalTemporary temp;
7108 protected bool emitting_compound_assignment;
7109 protected bool has_await_arguments;
7111 protected PropertyOrIndexerExpr (Location l)
7118 protected abstract Arguments Arguments { get; set; }
7120 public MethodSpec Getter {
7129 public MethodSpec Setter {
7140 protected override Expression DoResolve (ResolveContext ec)
7142 if (eclass == ExprClass.Unresolved) {
7143 ResolveConditionalAccessReceiver (ec);
7145 var expr = OverloadResolve (ec, null);
7150 return expr.Resolve (ec);
7152 if (conditional_access_receiver) {
7153 type = LiftMemberType (ec, type);
7154 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7158 if (!ResolveGetter (ec))
7164 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7166 if (HasConditionalAccess ())
7167 Error_NullPropagatingLValue (rc);
7169 if (right_side == EmptyExpression.OutAccess) {
7170 // TODO: best_candidate can be null at this point
7171 INamedBlockVariable variable = null;
7172 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7173 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7174 best_candidate.Name);
7176 right_side.DoResolveLValue (rc, this);
7181 if (eclass == ExprClass.Unresolved) {
7182 var expr = OverloadResolve (rc, right_side);
7187 return expr.ResolveLValue (rc, right_side);
7189 ResolveInstanceExpression (rc, right_side);
7192 if (!best_candidate.HasSet) {
7193 if (ResolveAutopropertyAssignment (rc, right_side))
7196 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7197 GetSignatureForError ());
7201 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7202 if (best_candidate.HasDifferentAccessibility) {
7203 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7204 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7205 GetSignatureForError ());
7207 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7208 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7212 if (best_candidate.HasDifferentAccessibility)
7213 CheckProtectedMemberAccess (rc, best_candidate.Set);
7215 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7219 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7221 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7223 call.Emit (ec, method, arguments, loc);
7225 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7229 // Implements the IAssignMethod interface for assignments
7231 public virtual void Emit (EmitContext ec, bool leave_copy)
7233 var call = new CallEmitter ();
7234 call.ConditionalAccess = ConditionalAccess;
7235 call.InstanceExpression = InstanceExpression;
7236 if (has_await_arguments)
7237 call.HasAwaitArguments = true;
7239 call.DuplicateArguments = emitting_compound_assignment;
7241 if (conditional_access_receiver)
7242 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7244 call.Emit (ec, Getter, Arguments, loc);
7246 if (call.HasAwaitArguments) {
7247 InstanceExpression = call.InstanceExpression;
7248 Arguments = call.EmittedArguments;
7249 has_await_arguments = true;
7253 ec.Emit (OpCodes.Dup);
7254 temp = new LocalTemporary (Type);
7259 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7261 public override void Emit (EmitContext ec)
7266 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7268 has_await_arguments = true;
7273 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7275 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7277 bool ResolveGetter (ResolveContext rc)
7279 if (!best_candidate.HasGet) {
7280 if (InstanceExpression != EmptyExpression.Null) {
7281 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7282 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7283 best_candidate.GetSignatureForError ());
7286 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7287 if (best_candidate.HasDifferentAccessibility) {
7288 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7289 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7290 TypeManager.CSharpSignature (best_candidate));
7292 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7293 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7297 if (best_candidate.HasDifferentAccessibility) {
7298 CheckProtectedMemberAccess (rc, best_candidate.Get);
7301 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7305 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7312 /// Fully resolved expression that evaluates to an Event
7314 public class EventExpr : MemberExpr, IAssignMethod
7316 readonly EventSpec spec;
7319 public EventExpr (EventSpec spec, Location loc)
7327 protected override TypeSpec DeclaringType {
7329 return spec.DeclaringType;
7333 public override string Name {
7339 public override bool IsInstance {
7341 return !spec.IsStatic;
7345 public override bool IsStatic {
7347 return spec.IsStatic;
7351 public override string KindName {
7352 get { return "event"; }
7355 public MethodSpec Operator {
7363 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7366 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7368 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7369 if (spec.BackingField != null &&
7370 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7372 spec.MemberDefinition.SetIsUsed ();
7374 spec.CheckObsoleteness (ec, loc);
7376 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7377 Error_AssignmentEventOnly (ec);
7379 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7381 InstanceExpression = null;
7383 return ml.ResolveMemberAccess (ec, left, original);
7387 return base.ResolveMemberAccess (ec, left, original);
7390 public override Expression CreateExpressionTree (ResolveContext ec)
7392 throw new NotSupportedException ("ET");
7395 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7397 if (right_side == EmptyExpression.EventAddition) {
7398 op = spec.AccessorAdd;
7399 } else if (right_side == EmptyExpression.EventSubtraction) {
7400 op = spec.AccessorRemove;
7404 Error_AssignmentEventOnly (ec);
7408 if (HasConditionalAccess ())
7409 Error_NullPropagatingLValue (ec);
7411 op = CandidateToBaseOverride (ec, op);
7415 protected override Expression DoResolve (ResolveContext ec)
7417 eclass = ExprClass.EventAccess;
7418 type = spec.MemberType;
7420 ResolveInstanceExpression (ec, null);
7422 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7423 Error_AssignmentEventOnly (ec);
7426 DoBestMemberChecks (ec, spec);
7430 public override void Emit (EmitContext ec)
7432 throw new NotSupportedException ();
7433 //Error_CannotAssign ();
7436 #region IAssignMethod Members
7438 public void Emit (EmitContext ec, bool leave_copy)
7440 throw new NotImplementedException ();
7443 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7445 if (leave_copy || !isCompound)
7446 throw new NotImplementedException ("EventExpr::EmitAssign");
7448 Arguments args = new Arguments (1);
7449 args.Add (new Argument (source));
7451 // TODO: Wrong, needs receiver
7452 // if (NullShortCircuit) {
7453 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7456 var call = new CallEmitter ();
7457 call.InstanceExpression = InstanceExpression;
7458 call.ConditionalAccess = ConditionalAccess;
7459 call.EmitStatement (ec, op, args, loc);
7461 // if (NullShortCircuit)
7462 // ec.CloseConditionalAccess (null);
7467 void Error_AssignmentEventOnly (ResolveContext ec)
7469 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7470 ec.Report.Error (79, loc,
7471 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7472 GetSignatureForError ());
7474 ec.Report.Error (70, loc,
7475 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7476 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7480 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7482 name = name.Substring (0, name.LastIndexOf ('.'));
7483 base.Error_CannotCallAbstractBase (rc, name);
7486 public override string GetSignatureForError ()
7488 return TypeManager.CSharpSignature (spec);
7491 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7493 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7497 public class TemporaryVariableReference : VariableReference
7499 public class Declarator : Statement
7501 TemporaryVariableReference variable;
7503 public Declarator (TemporaryVariableReference variable)
7505 this.variable = variable;
7509 protected override void DoEmit (EmitContext ec)
7511 variable.li.CreateBuilder (ec);
7514 public override void Emit (EmitContext ec)
7516 // Don't create sequence point
7520 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7525 protected override void CloneTo (CloneContext clonectx, Statement target)
7533 public TemporaryVariableReference (LocalVariable li, Location loc)
7536 this.type = li.Type;
7540 public override bool IsLockedByStatement {
7548 public LocalVariable LocalInfo {
7554 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7556 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7557 return new TemporaryVariableReference (li, loc);
7560 protected override Expression DoResolve (ResolveContext ec)
7562 eclass = ExprClass.Variable;
7565 // Don't capture temporary variables except when using
7566 // state machine redirection and block yields
7568 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7569 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7570 ec.IsVariableCapturingRequired) {
7571 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7572 storey.CaptureLocalVariable (ec, li);
7578 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7580 return Resolve (ec);
7583 public override void Emit (EmitContext ec)
7585 li.CreateBuilder (ec);
7590 public void EmitAssign (EmitContext ec, Expression source)
7592 li.CreateBuilder (ec);
7594 EmitAssign (ec, source, false, false);
7597 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7599 return li.HoistedVariant;
7602 public override bool IsFixed {
7603 get { return true; }
7606 public override bool IsRef {
7607 get { return false; }
7610 public override string Name {
7611 get { throw new NotImplementedException (); }
7614 public override void SetHasAddressTaken ()
7616 throw new NotImplementedException ();
7619 protected override ILocalVariable Variable {
7623 public override VariableInfo VariableInfo {
7624 get { return null; }
7629 /// Handles `var' contextual keyword; var becomes a keyword only
7630 /// if no type called var exists in a variable scope
7632 class VarExpr : SimpleName
7634 public VarExpr (Location loc)
7639 public bool InferType (ResolveContext ec, Expression right_side)
7642 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7644 type = right_side.Type;
7645 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7646 ec.Report.Error (815, loc,
7647 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7648 type.GetSignatureForError ());
7649 type = InternalType.ErrorType;
7653 eclass = ExprClass.Variable;
7657 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7659 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7660 base.Error_TypeOrNamespaceNotFound (ec);
7662 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");