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,
824 DontSetConditionalAccess = 1 << 8
828 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
829 // `qualifier_type' or null to lookup members in the current class.
831 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
833 var members = MemberCache.FindMembers (queried_type, name, false);
839 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
843 if (members [0].DeclaringType.BaseType == null)
846 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
847 } while (members != null);
852 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
854 MemberSpec non_method = null;
855 MemberSpec ambig_non_method = null;
857 for (int i = 0; i < members.Count; ++i) {
858 var member = members [i];
860 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
861 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
864 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
867 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
871 if (!member.IsAccessible (rc))
875 // With runtime binder we can have a situation where queried type is inaccessible
876 // because it came via dynamic object, the check about inconsisted accessibility
877 // had no effect as the type was unknown during compilation
880 // private class N { }
882 // public dynamic Foo ()
888 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
892 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
893 if (member is MethodSpec) {
895 // Interface members that are hidden by class members are removed from the set. This
896 // step only has an effect if T is a type parameter and T has both an effective base
897 // class other than object and a non-empty effective interface set
899 var tps = queried_type as TypeParameterSpec;
900 if (tps != null && tps.HasTypeConstraint)
901 members = RemoveHiddenTypeParameterMethods (members);
903 return new MethodGroupExpr (members, queried_type, loc);
906 if (!Invocation.IsMemberInvocable (member))
910 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
912 } else if (!errorMode && !member.IsNotCSharpCompatible) {
914 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
915 // T has both an effective base class other than object and a non-empty effective interface set.
917 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
919 var tps = queried_type as TypeParameterSpec;
920 if (tps != null && tps.HasTypeConstraint) {
921 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
924 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
930 ambig_non_method = member;
934 if (non_method != null) {
935 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
936 var report = rc.Module.Compiler.Report;
937 report.SymbolRelatedToPreviousError (non_method);
938 report.SymbolRelatedToPreviousError (ambig_non_method);
939 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
940 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
943 if (non_method is MethodSpec)
944 return new MethodGroupExpr (members, queried_type, loc);
946 return ExprClassFromMemberInfo (non_method, loc);
952 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
954 if (members.Count < 2)
958 // If M is a method, then all non-method members declared in an interface declaration
959 // are removed from the set, and all methods with the same signature as M declared in
960 // an interface declaration are removed from the set
964 for (int i = 0; i < members.Count; ++i) {
965 var method = members[i] as MethodSpec;
966 if (method == null) {
969 members = new List<MemberSpec> (members);
972 members.RemoveAt (i--);
976 if (!method.DeclaringType.IsInterface)
979 for (int ii = 0; ii < members.Count; ++ii) {
980 var candidate = members[ii] as MethodSpec;
981 if (candidate == null || !candidate.DeclaringType.IsClass)
984 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
987 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
992 members = new List<MemberSpec> (members);
995 members.RemoveAt (i--);
1003 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1005 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1008 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1010 throw new NotImplementedException ();
1013 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1015 if (t == InternalType.ErrorType)
1018 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1019 oper, t.GetSignatureForError ());
1022 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1024 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1027 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1029 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1032 protected void Error_NullPropagatingLValue (ResolveContext rc)
1034 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1037 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1042 // Special version of flow analysis for expressions which can return different
1043 // on-true and on-false result. Used by &&, ||, ?: expressions
1045 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1048 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1052 /// Returns an expression that can be used to invoke operator true
1053 /// on the expression if it exists.
1055 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1057 return GetOperatorTrueOrFalse (ec, e, true, loc);
1061 /// Returns an expression that can be used to invoke operator false
1062 /// on the expression if it exists.
1064 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1066 return GetOperatorTrueOrFalse (ec, e, false, loc);
1069 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1071 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1073 if (type.IsNullableType)
1074 type = Nullable.NullableInfo.GetUnderlyingType (type);
1076 var methods = MemberCache.GetUserOperator (type, op, false);
1077 if (methods == null)
1080 Arguments arguments = new Arguments (1);
1081 arguments.Add (new Argument (e));
1083 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1084 var oper = res.ResolveOperator (ec, ref arguments);
1089 return new UserOperatorCall (oper, arguments, null, loc);
1092 public virtual string ExprClassName
1096 case ExprClass.Unresolved:
1097 return "Unresolved";
1098 case ExprClass.Value:
1100 case ExprClass.Variable:
1102 case ExprClass.Namespace:
1104 case ExprClass.Type:
1106 case ExprClass.MethodGroup:
1107 return "method group";
1108 case ExprClass.PropertyAccess:
1109 return "property access";
1110 case ExprClass.EventAccess:
1111 return "event access";
1112 case ExprClass.IndexerAccess:
1113 return "indexer access";
1114 case ExprClass.Nothing:
1116 case ExprClass.TypeParameter:
1117 return "type parameter";
1119 throw new Exception ("Should not happen");
1124 /// Reports that we were expecting `expr' to be of class `expected'
1126 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1128 var name = memberExpr.GetSignatureForError ();
1130 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1133 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1135 string [] valid = new string [4];
1138 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1139 valid [count++] = "variable";
1140 valid [count++] = "value";
1143 if ((flags & ResolveFlags.Type) != 0)
1144 valid [count++] = "type";
1146 if ((flags & ResolveFlags.MethodGroup) != 0)
1147 valid [count++] = "method group";
1150 valid [count++] = "unknown";
1152 StringBuilder sb = new StringBuilder (valid [0]);
1153 for (int i = 1; i < count - 1; i++) {
1155 sb.Append (valid [i]);
1158 sb.Append ("' or `");
1159 sb.Append (valid [count - 1]);
1162 ec.Report.Error (119, loc,
1163 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1166 public static void UnsafeError (ResolveContext ec, Location loc)
1168 UnsafeError (ec.Report, loc);
1171 public static void UnsafeError (Report Report, Location loc)
1173 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1177 // Converts `source' to an int, uint, long or ulong.
1179 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1181 var btypes = ec.BuiltinTypes;
1183 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 Arguments args = new Arguments (1);
1185 args.Add (new Argument (source));
1186 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1189 Expression converted;
1191 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1192 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1193 if (converted == null)
1194 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1195 if (converted == null)
1196 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1197 if (converted == null)
1198 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1200 if (converted == null) {
1201 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1210 // Only positive constants are allowed at compile time
1212 Constant c = converted as Constant;
1213 if (c != null && c.IsNegative)
1214 Error_NegativeArrayIndex (ec, source.loc);
1216 // No conversion needed to array index
1217 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1220 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1223 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1225 if (args.Count != 1){
1226 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1231 if (arg is NamedArgument)
1232 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1234 var index = arg.Expr.Resolve (rc);
1238 index = ConvertExpressionToArrayIndex (rc, index, true);
1240 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1241 return new Indirection (p, loc);
1245 // Derived classes implement this method by cloning the fields that
1246 // could become altered during the Resolve stage
1248 // Only expressions that are created for the parser need to implement
1251 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1253 throw new NotImplementedException (
1255 "CloneTo not implemented for expression {0}", this.GetType ()));
1259 // Clones an expression created by the parser.
1261 // We only support expressions created by the parser so far, not
1262 // expressions that have been resolved (many more classes would need
1263 // to implement CloneTo).
1265 // This infrastructure is here merely for Lambda expressions which
1266 // compile the same code using different type values for the same
1267 // arguments to find the correct overload
1269 public virtual Expression Clone (CloneContext clonectx)
1271 Expression cloned = (Expression) MemberwiseClone ();
1272 CloneTo (clonectx, cloned);
1278 // Implementation of expression to expression tree conversion
1280 public abstract Expression CreateExpressionTree (ResolveContext ec);
1282 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1284 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1287 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1289 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1292 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1294 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1297 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1299 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1303 return new TypeExpression (t, loc);
1307 // Implemented by all expressions which support conversion from
1308 // compiler expression to invokable runtime expression. Used by
1309 // dynamic C# binder.
1311 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1313 throw new NotImplementedException ("MakeExpression for " + GetType ());
1316 public virtual object Accept (StructuralVisitor visitor)
1318 return visitor.Visit (this);
1323 /// This is just a base class for expressions that can
1324 /// appear on statements (invocations, object creation,
1325 /// assignments, post/pre increment and decrement). The idea
1326 /// being that they would support an extra Emition interface that
1327 /// does not leave a result on the stack.
1329 public abstract class ExpressionStatement : Expression
1331 public virtual void MarkReachable (Reachability rc)
1335 public ExpressionStatement ResolveStatement (BlockContext ec)
1337 Expression e = Resolve (ec);
1341 ExpressionStatement es = e as ExpressionStatement;
1342 if (es == null || e is AnonymousMethodBody) {
1343 var reduced = e as IReducedExpressionStatement;
1344 if (reduced != null) {
1345 return EmptyExpressionStatement.Instance;
1348 Error_InvalidExpressionStatement (ec);
1352 // This is quite expensive warning, try to limit the damage
1354 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1355 WarningAsyncWithoutWait (ec, e);
1361 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1363 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1364 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1369 // Need to do full resolve because GetAwaiter can be extension method
1370 // available only in this context
1372 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1376 var arguments = new Arguments (0);
1377 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1382 // Use same check rules as for real await
1384 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1385 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1388 bc.Report.Warning (4014, 1, e.Location,
1389 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1393 var inv = e as Invocation;
1394 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1395 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1396 bc.Report.Warning (4014, 1, e.Location,
1397 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1403 /// Requests the expression to be emitted in a `statement'
1404 /// context. This means that no new value is left on the
1405 /// stack after invoking this method (constrasted with
1406 /// Emit that will always leave a value on the stack).
1408 public abstract void EmitStatement (EmitContext ec);
1410 public override void EmitSideEffect (EmitContext ec)
1416 interface IReducedExpressionStatement
1421 /// This kind of cast is used to encapsulate the child
1422 /// whose type is child.Type into an expression that is
1423 /// reported to return "return_type". This is used to encapsulate
1424 /// expressions which have compatible types, but need to be dealt
1425 /// at higher levels with.
1427 /// For example, a "byte" expression could be encapsulated in one
1428 /// of these as an "unsigned int". The type for the expression
1429 /// would be "unsigned int".
1432 public abstract class TypeCast : Expression
1434 protected readonly Expression child;
1436 protected TypeCast (Expression child, TypeSpec return_type)
1438 eclass = child.eclass;
1439 loc = child.Location;
1444 public Expression Child {
1450 public override bool ContainsEmitWithAwait ()
1452 return child.ContainsEmitWithAwait ();
1455 public override Expression CreateExpressionTree (ResolveContext ec)
1457 Arguments args = new Arguments (2);
1458 args.Add (new Argument (child.CreateExpressionTree (ec)));
1459 args.Add (new Argument (new TypeOf (type, loc)));
1461 if (type.IsPointer || child.Type.IsPointer)
1462 Error_PointerInsideExpressionTree (ec);
1464 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1467 protected override Expression DoResolve (ResolveContext ec)
1469 // This should never be invoked, we are born in fully
1470 // initialized state.
1475 public override void Emit (EmitContext ec)
1480 public override void FlowAnalysis (FlowAnalysisContext fc)
1482 child.FlowAnalysis (fc);
1485 public override SLE.Expression MakeExpression (BuilderContext ctx)
1488 return base.MakeExpression (ctx);
1490 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1491 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1492 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1496 protected override void CloneTo (CloneContext clonectx, Expression t)
1501 public override bool IsNull {
1502 get { return child.IsNull; }
1506 public class EmptyCast : TypeCast {
1507 EmptyCast (Expression child, TypeSpec target_type)
1508 : base (child, target_type)
1512 public static Expression Create (Expression child, TypeSpec type)
1514 Constant c = child as Constant;
1516 var enum_constant = c as EnumConstant;
1517 if (enum_constant != null)
1518 c = enum_constant.Child;
1520 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1524 var res = c.ConvertImplicitly (type);
1530 EmptyCast e = child as EmptyCast;
1532 return new EmptyCast (e.child, type);
1534 return new EmptyCast (child, type);
1537 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1539 child.EmitBranchable (ec, label, on_true);
1542 public override void EmitSideEffect (EmitContext ec)
1544 child.EmitSideEffect (ec);
1549 // Used for predefined type user operator (no obsolete check, etc.)
1551 public class OperatorCast : TypeCast
1553 readonly MethodSpec conversion_operator;
1555 public OperatorCast (Expression expr, TypeSpec target_type)
1556 : this (expr, target_type, target_type, false)
1560 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1561 : this (expr, target_type, target_type, find_explicit)
1565 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1566 : base (expr, returnType)
1568 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1569 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1572 foreach (MethodSpec oper in mi) {
1573 if (oper.ReturnType != returnType)
1576 if (oper.Parameters.Types[0] == expr.Type) {
1577 conversion_operator = oper;
1583 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1584 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1587 public override void Emit (EmitContext ec)
1590 ec.Emit (OpCodes.Call, conversion_operator);
1595 // Constant specialization of EmptyCast.
1596 // We need to special case this since an empty cast of
1597 // a constant is still a constant.
1599 public class EmptyConstantCast : Constant
1601 public readonly Constant child;
1603 public EmptyConstantCast (Constant child, TypeSpec type)
1604 : base (child.Location)
1607 throw new ArgumentNullException ("child");
1610 this.eclass = child.eclass;
1614 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1616 if (child.Type == target_type)
1619 // FIXME: check that 'type' can be converted to 'target_type' first
1620 return child.ConvertExplicitly (in_checked_context, target_type);
1623 public override Expression CreateExpressionTree (ResolveContext ec)
1625 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1626 child.CreateExpressionTree (ec),
1627 new TypeOf (type, loc));
1630 Error_PointerInsideExpressionTree (ec);
1632 return CreateExpressionFactoryCall (ec, "Convert", args);
1635 public override bool IsDefaultValue {
1636 get { return child.IsDefaultValue; }
1639 public override bool IsNegative {
1640 get { return child.IsNegative; }
1643 public override bool IsNull {
1644 get { return child.IsNull; }
1647 public override bool IsOneInteger {
1648 get { return child.IsOneInteger; }
1651 public override bool IsSideEffectFree {
1653 return child.IsSideEffectFree;
1657 public override bool IsZeroInteger {
1658 get { return child.IsZeroInteger; }
1661 public override void Emit (EmitContext ec)
1666 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1668 child.EmitBranchable (ec, label, on_true);
1670 // Only to make verifier happy
1671 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1672 ec.Emit (OpCodes.Unbox_Any, type);
1675 public override void EmitSideEffect (EmitContext ec)
1677 child.EmitSideEffect (ec);
1680 public override object GetValue ()
1682 return child.GetValue ();
1685 public override string GetValueAsLiteral ()
1687 return child.GetValueAsLiteral ();
1690 public override long GetValueAsLong ()
1692 return child.GetValueAsLong ();
1695 public override Constant ConvertImplicitly (TypeSpec target_type)
1697 if (type == target_type)
1700 // FIXME: Do we need to check user conversions?
1701 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1704 return child.ConvertImplicitly (target_type);
1709 /// This class is used to wrap literals which belong inside Enums
1711 public class EnumConstant : Constant
1713 public Constant Child;
1715 public EnumConstant (Constant child, TypeSpec enum_type)
1716 : base (child.Location)
1720 this.eclass = ExprClass.Value;
1721 this.type = enum_type;
1724 protected EnumConstant (Location loc)
1729 public override void Emit (EmitContext ec)
1734 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1736 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1739 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1741 Child.EmitBranchable (ec, label, on_true);
1744 public override void EmitSideEffect (EmitContext ec)
1746 Child.EmitSideEffect (ec);
1749 public override string GetSignatureForError()
1751 return Type.GetSignatureForError ();
1754 public override object GetValue ()
1756 return Child.GetValue ();
1760 public override object GetTypedValue ()
1763 // The method can be used in dynamic context only (on closed types)
1765 // System.Enum.ToObject cannot be called on dynamic types
1766 // EnumBuilder has to be used, but we cannot use EnumBuilder
1767 // because it does not properly support generics
1769 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1773 public override string GetValueAsLiteral ()
1775 return Child.GetValueAsLiteral ();
1778 public override long GetValueAsLong ()
1780 return Child.GetValueAsLong ();
1783 public EnumConstant Increment()
1785 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1788 public override bool IsDefaultValue {
1790 return Child.IsDefaultValue;
1794 public override bool IsSideEffectFree {
1796 return Child.IsSideEffectFree;
1800 public override bool IsZeroInteger {
1801 get { return Child.IsZeroInteger; }
1804 public override bool IsNegative {
1806 return Child.IsNegative;
1810 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1812 if (Child.Type == target_type)
1815 return Child.ConvertExplicitly (in_checked_context, target_type);
1818 public override Constant ConvertImplicitly (TypeSpec type)
1820 if (this.type == type) {
1824 if (!Convert.ImplicitStandardConversionExists (this, type)){
1828 return Child.ConvertImplicitly (type);
1833 /// This kind of cast is used to encapsulate Value Types in objects.
1835 /// The effect of it is to box the value type emitted by the previous
1838 public class BoxedCast : TypeCast {
1840 public BoxedCast (Expression expr, TypeSpec target_type)
1841 : base (expr, target_type)
1843 eclass = ExprClass.Value;
1846 protected override Expression DoResolve (ResolveContext ec)
1848 // This should never be invoked, we are born in fully
1849 // initialized state.
1854 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1856 // Only boxing to object type is supported
1857 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1858 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1862 enc.Encode (child.Type);
1863 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1866 public override void Emit (EmitContext ec)
1870 ec.Emit (OpCodes.Box, child.Type);
1873 public override void EmitSideEffect (EmitContext ec)
1875 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1876 // so, we need to emit the box+pop instructions in most cases
1877 if (child.Type.IsStruct &&
1878 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1879 child.EmitSideEffect (ec);
1881 base.EmitSideEffect (ec);
1885 public class UnboxCast : TypeCast {
1886 public UnboxCast (Expression expr, TypeSpec return_type)
1887 : base (expr, return_type)
1891 protected override Expression DoResolve (ResolveContext ec)
1893 // This should never be invoked, we are born in fully
1894 // initialized state.
1899 public override void Emit (EmitContext ec)
1903 ec.Emit (OpCodes.Unbox_Any, type);
1908 /// This is used to perform explicit numeric conversions.
1910 /// Explicit numeric conversions might trigger exceptions in a checked
1911 /// context, so they should generate the conv.ovf opcodes instead of
1914 public class ConvCast : TypeCast {
1915 public enum Mode : byte {
1916 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1918 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1919 U2_I1, U2_U1, U2_I2, U2_CH,
1920 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1921 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1922 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1923 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1924 CH_I1, CH_U1, CH_I2,
1925 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1926 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1932 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1933 : base (child, return_type)
1938 protected override Expression DoResolve (ResolveContext ec)
1940 // This should never be invoked, we are born in fully
1941 // initialized state.
1946 public override string ToString ()
1948 return String.Format ("ConvCast ({0}, {1})", mode, child);
1951 public override void Emit (EmitContext ec)
1957 public static void Emit (EmitContext ec, Mode mode)
1959 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1961 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1962 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U1_CH: /* nothing */ break;
1970 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1971 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1972 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1974 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1975 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1977 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1979 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.U2_CH: /* nothing */ break;
1982 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1983 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1984 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1985 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1991 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1992 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1993 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1994 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1995 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1997 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1998 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1999 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2000 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2001 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2002 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2003 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2004 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2007 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2008 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2009 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2010 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2011 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2012 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2013 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2014 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2015 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2017 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2018 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2019 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2021 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2022 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2023 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2024 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2025 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2026 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2027 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2028 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2029 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2031 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2032 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2033 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2034 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2035 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2036 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2037 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2038 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2039 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2040 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2042 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2046 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2047 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2049 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2050 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2053 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2055 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2056 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2057 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2059 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2060 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2062 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2063 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2064 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2065 case Mode.U2_CH: /* nothing */ break;
2067 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2068 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2069 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2070 case Mode.I4_U4: /* nothing */ break;
2071 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2073 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2076 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2077 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2078 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2079 case Mode.U4_I4: /* nothing */ break;
2080 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2083 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2084 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2085 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2086 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2087 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2088 case Mode.I8_U8: /* nothing */ break;
2089 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2090 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2092 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.U8_I8: /* nothing */ break;
2099 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2100 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2102 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2106 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2107 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2108 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2109 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2110 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2111 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2112 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2113 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2114 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2116 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2117 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2118 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2119 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2120 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2121 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2122 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2123 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2124 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2125 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2127 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2133 class OpcodeCast : TypeCast
2137 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2138 : base (child, return_type)
2143 protected override Expression DoResolve (ResolveContext ec)
2145 // This should never be invoked, we are born in fully
2146 // initialized state.
2151 public override void Emit (EmitContext ec)
2157 public TypeSpec UnderlyingType {
2158 get { return child.Type; }
2163 // Opcode casts expression with 2 opcodes but only
2164 // single expression tree node
2166 class OpcodeCastDuplex : OpcodeCast
2168 readonly OpCode second;
2170 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2171 : base (child, returnType, first)
2173 this.second = second;
2176 public override void Emit (EmitContext ec)
2184 /// This kind of cast is used to encapsulate a child and cast it
2185 /// to the class requested
2187 public sealed class ClassCast : TypeCast {
2188 readonly bool forced;
2190 public ClassCast (Expression child, TypeSpec return_type)
2191 : base (child, return_type)
2195 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2196 : base (child, return_type)
2198 this.forced = forced;
2201 public override void Emit (EmitContext ec)
2205 bool gen = TypeManager.IsGenericParameter (child.Type);
2207 ec.Emit (OpCodes.Box, child.Type);
2209 if (type.IsGenericParameter) {
2210 ec.Emit (OpCodes.Unbox_Any, type);
2217 ec.Emit (OpCodes.Castclass, type);
2222 // Created during resolving pahse when an expression is wrapped or constantified
2223 // and original expression can be used later (e.g. for expression trees)
2225 public class ReducedExpression : Expression
2227 public class ReducedConstantExpression : EmptyConstantCast
2229 readonly Expression orig_expr;
2231 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2232 : base (expr, expr.Type)
2234 this.orig_expr = orig_expr;
2237 public Expression OriginalExpression {
2243 public override Constant ConvertImplicitly (TypeSpec target_type)
2245 Constant c = base.ConvertImplicitly (target_type);
2247 c = new ReducedConstantExpression (c, orig_expr);
2252 public override Expression CreateExpressionTree (ResolveContext ec)
2254 return orig_expr.CreateExpressionTree (ec);
2257 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2259 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2261 c = new ReducedConstantExpression (c, orig_expr);
2265 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2268 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2270 if (orig_expr is Conditional)
2271 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2273 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2277 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2279 public ReducedConstantStatement (Constant expr, Expression origExpr)
2280 : base (expr, origExpr)
2285 sealed class ReducedExpressionStatement : ExpressionStatement
2287 readonly Expression orig_expr;
2288 readonly ExpressionStatement stm;
2290 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2292 this.orig_expr = orig;
2294 this.eclass = stm.eclass;
2295 this.type = stm.Type;
2297 this.loc = orig.Location;
2300 public override bool ContainsEmitWithAwait ()
2302 return stm.ContainsEmitWithAwait ();
2305 public override Expression CreateExpressionTree (ResolveContext ec)
2307 return orig_expr.CreateExpressionTree (ec);
2310 protected override Expression DoResolve (ResolveContext ec)
2315 public override void Emit (EmitContext ec)
2320 public override void EmitStatement (EmitContext ec)
2322 stm.EmitStatement (ec);
2325 public override void FlowAnalysis (FlowAnalysisContext fc)
2327 stm.FlowAnalysis (fc);
2331 readonly Expression expr, orig_expr;
2333 private ReducedExpression (Expression expr, Expression orig_expr)
2336 this.eclass = expr.eclass;
2337 this.type = expr.Type;
2338 this.orig_expr = orig_expr;
2339 this.loc = orig_expr.Location;
2344 public override bool IsSideEffectFree {
2346 return expr.IsSideEffectFree;
2350 public Expression OriginalExpression {
2358 public override bool ContainsEmitWithAwait ()
2360 return expr.ContainsEmitWithAwait ();
2364 // Creates fully resolved expression switcher
2366 public static Constant Create (Constant expr, Expression originalExpr)
2368 if (expr.eclass == ExprClass.Unresolved)
2369 throw new ArgumentException ("Unresolved expression");
2371 if (originalExpr is ExpressionStatement)
2372 return new ReducedConstantStatement (expr, originalExpr);
2374 return new ReducedConstantExpression (expr, originalExpr);
2377 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2379 return new ReducedExpressionStatement (s, orig);
2382 public static Expression Create (Expression expr, Expression original_expr)
2384 return Create (expr, original_expr, true);
2388 // Creates unresolved reduce expression. The original expression has to be
2389 // already resolved. Created expression is constant based based on `expr'
2390 // value unless canBeConstant is used
2392 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2394 if (canBeConstant) {
2395 Constant c = expr as Constant;
2397 return Create (c, original_expr);
2400 ExpressionStatement s = expr as ExpressionStatement;
2402 return Create (s, original_expr);
2404 if (expr.eclass == ExprClass.Unresolved)
2405 throw new ArgumentException ("Unresolved expression");
2407 return new ReducedExpression (expr, original_expr);
2410 public override Expression CreateExpressionTree (ResolveContext ec)
2412 return orig_expr.CreateExpressionTree (ec);
2415 protected override Expression DoResolve (ResolveContext ec)
2420 public override void Emit (EmitContext ec)
2425 public override Expression EmitToField (EmitContext ec)
2427 return expr.EmitToField(ec);
2430 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2432 expr.EmitBranchable (ec, target, on_true);
2435 public override void FlowAnalysis (FlowAnalysisContext fc)
2437 expr.FlowAnalysis (fc);
2440 public override SLE.Expression MakeExpression (BuilderContext ctx)
2442 return orig_expr.MakeExpression (ctx);
2447 // Standard composite pattern
2449 public abstract class CompositeExpression : Expression
2451 protected Expression expr;
2453 protected CompositeExpression (Expression expr)
2456 this.loc = expr.Location;
2459 public override bool ContainsEmitWithAwait ()
2461 return expr.ContainsEmitWithAwait ();
2464 public override Expression CreateExpressionTree (ResolveContext rc)
2466 return expr.CreateExpressionTree (rc);
2469 public Expression Child {
2470 get { return expr; }
2473 protected override Expression DoResolve (ResolveContext rc)
2475 expr = expr.Resolve (rc);
2480 eclass = expr.eclass;
2484 public override void Emit (EmitContext ec)
2489 public override bool IsNull {
2490 get { return expr.IsNull; }
2495 // Base of expressions used only to narrow resolve flow
2497 public abstract class ShimExpression : Expression
2499 protected Expression expr;
2501 protected ShimExpression (Expression expr)
2506 public Expression Expr {
2512 protected override void CloneTo (CloneContext clonectx, Expression t)
2517 ShimExpression target = (ShimExpression) t;
2518 target.expr = expr.Clone (clonectx);
2521 public override bool ContainsEmitWithAwait ()
2523 return expr.ContainsEmitWithAwait ();
2526 public override Expression CreateExpressionTree (ResolveContext ec)
2528 throw new NotSupportedException ("ET");
2531 public override void Emit (EmitContext ec)
2533 throw new InternalErrorException ("Missing Resolve call");
2537 public class UnreachableExpression : Expression
2539 public UnreachableExpression (Expression expr)
2541 this.loc = expr.Location;
2544 public override Expression CreateExpressionTree (ResolveContext ec)
2547 throw new NotImplementedException ();
2550 protected override Expression DoResolve (ResolveContext rc)
2552 throw new NotSupportedException ();
2555 public override void FlowAnalysis (FlowAnalysisContext fc)
2557 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2560 public override void Emit (EmitContext ec)
2564 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2570 // Unresolved type name expressions
2572 public abstract class ATypeNameExpression : FullNamedExpression
2575 protected TypeArguments targs;
2577 protected ATypeNameExpression (string name, Location l)
2583 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2590 protected ATypeNameExpression (string name, int arity, Location l)
2591 : this (name, new UnboundTypeArguments (arity, l), l)
2599 return targs == null ? 0 : targs.Count;
2603 public bool HasTypeArguments {
2605 return targs != null && !targs.IsEmpty;
2609 public string Name {
2618 public TypeArguments TypeArguments {
2626 public override bool Equals (object obj)
2628 ATypeNameExpression atne = obj as ATypeNameExpression;
2629 return atne != null && atne.Name == Name &&
2630 (targs == null || targs.Equals (atne.targs));
2633 public override int GetHashCode ()
2635 return Name.GetHashCode ();
2638 // TODO: Move it to MemberCore
2639 public static string GetMemberType (MemberCore mc)
2645 if (mc is FieldBase)
2647 if (mc is MethodCore)
2649 if (mc is EnumMember)
2657 public override string GetSignatureForError ()
2659 if (targs != null) {
2660 return Name + "<" + targs.GetSignatureForError () + ">";
2666 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2670 /// SimpleName expressions are formed of a single word and only happen at the beginning
2671 /// of a dotted-name.
2673 public class SimpleName : ATypeNameExpression
2675 public SimpleName (string name, Location l)
2680 public SimpleName (string name, TypeArguments args, Location l)
2681 : base (name, args, l)
2685 public SimpleName (string name, int arity, Location l)
2686 : base (name, arity, l)
2690 public SimpleName GetMethodGroup ()
2692 return new SimpleName (Name, targs, loc);
2695 protected override Expression DoResolve (ResolveContext rc)
2697 return SimpleNameResolve (rc, null);
2700 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2702 return SimpleNameResolve (ec, right_side);
2705 public void Error_NameDoesNotExist (ResolveContext rc)
2707 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2710 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2712 if (ctx.CurrentType != null) {
2713 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2714 if (member != null) {
2715 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2720 var report = ctx.Module.Compiler.Report;
2722 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2723 if (retval != null) {
2724 report.SymbolRelatedToPreviousError (retval.Type);
2725 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2729 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2730 if (retval != null) {
2731 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2735 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2736 if (ns_candidates != null) {
2737 if (ctx is UsingAliasNamespace.AliasContext) {
2738 report.Error (246, loc,
2739 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2740 ns_candidates[0], Name);
2742 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2743 report.Error (246, loc,
2744 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2748 report.Error (246, loc,
2749 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2754 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2756 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2759 if (fne.Type != null && Arity > 0) {
2760 if (HasTypeArguments) {
2761 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2762 if (ct.ResolveAsType (mc) == null)
2768 targs.Resolve (mc, allowUnboundTypeArguments);
2770 return new GenericOpenTypeExpr (fne.Type, loc);
2774 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2776 if (!(fne is NamespaceExpression))
2780 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2781 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2782 mc.Module.Compiler.Report.Error (1980, Location,
2783 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2784 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2787 fne = new DynamicTypeExpr (loc);
2788 fne.ResolveAsType (mc);
2794 Error_TypeOrNamespaceNotFound (mc);
2798 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2800 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2803 public bool IsPossibleType (IMemberContext mc)
2805 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2808 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2810 int lookup_arity = Arity;
2811 bool errorMode = false;
2813 Block current_block = rc.CurrentBlock;
2814 INamedBlockVariable variable = null;
2815 bool variable_found = false;
2819 // Stage 1: binding to local variables or parameters
2821 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2823 if (current_block != null && lookup_arity == 0) {
2824 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2825 if (!variable.IsDeclared) {
2826 // We found local name in accessible block but it's not
2827 // initialized yet, maybe the user wanted to bind to something else
2829 variable_found = true;
2831 e = variable.CreateReferenceExpression (rc, loc);
2834 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2843 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2845 TypeSpec member_type = rc.CurrentType;
2846 for (; member_type != null; member_type = member_type.DeclaringType) {
2847 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2851 var me = e as MemberExpr;
2853 // The name matches a type, defer to ResolveAsTypeStep
2861 if (variable != null) {
2862 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2863 rc.Report.Error (844, loc,
2864 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2865 Name, me.GetSignatureForError ());
2869 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2870 // Leave it to overload resolution to report correct error
2872 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2873 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2877 // MemberLookup does not check accessors availability, this is actually needed for properties only
2879 var pe = me as PropertyExpr;
2882 // Break as there is no other overload available anyway
2883 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2884 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2887 pe.Getter = pe.PropertyInfo.Get;
2889 if (!pe.PropertyInfo.HasSet) {
2890 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2891 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2892 var p = (Property) pe.PropertyInfo.MemberDefinition;
2893 return new FieldExpr (p.BackingField, loc);
2896 variable_found = true;
2900 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2901 variable_found = true;
2905 pe.Setter = pe.PropertyInfo.Set;
2910 // TODO: It's used by EventExpr -> FieldExpr transformation only
2911 // TODO: Should go to MemberAccess
2912 me = me.ResolveMemberAccess (rc, null, null);
2915 targs.Resolve (rc, false);
2916 me.SetTypeArguments (rc, targs);
2923 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2925 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2926 if (IsPossibleTypeOrNamespace (rc)) {
2927 return ResolveAsTypeOrNamespace (rc, false);
2931 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2934 targs.Resolve (rc, false);
2936 var me = expr as MemberExpr;
2938 me.SetTypeArguments (rc, targs);
2943 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2944 return new NameOf (this);
2947 if (variable_found) {
2948 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2951 var tparams = rc.CurrentTypeParameters;
2952 if (tparams != null) {
2953 if (tparams.Find (Name) != null) {
2954 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2959 var ct = rc.CurrentType;
2961 if (ct.MemberDefinition.TypeParametersCount > 0) {
2962 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2963 if (ctp.Name == Name) {
2964 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2970 ct = ct.DeclaringType;
2971 } while (ct != null);
2974 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2975 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2977 rc.Report.SymbolRelatedToPreviousError (e.Type);
2978 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2982 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2984 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2985 return ErrorExpression.Instance;
2989 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2991 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2992 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2996 if (e is TypeExpr) {
2997 // TypeExpression does not have correct location
2998 if (e is TypeExpression)
2999 e = new TypeExpression (e.Type, loc);
3005 Error_NameDoesNotExist (rc);
3008 return ErrorExpression.Instance;
3011 if (rc.Module.Evaluator != null) {
3012 var fi = rc.Module.Evaluator.LookupField (Name);
3014 return new FieldExpr (fi.Item1, loc);
3022 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3024 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3029 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3030 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3034 if (right_side != null) {
3035 e = e.ResolveLValue (ec, right_side);
3043 public override object Accept (StructuralVisitor visitor)
3045 return visitor.Visit (this);
3050 /// Represents a namespace or a type. The name of the class was inspired by
3051 /// section 10.8.1 (Fully Qualified Names).
3053 public abstract class FullNamedExpression : Expression
3055 protected override void CloneTo (CloneContext clonectx, Expression target)
3057 // Do nothing, most unresolved type expressions cannot be
3058 // resolved to different type
3061 public override bool ContainsEmitWithAwait ()
3066 public override Expression CreateExpressionTree (ResolveContext ec)
3068 throw new NotSupportedException ("ET");
3071 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3074 // This is used to resolve the expression as a type, a null
3075 // value will be returned if the expression is not a type
3078 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3080 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3085 TypeExpr te = fne as TypeExpr;
3087 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3095 var dep = type.GetMissingDependencies ();
3097 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3100 if (type.Kind == MemberKind.Void) {
3101 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3105 // Obsolete checks cannot be done when resolving base context as they
3106 // require type dependencies to be set but we are in process of resolving them
3108 if (mc is ResolveContext) {
3109 var oa = type.GetAttributeObsolete ();
3110 if (oa != null && !mc.IsObsolete)
3111 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3118 public override void Emit (EmitContext ec)
3120 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3121 GetSignatureForError ());
3126 /// Expression that evaluates to a type
3128 public abstract class TypeExpr : FullNamedExpression
3130 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3136 protected sealed override Expression DoResolve (ResolveContext ec)
3142 public override bool Equals (object obj)
3144 TypeExpr tobj = obj as TypeExpr;
3148 return Type == tobj.Type;
3151 public override int GetHashCode ()
3153 return Type.GetHashCode ();
3158 /// Fully resolved Expression that already evaluated to a type
3160 public class TypeExpression : TypeExpr
3162 public TypeExpression (TypeSpec t, Location l)
3165 eclass = ExprClass.Type;
3169 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3175 public class NamespaceExpression : FullNamedExpression
3177 readonly Namespace ns;
3179 public NamespaceExpression (Namespace ns, Location loc)
3182 this.Type = InternalType.Namespace;
3183 this.eclass = ExprClass.Namespace;
3187 public Namespace Namespace {
3193 protected override Expression DoResolve (ResolveContext rc)
3195 throw new NotImplementedException ();
3198 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3203 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3205 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3206 if (retval != null) {
3207 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3208 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3212 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3213 if (retval != null) {
3214 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3219 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3220 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3224 string assembly = null;
3225 string possible_name = Namespace.GetSignatureForError () + "." + name;
3227 // Only assembly unique name should be added
3228 switch (possible_name) {
3229 case "System.Drawing":
3230 case "System.Web.Services":
3233 case "System.Configuration":
3234 case "System.Data.Services":
3235 case "System.DirectoryServices":
3237 case "System.Net.Http":
3238 case "System.Numerics":
3239 case "System.Runtime.Caching":
3240 case "System.ServiceModel":
3241 case "System.Transactions":
3242 case "System.Web.Routing":
3243 case "System.Xml.Linq":
3245 assembly = possible_name;
3249 case "System.Linq.Expressions":
3250 assembly = "System.Core";
3253 case "System.Windows.Forms":
3254 case "System.Windows.Forms.Layout":
3255 assembly = "System.Windows.Forms";
3259 assembly = assembly == null ? "an" : "`" + assembly + "'";
3261 if (Namespace is GlobalRootNamespace) {
3262 ctx.Module.Compiler.Report.Error (400, loc,
3263 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3266 ctx.Module.Compiler.Report.Error (234, loc,
3267 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3268 name, GetSignatureForError (), assembly);
3272 public override string GetSignatureForError ()
3274 return ns.GetSignatureForError ();
3277 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3279 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3282 public override string ToString ()
3284 return Namespace.Name;
3289 /// This class denotes an expression which evaluates to a member
3290 /// of a struct or a class.
3292 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3294 protected bool conditional_access_receiver;
3297 // An instance expression associated with this member, if it's a
3298 // non-static member
3300 public Expression InstanceExpression;
3303 /// The name of this member.
3305 public abstract string Name {
3310 // When base.member is used
3312 public bool IsBase {
3313 get { return InstanceExpression is BaseThis; }
3317 /// Whether this is an instance member.
3319 public abstract bool IsInstance {
3324 /// Whether this is a static member.
3326 public abstract bool IsStatic {
3330 public abstract string KindName {
3334 public bool ConditionalAccess { get; set; }
3336 protected abstract TypeSpec DeclaringType {
3340 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3342 return InstanceExpression.Type;
3347 // Converts best base candidate for virtual method starting from QueriedBaseType
3349 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3352 // Only when base.member is used and method is virtual
3358 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3359 // means for base.member access we have to find the closest match after we found best candidate
3361 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3363 // The method could already be what we are looking for
3365 TypeSpec[] targs = null;
3366 if (method.DeclaringType != InstanceExpression.Type) {
3368 // Candidate can have inflated MVAR parameters and we need to find
3369 // base match for original definition not inflated parameter types
3371 var parameters = method.Parameters;
3372 if (method.Arity > 0) {
3373 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3374 var inflated = method.DeclaringType as InflatedTypeSpec;
3375 if (inflated != null) {
3376 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3380 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3381 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3382 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3383 if (base_override.IsGeneric)
3384 targs = method.TypeArguments;
3386 method = base_override;
3391 // When base access is used inside anonymous method/iterator/etc we need to
3392 // get back to the context of original type. We do it by emiting proxy
3393 // method in original class and rewriting base call to this compiler
3394 // generated method call which does the actual base invocation. This may
3395 // introduce redundant storey but with `this' only but it's tricky to avoid
3396 // at this stage as we don't know what expressions follow base
3398 if (rc.CurrentAnonymousMethod != null) {
3399 if (targs == null && method.IsGeneric) {
3400 targs = method.TypeArguments;
3401 method = method.GetGenericMethodDefinition ();
3404 if (method.Parameters.HasArglist)
3405 throw new NotImplementedException ("__arglist base call proxy");
3407 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3409 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3410 // get/set member expressions second call would fail to proxy because left expression
3411 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3412 // FIXME: The async check is another hack but will probably fail with mutators
3413 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3414 InstanceExpression = new This (loc).Resolve (rc);
3418 method = method.MakeGenericMethod (rc, targs);
3422 // Only base will allow this invocation to happen.
3424 if (method.IsAbstract) {
3425 rc.Report.SymbolRelatedToPreviousError (method);
3426 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3432 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3434 if (InstanceExpression == null)
3437 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3438 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3439 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3444 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3446 if (InstanceExpression == null)
3449 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3452 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3454 var ct = rc.CurrentType;
3455 if (ct == qualifier)
3458 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3461 qualifier = qualifier.GetDefinition ();
3462 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3469 public override bool ContainsEmitWithAwait ()
3471 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3474 public override bool HasConditionalAccess ()
3476 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3479 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3482 type = type.GetDefinition ();
3484 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3487 type = type.DeclaringType;
3488 } while (type != null);
3493 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3495 if (InstanceExpression != null) {
3496 InstanceExpression = InstanceExpression.Resolve (rc);
3497 CheckProtectedMemberAccess (rc, member);
3500 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3501 UnsafeError (rc, loc);
3504 var dep = member.GetMissingDependencies ();
3506 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3509 member.CheckObsoleteness (rc, loc);
3511 if (!(member is FieldSpec))
3512 member.MemberDefinition.SetIsUsed ();
3515 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3517 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3520 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3522 rc.Report.SymbolRelatedToPreviousError (member);
3523 rc.Report.Error (1540, loc,
3524 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3525 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3528 public override void FlowAnalysis (FlowAnalysisContext fc)
3530 if (InstanceExpression != null) {
3531 InstanceExpression.FlowAnalysis (fc);
3535 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3537 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3538 conditional_access_receiver = true;
3542 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3544 if (!ResolveInstanceExpressionCore (rc, rhs))
3548 // Check intermediate value modification which won't have any effect
3550 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3551 var fexpr = InstanceExpression as FieldExpr;
3552 if (fexpr != null) {
3553 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3556 if (fexpr.IsStatic) {
3557 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3558 fexpr.GetSignatureForError ());
3560 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3561 fexpr.GetSignatureForError ());
3567 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3568 if (rc.CurrentInitializerVariable != null) {
3569 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3570 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3572 rc.Report.Error (1612, loc,
3573 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3574 InstanceExpression.GetSignatureForError ());
3580 var lvr = InstanceExpression as LocalVariableReference;
3583 if (!lvr.local_info.IsReadonly)
3586 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3587 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3594 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3597 if (InstanceExpression != null) {
3598 if (InstanceExpression is TypeExpr) {
3599 var t = InstanceExpression.Type;
3601 t.CheckObsoleteness (rc, loc);
3603 t = t.DeclaringType;
3604 } while (t != null);
3606 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3607 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3608 rc.Report.Error (176, loc,
3609 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3610 GetSignatureForError ());
3614 InstanceExpression = null;
3620 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3621 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3622 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3623 rc.Report.Error (236, loc,
3624 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3625 GetSignatureForError ());
3627 var fe = this as FieldExpr;
3628 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3629 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3630 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3632 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3636 rc.Report.Error (120, loc,
3637 "An object reference is required to access non-static member `{0}'",
3638 GetSignatureForError ());
3642 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3646 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3647 rc.Report.Error (38, loc,
3648 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3649 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3652 InstanceExpression = new This (loc).Resolve (rc);
3656 var me = InstanceExpression as MemberExpr;
3658 me.ResolveInstanceExpressionCore (rc, rhs);
3660 var fe = me as FieldExpr;
3661 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3662 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3663 rc.Report.Warning (1690, 1, loc,
3664 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3665 me.GetSignatureForError ());
3672 // Additional checks for l-value member access
3675 if (InstanceExpression is UnboxCast) {
3676 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3683 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3685 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3686 ec.Report.Warning (1720, 1, left.Location,
3687 "Expression will always cause a `{0}'", "System.NullReferenceException");
3690 InstanceExpression = left;
3694 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3696 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3697 inst.Emit (ec, ConditionalAccess);
3699 if (prepare_for_load)
3700 ec.Emit (OpCodes.Dup);
3703 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3706 public class ExtensionMethodCandidates
3708 readonly NamespaceContainer container;
3709 readonly IList<MethodSpec> methods;
3711 readonly IMemberContext context;
3713 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3715 this.context = context;
3716 this.methods = methods;
3717 this.container = nsContainer;
3718 this.index = lookupIndex;
3721 public NamespaceContainer Container {
3727 public IMemberContext Context {
3733 public int LookupIndex {
3739 public IList<MethodSpec> Methods {
3747 // Represents a group of extension method candidates for whole namespace
3749 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3751 ExtensionMethodCandidates candidates;
3752 public Expression ExtensionExpression;
3754 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3755 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3757 this.candidates = candidates;
3758 this.ExtensionExpression = extensionExpr;
3761 public override bool IsStatic {
3762 get { return true; }
3766 // For extension methodgroup we are not looking for base members but parent
3767 // namespace extension methods
3769 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3771 // TODO: candidates are null only when doing error reporting, that's
3772 // incorrect. We have to discover same extension methods in error mode
3773 if (candidates == null)
3776 int arity = type_arguments == null ? 0 : type_arguments.Count;
3778 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3779 if (candidates == null)
3782 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3785 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3788 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3790 // LAMESPEC: or implicit type parameter conversion
3792 return argType == extensionType ||
3793 TypeSpecComparer.IsEqual (argType, extensionType) ||
3794 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3795 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3798 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3800 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3802 // Not included in C#6
3804 ExtensionExpression = ExtensionExpression.Resolve (rc);
3805 if (ExtensionExpression == null)
3808 var argType = ExtensionExpression.Type;
3809 foreach (MethodSpec candidate in Candidates) {
3810 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3814 // TODO: Scan full hierarchy
3816 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3821 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3823 // We are already here
3827 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3829 if (arguments == null)
3830 arguments = new Arguments (1);
3832 ExtensionExpression = ExtensionExpression.Resolve (ec);
3833 if (ExtensionExpression == null)
3836 var cand = candidates;
3837 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3838 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3839 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3841 // Restore candidates in case we are running in probing mode
3844 // Store resolved argument and restore original arguments
3846 // Clean-up modified arguments for error reporting
3847 arguments.RemoveAt (0);
3851 var me = ExtensionExpression as MemberExpr;
3853 me.ResolveInstanceExpression (ec, null);
3854 var fe = me as FieldExpr;
3856 fe.Spec.MemberDefinition.SetIsUsed ();
3859 InstanceExpression = null;
3863 #region IErrorHandler Members
3865 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3870 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3872 rc.Report.SymbolRelatedToPreviousError (best);
3875 rc.Report.Error (1929, loc,
3876 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3877 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3879 rc.Report.Error (1928, loc,
3880 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3881 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3887 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3892 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3901 /// MethodGroupExpr represents a group of method candidates which
3902 /// can be resolved to the best method overload
3904 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3906 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3908 protected IList<MemberSpec> Methods;
3909 MethodSpec best_candidate;
3910 TypeSpec best_candidate_return;
3911 protected TypeArguments type_arguments;
3913 SimpleName simple_name;
3914 protected TypeSpec queried_type;
3916 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3920 this.type = InternalType.MethodGroup;
3922 eclass = ExprClass.MethodGroup;
3923 queried_type = type;
3926 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3927 : this (new MemberSpec[] { m }, type, loc)
3933 public MethodSpec BestCandidate {
3935 return best_candidate;
3939 public TypeSpec BestCandidateReturnType {
3941 return best_candidate_return;
3945 public IList<MemberSpec> Candidates {
3951 protected override TypeSpec DeclaringType {
3953 return queried_type;
3957 public bool IsConditionallyExcluded {
3959 return Methods == Excluded;
3963 public override bool IsInstance {
3965 if (best_candidate != null)
3966 return !best_candidate.IsStatic;
3972 public override bool IsSideEffectFree {
3974 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3978 public override bool IsStatic {
3980 if (best_candidate != null)
3981 return best_candidate.IsStatic;
3987 public override string KindName {
3988 get { return "method"; }
3991 public override string Name {
3993 if (best_candidate != null)
3994 return best_candidate.Name;
3997 return Methods.First ().Name;
4004 // When best candidate is already know this factory can be used
4005 // to avoid expensive overload resolution to be called
4007 // NOTE: InstanceExpression has to be set manually
4009 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4011 return new MethodGroupExpr (best, queriedType, loc) {
4012 best_candidate = best,
4013 best_candidate_return = best.ReturnType
4017 public override string GetSignatureForError ()
4019 if (best_candidate != null)
4020 return best_candidate.GetSignatureForError ();
4022 return Methods.First ().GetSignatureForError ();
4025 public override Expression CreateExpressionTree (ResolveContext ec)
4027 if (best_candidate == null) {
4028 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4032 if (IsConditionallyExcluded)
4033 ec.Report.Error (765, loc,
4034 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4036 if (ConditionalAccess)
4037 Error_NullShortCircuitInsideExpressionTree (ec);
4039 return new TypeOfMethod (best_candidate, loc);
4042 protected override Expression DoResolve (ResolveContext ec)
4044 this.eclass = ExprClass.MethodGroup;
4046 if (InstanceExpression != null) {
4047 InstanceExpression = InstanceExpression.Resolve (ec);
4048 if (InstanceExpression == null)
4055 public override void Emit (EmitContext ec)
4057 throw new NotSupportedException ();
4060 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4062 var call = new CallEmitter ();
4063 call.InstanceExpression = InstanceExpression;
4064 call.ConditionalAccess = ConditionalAccess;
4067 call.EmitStatement (ec, best_candidate, arguments, loc);
4069 call.Emit (ec, best_candidate, arguments, loc);
4072 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4074 var ca = ec.ConditionalAccess;
4075 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4076 Statement = statement
4079 EmitCall (ec, arguments, statement);
4081 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4082 ec.ConditionalAccess = ca;
4085 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4087 if (target != InternalType.ErrorType) {
4088 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4089 Name, target.GetSignatureForError ());
4093 public bool HasAccessibleCandidate (ResolveContext rc)
4095 foreach (var candidate in Candidates) {
4096 if (candidate.IsAccessible (rc))
4103 public static bool IsExtensionMethodArgument (Expression expr)
4106 // LAMESPEC: No details about which expressions are not allowed
4108 return !(expr is TypeExpr) && !(expr is BaseThis);
4112 /// Find the Applicable Function Members (7.4.2.1)
4114 /// me: Method Group expression with the members to select.
4115 /// it might contain constructors or methods (or anything
4116 /// that maps to a method).
4118 /// Arguments: ArrayList containing resolved Argument objects.
4120 /// loc: The location if we want an error to be reported, or a Null
4121 /// location for "probing" purposes.
4123 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4124 /// that is the best match of me on Arguments.
4127 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4129 // TODO: causes issues with probing mode, remove explicit Kind check
4130 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4133 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4134 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4135 r.BaseMembersProvider = this;
4136 r.InstanceQualifier = this;
4139 if (cerrors != null)
4140 r.CustomErrors = cerrors;
4142 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4143 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4144 if (best_candidate == null) {
4145 if (!r.BestCandidateIsDynamic)
4148 if (simple_name != null && ec.IsStatic)
4149 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4154 // Overload resolver had to create a new method group, all checks bellow have already been executed
4155 if (r.BestCandidateNewMethodGroup != null)
4156 return r.BestCandidateNewMethodGroup;
4158 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4159 if (InstanceExpression != null) {
4160 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4161 InstanceExpression = null;
4163 if (simple_name != null && best_candidate.IsStatic) {
4164 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4167 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4171 ResolveInstanceExpression (ec, null);
4174 var base_override = CandidateToBaseOverride (ec, best_candidate);
4175 if (base_override == best_candidate) {
4176 best_candidate_return = r.BestCandidateReturnType;
4178 best_candidate = base_override;
4179 best_candidate_return = best_candidate.ReturnType;
4182 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4183 ConstraintChecker cc = new ConstraintChecker (ec);
4184 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4188 // Additional check for possible imported base override method which
4189 // could not be done during IsOverrideMethodBaseTypeAccessible
4191 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4192 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4193 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4194 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4197 // Speed up the check by not doing it on disallowed targets
4198 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4204 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4206 var fe = left as FieldExpr;
4209 // Using method-group on struct fields makes the struct assigned. I am not sure
4210 // why but that's what .net does
4212 fe.Spec.MemberDefinition.SetIsAssigned ();
4215 simple_name = original;
4216 return base.ResolveMemberAccess (ec, left, original);
4219 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4221 type_arguments = ta;
4224 #region IBaseMembersProvider Members
4226 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4228 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4231 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4233 if (queried_type == member.DeclaringType)
4236 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4237 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4241 // Extension methods lookup after ordinary methods candidates failed to apply
4243 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4245 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4248 if (!IsExtensionMethodArgument (InstanceExpression))
4251 int arity = type_arguments == null ? 0 : type_arguments.Count;
4252 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4253 if (methods == null)
4256 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4257 emg.SetTypeArguments (rc, type_arguments);
4264 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4266 public ConstructorInstanceQualifier (TypeSpec type)
4269 InstanceType = type;
4272 public TypeSpec InstanceType { get; private set; }
4274 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4276 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4280 public struct OverloadResolver
4283 public enum Restrictions
4287 ProbingOnly = 1 << 1,
4288 CovariantDelegate = 1 << 2,
4289 NoBaseMembers = 1 << 3,
4290 BaseMembersIncluded = 1 << 4,
4291 GetEnumeratorLookup = 1 << 5
4294 public interface IBaseMembersProvider
4296 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4297 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4298 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4301 public interface IErrorHandler
4303 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4304 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4305 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4306 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4309 public interface IInstanceQualifier
4311 TypeSpec InstanceType { get; }
4312 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4315 sealed class NoBaseMembers : IBaseMembersProvider
4317 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4319 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4324 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4329 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4335 struct AmbiguousCandidate
4337 public readonly MemberSpec Member;
4338 public readonly bool Expanded;
4339 public readonly AParametersCollection Parameters;
4341 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4344 Parameters = parameters;
4345 Expanded = expanded;
4350 IList<MemberSpec> members;
4351 TypeArguments type_arguments;
4352 IBaseMembersProvider base_provider;
4353 IErrorHandler custom_errors;
4354 IInstanceQualifier instance_qualifier;
4355 Restrictions restrictions;
4356 MethodGroupExpr best_candidate_extension_group;
4357 TypeSpec best_candidate_return_type;
4359 SessionReportPrinter lambda_conv_msgs;
4361 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4362 : this (members, null, restrictions, loc)
4366 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4369 if (members == null || members.Count == 0)
4370 throw new ArgumentException ("empty members set");
4372 this.members = members;
4374 type_arguments = targs;
4375 this.restrictions = restrictions;
4376 if (IsDelegateInvoke)
4377 this.restrictions |= Restrictions.NoBaseMembers;
4379 base_provider = NoBaseMembers.Instance;
4384 public IBaseMembersProvider BaseMembersProvider {
4386 return base_provider;
4389 base_provider = value;
4393 public bool BestCandidateIsDynamic { get; set; }
4396 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4398 public MethodGroupExpr BestCandidateNewMethodGroup {
4400 return best_candidate_extension_group;
4405 // Return type can be different between best candidate and closest override
4407 public TypeSpec BestCandidateReturnType {
4409 return best_candidate_return_type;
4413 public IErrorHandler CustomErrors {
4415 return custom_errors;
4418 custom_errors = value;
4422 TypeSpec DelegateType {
4424 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4425 throw new InternalErrorException ("Not running in delegate mode", loc);
4427 return members [0].DeclaringType;
4431 public IInstanceQualifier InstanceQualifier {
4433 return instance_qualifier;
4436 instance_qualifier = value;
4440 bool IsProbingOnly {
4442 return (restrictions & Restrictions.ProbingOnly) != 0;
4446 bool IsDelegateInvoke {
4448 return (restrictions & Restrictions.DelegateInvoke) != 0;
4455 // 7.4.3.3 Better conversion from expression
4456 // Returns : 1 if a->p is better,
4457 // 2 if a->q is better,
4458 // 0 if neither is better
4460 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4462 TypeSpec argument_type = a.Type;
4465 // If argument is an anonymous function
4467 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4469 // p and q are delegate types or expression tree types
4471 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4472 if (q.MemberDefinition != p.MemberDefinition) {
4477 // Uwrap delegate from Expression<T>
4479 q = TypeManager.GetTypeArguments (q)[0];
4480 p = TypeManager.GetTypeArguments (p)[0];
4483 var p_m = Delegate.GetInvokeMethod (p);
4484 var q_m = Delegate.GetInvokeMethod (q);
4487 // With identical parameter lists
4489 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4497 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4499 if (p.Kind == MemberKind.Void) {
4500 return q.Kind != MemberKind.Void ? 2 : 0;
4504 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4506 if (q.Kind == MemberKind.Void) {
4507 return p.Kind != MemberKind.Void ? 1: 0;
4510 var am = (AnonymousMethodExpression) a.Expr;
4513 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4514 // better conversion is performed between underlying types Y1 and Y2
4516 if (p.IsGenericTask || q.IsGenericTask) {
4517 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4518 q = q.TypeArguments[0];
4519 p = p.TypeArguments[0];
4525 // An inferred return type X exists for E in the context of that parameter list, and
4526 // the conversion from X to Y1 is better than the conversion from X to Y2
4528 argument_type = am.InferReturnType (ec, null, orig_q);
4529 if (argument_type == null) {
4530 // TODO: Can this be hit?
4534 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4535 argument_type = ec.BuiltinTypes.Object;
4539 if (argument_type == p)
4542 if (argument_type == q)
4546 // The parameters are identicial and return type is not void, use better type conversion
4547 // on return type to determine better one
4549 return BetterTypeConversion (ec, p, q);
4553 // 7.4.3.4 Better conversion from type
4555 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4557 if (p == null || q == null)
4558 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4560 switch (p.BuiltinType) {
4561 case BuiltinTypeSpec.Type.Int:
4562 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4565 case BuiltinTypeSpec.Type.Long:
4566 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4569 case BuiltinTypeSpec.Type.SByte:
4570 switch (q.BuiltinType) {
4571 case BuiltinTypeSpec.Type.Byte:
4572 case BuiltinTypeSpec.Type.UShort:
4573 case BuiltinTypeSpec.Type.UInt:
4574 case BuiltinTypeSpec.Type.ULong:
4578 case BuiltinTypeSpec.Type.Short:
4579 switch (q.BuiltinType) {
4580 case BuiltinTypeSpec.Type.UShort:
4581 case BuiltinTypeSpec.Type.UInt:
4582 case BuiltinTypeSpec.Type.ULong:
4586 case BuiltinTypeSpec.Type.Dynamic:
4587 // Dynamic is never better
4591 switch (q.BuiltinType) {
4592 case BuiltinTypeSpec.Type.Int:
4593 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4596 case BuiltinTypeSpec.Type.Long:
4597 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4600 case BuiltinTypeSpec.Type.SByte:
4601 switch (p.BuiltinType) {
4602 case BuiltinTypeSpec.Type.Byte:
4603 case BuiltinTypeSpec.Type.UShort:
4604 case BuiltinTypeSpec.Type.UInt:
4605 case BuiltinTypeSpec.Type.ULong:
4609 case BuiltinTypeSpec.Type.Short:
4610 switch (p.BuiltinType) {
4611 case BuiltinTypeSpec.Type.UShort:
4612 case BuiltinTypeSpec.Type.UInt:
4613 case BuiltinTypeSpec.Type.ULong:
4617 case BuiltinTypeSpec.Type.Dynamic:
4618 // Dynamic is never better
4622 // FIXME: handle lifted operators
4624 // TODO: this is expensive
4625 Expression p_tmp = new EmptyExpression (p);
4626 Expression q_tmp = new EmptyExpression (q);
4628 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4629 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4631 if (p_to_q && !q_to_p)
4634 if (q_to_p && !p_to_q)
4641 /// Determines "Better function" between candidate
4642 /// and the current best match
4645 /// Returns a boolean indicating :
4646 /// false if candidate ain't better
4647 /// true if candidate is better than the current best match
4649 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4650 MemberSpec best, AParametersCollection bparam, bool best_params)
4652 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4653 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4655 bool better_at_least_one = false;
4656 bool are_equivalent = true;
4657 int args_count = args == null ? 0 : args.Count;
4661 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4664 // Default arguments are ignored for better decision
4665 if (a.IsDefaultArgument)
4669 // When comparing named argument the parameter type index has to be looked up
4670 // in original parameter set (override version for virtual members)
4672 NamedArgument na = a as NamedArgument;
4674 int idx = cparam.GetParameterIndexByName (na.Name);
4675 ct = candidate_pd.Types[idx];
4676 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4677 ct = TypeManager.GetElementType (ct);
4679 idx = bparam.GetParameterIndexByName (na.Name);
4680 bt = best_pd.Types[idx];
4681 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4682 bt = TypeManager.GetElementType (bt);
4684 ct = candidate_pd.Types[c_idx];
4685 bt = best_pd.Types[b_idx];
4687 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4688 ct = TypeManager.GetElementType (ct);
4692 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4693 bt = TypeManager.GetElementType (bt);
4698 if (TypeSpecComparer.IsEqual (ct, bt))
4701 are_equivalent = false;
4702 int result = BetterExpressionConversion (ec, a, ct, bt);
4704 // for each argument, the conversion to 'ct' should be no worse than
4705 // the conversion to 'bt'.
4709 // for at least one argument, the conversion to 'ct' should be better than
4710 // the conversion to 'bt'.
4712 better_at_least_one = true;
4715 if (better_at_least_one)
4719 // Tie-breaking rules are applied only for equivalent parameter types
4721 if (!are_equivalent) {
4723 // LAMESPEC: A candidate with less default parameters is still better when there
4724 // is no better expression conversion
4726 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4734 // If candidate is applicable in its normal form and best has a params array and is applicable
4735 // only in its expanded form, then candidate is better
4737 if (candidate_params != best_params)
4738 return !candidate_params;
4741 // We have not reached end of parameters list due to params or used default parameters
4743 while (j < candidate_pd.Count && j < best_pd.Count) {
4744 var cand_param = candidate_pd.FixedParameters [j];
4745 var best_param = best_pd.FixedParameters [j];
4747 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4748 return cand_param.HasDefaultValue;
4750 if (candidate_pd.Count == best_pd.Count) {
4754 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4755 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4758 if (cand_param.HasDefaultValue) {
4764 // Neither is better when not all arguments are provided
4766 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4767 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4768 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4776 if (candidate_pd.Count != best_pd.Count)
4777 return candidate_pd.Count < best_pd.Count;
4780 // One is a non-generic method and second is a generic method, then non-generic is better
4782 if (best.IsGeneric != candidate.IsGeneric)
4783 return best.IsGeneric;
4786 // Both methods have the same number of parameters, and the parameters have equal types
4787 // Pick the "more specific" signature using rules over original (non-inflated) types
4789 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4790 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4792 bool specific_at_least_once = false;
4793 for (j = 0; j < args_count; ++j) {
4794 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4796 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4797 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4799 ct = candidate_def_pd.Types[j];
4800 bt = best_def_pd.Types[j];
4805 TypeSpec specific = MoreSpecific (ct, bt);
4809 specific_at_least_once = true;
4812 if (specific_at_least_once)
4818 static bool CheckInflatedArguments (MethodSpec ms)
4820 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4823 // Setup constraint checker for probing only
4824 ConstraintChecker cc = new ConstraintChecker (null);
4826 var mp = ms.Parameters.Types;
4827 for (int i = 0; i < mp.Length; ++i) {
4828 var type = mp[i] as InflatedTypeSpec;
4832 var targs = type.TypeArguments;
4833 if (targs.Length == 0)
4836 // TODO: Checking inflated MVAR arguments should be enough
4837 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4844 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4846 rc.Report.Error (1729, loc,
4847 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4848 type.GetSignatureForError (), argCount.ToString ());
4852 // Determines if the candidate method is applicable to the given set of arguments
4853 // There could be two different set of parameters for same candidate where one
4854 // is the closest override for default values and named arguments checks and second
4855 // one being the virtual base for the parameter types and modifiers.
4857 // A return value rates candidate method compatibility,
4859 // 0 = the best, int.MaxValue = the worst
4861 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)
4864 // Each step has allocated 10 values, it can overflow for
4865 // more than 10 arguments but that's ok as it's used for
4866 // better error reporting only
4868 const int ArgumentCountMismatch = 1000000000;
4869 const int NamedArgumentsMismatch = 100000000;
4870 const int DefaultArgumentMismatch = 10000000;
4871 const int UnexpectedTypeArguments = 1000000;
4872 const int TypeArgumentsMismatch = 100000;
4873 const int InflatedTypesMismatch = 10000;
4875 // Parameters of most-derived type used mainly for named and optional parameters
4876 var pd = pm.Parameters;
4878 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4879 // params modifier instead of most-derived type
4880 var cpd = ((IParametersMember) candidate).Parameters;
4881 int param_count = pd.Count;
4882 int optional_count = 0;
4884 Arguments orig_args = arguments;
4886 if (arg_count != param_count) {
4888 // No arguments expansion when doing exact match for delegates
4890 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4891 for (int i = 0; i < pd.Count; ++i) {
4892 if (pd.FixedParameters[i].HasDefaultValue) {
4893 optional_count = pd.Count - i;
4899 if (optional_count != 0) {
4900 // Readjust expected number when params used
4901 if (cpd.HasParams) {
4903 if (arg_count < param_count)
4905 } else if (arg_count > param_count) {
4906 int args_gap = System.Math.Abs (arg_count - param_count);
4907 return ArgumentCountMismatch + args_gap;
4908 } else if (arg_count < param_count - optional_count) {
4909 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4910 return ArgumentCountMismatch + args_gap;
4912 } else if (arg_count != param_count) {
4913 int args_gap = System.Math.Abs (arg_count - param_count);
4915 return ArgumentCountMismatch + args_gap;
4916 if (arg_count < param_count - 1)
4917 return ArgumentCountMismatch + args_gap;
4920 // Resize to fit optional arguments
4921 if (optional_count != 0) {
4922 if (arguments == null) {
4923 arguments = new Arguments (optional_count);
4925 // Have to create a new container, so the next run can do same
4926 var resized = new Arguments (param_count);
4927 resized.AddRange (arguments);
4928 arguments = resized;
4931 for (int i = arg_count; i < param_count; ++i)
4932 arguments.Add (null);
4936 if (arg_count > 0) {
4938 // Shuffle named arguments to the right positions if there are any
4940 if (arguments[arg_count - 1] is NamedArgument) {
4941 arg_count = arguments.Count;
4943 for (int i = 0; i < arg_count; ++i) {
4944 bool arg_moved = false;
4946 NamedArgument na = arguments[i] as NamedArgument;
4950 int index = pd.GetParameterIndexByName (na.Name);
4952 // Named parameter not found
4954 return NamedArgumentsMismatch - i;
4956 // already reordered
4961 if (index >= param_count) {
4962 // When using parameters which should not be available to the user
4963 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4966 arguments.Add (null);
4970 if (index == arg_count)
4971 return NamedArgumentsMismatch - i - 1;
4973 temp = arguments [index];
4975 // The slot has been taken by positional argument
4976 if (temp != null && !(temp is NamedArgument))
4981 arguments = arguments.MarkOrderedArgument (na);
4985 if (arguments == orig_args) {
4986 arguments = new Arguments (orig_args.Count);
4987 arguments.AddRange (orig_args);
4990 arguments[index] = arguments[i];
4991 arguments[i] = temp;
4998 arg_count = arguments.Count;
5000 } else if (arguments != null) {
5001 arg_count = arguments.Count;
5005 // Don't do any expensive checks when the candidate cannot succeed
5007 if (arg_count != param_count && !cpd.HasParams)
5008 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5010 var dep = candidate.GetMissingDependencies ();
5012 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5017 // 1. Handle generic method using type arguments when specified or type inference
5020 var ms = candidate as MethodSpec;
5021 if (ms != null && ms.IsGeneric) {
5022 if (type_arguments != null) {
5023 var g_args_count = ms.Arity;
5024 if (g_args_count != type_arguments.Count)
5025 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5027 if (type_arguments.Arguments != null)
5028 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5031 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5032 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5033 // candidate was found use the set to report more details about what was wrong with lambda body.
5034 // The general idea is to distinguish between code errors and errors caused by
5035 // trial-and-error type inference
5037 if (lambda_conv_msgs == null) {
5038 for (int i = 0; i < arg_count; i++) {
5039 Argument a = arguments[i];
5043 var am = a.Expr as AnonymousMethodExpression;
5045 if (lambda_conv_msgs == null)
5046 lambda_conv_msgs = new SessionReportPrinter ();
5048 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5053 var ti = new TypeInference (arguments);
5054 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5057 return TypeArgumentsMismatch - ti.InferenceScore;
5060 // Clear any error messages when the result was success
5062 if (lambda_conv_msgs != null)
5063 lambda_conv_msgs.ClearSession ();
5065 if (i_args.Length != 0) {
5067 for (int i = 0; i < i_args.Length; ++i) {
5068 var ta = i_args [i];
5069 if (!ta.IsAccessible (ec))
5070 return TypeArgumentsMismatch - i;
5074 ms = ms.MakeGenericMethod (ec, i_args);
5079 // Type arguments constraints have to match for the method to be applicable
5081 if (!CheckInflatedArguments (ms)) {
5083 return InflatedTypesMismatch;
5087 // We have a generic return type and at same time the method is override which
5088 // means we have to also inflate override return type in case the candidate is
5089 // best candidate and override return type is different to base return type.
5091 // virtual Foo<T, object> with override Foo<T, dynamic>
5093 if (candidate != pm) {
5094 MethodSpec override_ms = (MethodSpec) pm;
5095 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5096 returnType = inflator.Inflate (returnType);
5098 returnType = ms.ReturnType;
5105 if (type_arguments != null)
5106 return UnexpectedTypeArguments;
5112 // 2. Each argument has to be implicitly convertible to method parameter
5114 Parameter.Modifier p_mod = 0;
5117 for (int i = 0; i < arg_count; i++) {
5118 Argument a = arguments[i];
5120 var fp = pd.FixedParameters[i];
5121 if (!fp.HasDefaultValue) {
5122 arguments = orig_args;
5123 return arg_count * 2 + 2;
5127 // Get the default value expression, we can use the same expression
5128 // if the type matches
5130 Expression e = fp.DefaultValue;
5132 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5134 // Restore for possible error reporting
5135 for (int ii = i; ii < arg_count; ++ii)
5136 arguments.RemoveAt (i);
5138 return (arg_count - i) * 2 + 1;
5142 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5144 // LAMESPEC: Attributes can be mixed together with build-in priority
5146 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5147 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5148 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5149 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5150 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5151 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5155 arguments[i] = new Argument (e, Argument.AType.Default);
5159 if (p_mod != Parameter.Modifier.PARAMS) {
5160 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5162 } else if (!params_expanded_form) {
5163 params_expanded_form = true;
5164 pt = ((ElementTypeSpec) pt).Element;
5170 if (!params_expanded_form) {
5171 if (a.IsExtensionType) {
5172 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5177 score = IsArgumentCompatible (ec, a, p_mod, pt);
5180 dynamicArgument = true;
5185 // It can be applicable in expanded form (when not doing exact match like for delegates)
5187 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5188 if (!params_expanded_form) {
5189 pt = ((ElementTypeSpec) pt).Element;
5193 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5196 params_expanded_form = true;
5197 dynamicArgument = true;
5198 } else if (score == 0 || arg_count > pd.Count) {
5199 params_expanded_form = true;
5204 if (params_expanded_form)
5206 return (arg_count - i) * 2 + score;
5211 // Restore original arguments for dynamic binder to keep the intention of original source code
5213 if (dynamicArgument)
5214 arguments = orig_args;
5219 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5221 if (e is Constant && e.Type == ptype)
5225 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5227 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5228 e = new MemberAccess (new MemberAccess (new MemberAccess (
5229 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5230 } else if (e is Constant) {
5232 // Handles int to int? conversions, DefaultParameterValue check
5234 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5238 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5241 return e.Resolve (ec);
5245 // Tests argument compatibility with the parameter
5246 // The possible return values are
5248 // 1 - modifier mismatch
5249 // 2 - type mismatch
5250 // -1 - dynamic binding required
5252 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5255 // Types have to be identical when ref or out modifer
5256 // is used and argument is not of dynamic type
5258 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5259 var arg_type = argument.Type;
5261 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5263 // Using dynamic for ref/out parameter can still succeed at runtime
5265 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5271 if (arg_type != parameter) {
5272 if (arg_type == InternalType.VarOutType)
5276 // Do full equality check after quick path
5278 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5280 // Using dynamic for ref/out parameter can still succeed at runtime
5282 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5290 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5294 // Use implicit conversion in all modes to return same candidates when the expression
5295 // is used as argument or delegate conversion
5297 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5298 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5305 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5307 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5309 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5312 var ac_p = p as ArrayContainer;
5314 var ac_q = q as ArrayContainer;
5318 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5319 if (specific == ac_p.Element)
5321 if (specific == ac_q.Element)
5323 } else if (p.IsGeneric && q.IsGeneric) {
5324 var pargs = TypeManager.GetTypeArguments (p);
5325 var qargs = TypeManager.GetTypeArguments (q);
5327 bool p_specific_at_least_once = false;
5328 bool q_specific_at_least_once = false;
5330 for (int i = 0; i < pargs.Length; i++) {
5331 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5332 if (specific == pargs[i])
5333 p_specific_at_least_once = true;
5334 if (specific == qargs[i])
5335 q_specific_at_least_once = true;
5338 if (p_specific_at_least_once && !q_specific_at_least_once)
5340 if (!p_specific_at_least_once && q_specific_at_least_once)
5348 // Find the best method from candidate list
5350 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5352 List<AmbiguousCandidate> ambiguous_candidates = null;
5354 MemberSpec best_candidate;
5355 Arguments best_candidate_args = null;
5356 bool best_candidate_params = false;
5357 bool best_candidate_dynamic = false;
5358 int best_candidate_rate;
5359 IParametersMember best_parameter_member = null;
5361 int args_count = args != null ? args.Count : 0;
5363 Arguments candidate_args = args;
5364 bool error_mode = false;
5365 MemberSpec invocable_member = null;
5366 int applicable_candidates = 0;
5369 best_candidate = null;
5370 best_candidate_rate = int.MaxValue;
5372 var type_members = members;
5374 for (int i = 0; i < type_members.Count; ++i) {
5375 var member = type_members[i];
5378 // Methods in a base class are not candidates if any method in a derived
5379 // class is applicable
5381 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5385 if (!member.IsAccessible (rc))
5388 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5391 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5392 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5397 IParametersMember pm = member as IParametersMember;
5400 // Will use it later to report ambiguity between best method and invocable member
5402 if (Invocation.IsMemberInvocable (member))
5403 invocable_member = member;
5409 // Overload resolution is looking for base member but using parameter names
5410 // and default values from the closest member. That means to do expensive lookup
5411 // for the closest override for virtual or abstract members
5413 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5414 var override_params = base_provider.GetOverrideMemberParameters (member);
5415 if (override_params != null)
5416 pm = override_params;
5420 // Check if the member candidate is applicable
5422 bool params_expanded_form = false;
5423 bool dynamic_argument = false;
5424 TypeSpec rt = pm.MemberType;
5425 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5427 if (lambda_conv_msgs != null)
5428 lambda_conv_msgs.EndSession ();
5431 // How does it score compare to others
5433 if (candidate_rate < best_candidate_rate) {
5435 // Fatal error (missing dependency), cannot continue
5436 if (candidate_rate < 0)
5439 applicable_candidates = 1;
5440 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5441 // Only parameterless methods are considered
5443 best_candidate_rate = candidate_rate;
5444 best_candidate = member;
5445 best_candidate_args = candidate_args;
5446 best_candidate_params = params_expanded_form;
5447 best_candidate_dynamic = dynamic_argument;
5448 best_parameter_member = pm;
5449 best_candidate_return_type = rt;
5451 } else if (candidate_rate == 0) {
5453 // The member look is done per type for most operations but sometimes
5454 // it's not possible like for binary operators overload because they
5455 // are unioned between 2 sides
5457 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5458 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5462 ++applicable_candidates;
5464 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5466 // We pack all interface members into top level type which makes the overload resolution
5467 // more complicated for interfaces. We compensate it by removing methods with same
5468 // signature when building the cache hence this path should not really be hit often
5471 // interface IA { void Foo (int arg); }
5472 // interface IB : IA { void Foo (params int[] args); }
5474 // IB::Foo is the best overload when calling IB.Foo (1)
5477 if (ambiguous_candidates != null) {
5478 foreach (var amb_cand in ambiguous_candidates) {
5479 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5488 ambiguous_candidates = null;
5491 // Is the new candidate better
5492 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5496 best_candidate = member;
5497 best_candidate_args = candidate_args;
5498 best_candidate_params = params_expanded_form;
5499 best_candidate_dynamic = dynamic_argument;
5500 best_parameter_member = pm;
5501 best_candidate_return_type = rt;
5503 // It's not better but any other found later could be but we are not sure yet
5504 if (ambiguous_candidates == null)
5505 ambiguous_candidates = new List<AmbiguousCandidate> ();
5507 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5511 // Restore expanded arguments
5512 candidate_args = args;
5514 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5517 // We've found exact match
5519 if (best_candidate_rate == 0)
5523 // Try extension methods lookup when no ordinary method match was found and provider enables it
5526 var emg = base_provider.LookupExtensionMethod (rc);
5528 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5530 best_candidate_extension_group = emg;
5531 return (T) (MemberSpec) emg.BestCandidate;
5536 // Don't run expensive error reporting mode for probing
5543 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5546 lambda_conv_msgs = null;
5551 // No best member match found, report an error
5553 if (best_candidate_rate != 0 || error_mode) {
5554 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5558 if (best_candidate_dynamic) {
5559 if (args[0].IsExtensionType) {
5560 rc.Report.Error (1973, loc,
5561 "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",
5562 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5566 // Check type constraints only when explicit type arguments are used
5568 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5569 MethodSpec bc = best_candidate as MethodSpec;
5570 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5571 ConstraintChecker cc = new ConstraintChecker (rc);
5572 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5576 BestCandidateIsDynamic = true;
5581 // These flags indicates we are running delegate probing conversion. No need to
5582 // do more expensive checks
5584 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5585 return (T) best_candidate;
5587 if (ambiguous_candidates != null) {
5589 // Now check that there are no ambiguities i.e the selected method
5590 // should be better than all the others
5592 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5593 var candidate = ambiguous_candidates [ix];
5595 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5596 var ambiguous = candidate.Member;
5597 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5598 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5599 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5600 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5601 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5604 return (T) best_candidate;
5609 if (invocable_member != null && !IsProbingOnly) {
5610 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5611 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5612 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5613 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5617 // And now check if the arguments are all
5618 // compatible, perform conversions if
5619 // necessary etc. and return if everything is
5622 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5625 if (best_candidate == null)
5629 // Don't run possibly expensive checks in probing mode
5631 if (!IsProbingOnly && !rc.IsInProbingMode) {
5633 // Check ObsoleteAttribute on the best method
5635 best_candidate.CheckObsoleteness (rc, loc);
5637 best_candidate.MemberDefinition.SetIsUsed ();
5640 args = best_candidate_args;
5641 return (T) best_candidate;
5644 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5646 return ResolveMember<MethodSpec> (rc, ref args);
5649 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5650 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5652 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5655 if (a.Type == InternalType.ErrorType)
5658 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5659 ec.Report.SymbolRelatedToPreviousError (method);
5660 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5661 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5662 TypeManager.CSharpSignature (method));
5665 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5666 TypeManager.CSharpSignature (method));
5667 } else if (IsDelegateInvoke) {
5668 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5669 DelegateType.GetSignatureForError ());
5671 ec.Report.SymbolRelatedToPreviousError (method);
5672 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5673 method.GetSignatureForError ());
5676 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5678 string index = (idx + 1).ToString ();
5679 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5680 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5681 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5682 index, Parameter.GetModifierSignature (a.Modifier));
5684 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5685 index, Parameter.GetModifierSignature (mod));
5687 string p1 = a.GetSignatureForError ();
5688 string p2 = paramType.GetSignatureForError ();
5691 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5692 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5695 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5696 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5697 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5700 ec.Report.Error (1503, a.Expr.Location,
5701 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5706 // We have failed to find exact match so we return error info about the closest match
5708 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5710 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5711 int arg_count = args == null ? 0 : args.Count;
5713 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5714 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5715 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5719 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5724 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5725 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5726 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5730 // For candidates which match on parameters count report more details about incorrect arguments
5733 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5734 // Reject any inaccessible member
5735 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5736 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5737 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5741 var ms = best_candidate as MethodSpec;
5742 if (ms != null && ms.IsGeneric) {
5743 bool constr_ok = true;
5744 if (ms.TypeArguments != null)
5745 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5747 if (ta_count == 0 && ms.TypeArguments == null) {
5748 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5752 rc.Report.Error (411, loc,
5753 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5754 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5761 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5767 // We failed to find any method with correct argument count, report best candidate
5769 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5772 if (best_candidate.Kind == MemberKind.Constructor) {
5773 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5774 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5775 } else if (IsDelegateInvoke) {
5776 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5777 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5778 DelegateType.GetSignatureForError (), arg_count.ToString ());
5780 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5781 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5782 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5783 name, arg_count.ToString ());
5787 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5789 var p = ((IParametersMember)best_candidate).Parameters;
5794 for (int i = p.Count - 1; i != 0; --i) {
5795 var fp = p.FixedParameters [i];
5796 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5806 foreach (var arg in args) {
5807 var na = arg as NamedArgument;
5811 if (na.Name == name) {
5820 return args.Count + 1 == pm.Parameters.Count;
5823 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5825 var pd = pm.Parameters;
5826 var cpd = ((IParametersMember) member).Parameters;
5827 var ptypes = cpd.Types;
5829 Parameter.Modifier p_mod = 0;
5831 int a_idx = 0, a_pos = 0;
5833 ArrayInitializer params_initializers = null;
5834 bool has_unsafe_arg = pm.MemberType.IsPointer;
5835 int arg_count = args == null ? 0 : args.Count;
5837 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5842 if (p_mod != Parameter.Modifier.PARAMS) {
5843 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5845 has_unsafe_arg |= pt.IsPointer;
5847 if (p_mod == Parameter.Modifier.PARAMS) {
5848 if (chose_params_expanded) {
5849 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5850 pt = TypeManager.GetElementType (pt);
5856 // Types have to be identical when ref or out modifer is used
5858 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5859 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5862 var arg_type = a.Type;
5866 if (arg_type == InternalType.VarOutType) {
5868 // Set underlying variable type based on parameter type
5870 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5874 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5878 NamedArgument na = a as NamedArgument;
5880 int name_index = pd.GetParameterIndexByName (na.Name);
5881 if (name_index < 0 || name_index >= pd.Count) {
5882 if (IsDelegateInvoke) {
5883 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5884 ec.Report.Error (1746, na.Location,
5885 "The delegate `{0}' does not contain a parameter named `{1}'",
5886 DelegateType.GetSignatureForError (), na.Name);
5888 ec.Report.SymbolRelatedToPreviousError (member);
5889 ec.Report.Error (1739, na.Location,
5890 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5891 TypeManager.CSharpSignature (member), na.Name);
5893 } else if (args[name_index] != a && args[name_index] != null) {
5894 if (IsDelegateInvoke)
5895 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5897 ec.Report.SymbolRelatedToPreviousError (member);
5899 ec.Report.Error (1744, na.Location,
5900 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5905 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5908 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5909 if (a.IsExtensionType) {
5910 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5911 // CS1061 but that still better than confusing CS0123
5912 var ma = new MemberAccess (a.Expr, member.Name, loc);
5913 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5915 custom_errors.NoArgumentMatch (ec, member);
5921 if (a.IsExtensionType) {
5922 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5925 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5927 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5930 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5937 // Convert params arguments to an array initializer
5939 if (params_initializers != null) {
5940 // we choose to use 'a.Expr' rather than 'conv' so that
5941 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5942 params_initializers.Add (a.Expr);
5943 args.RemoveAt (a_idx--);
5949 // Update the argument with the implicit conversion
5953 if (a_idx != arg_count) {
5955 // Convert all var out argument to error type for less confusing error reporting
5956 // when no matching overload is found
5958 for (; a_idx < arg_count; a_idx++) {
5959 var arg = args [a_idx];
5963 if (arg.Type == InternalType.VarOutType) {
5964 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5968 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5973 // Fill not provided arguments required by params modifier
5975 if (params_initializers == null && arg_count + 1 == pd.Count) {
5977 args = new Arguments (1);
5979 pt = ptypes[pd.Count - 1];
5980 pt = TypeManager.GetElementType (pt);
5981 has_unsafe_arg |= pt.IsPointer;
5982 params_initializers = new ArrayInitializer (0, loc);
5986 // Append an array argument with all params arguments
5988 if (params_initializers != null) {
5989 args.Add (new Argument (
5990 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5994 if (has_unsafe_arg && !ec.IsUnsafe) {
5995 Expression.UnsafeError (ec, loc);
5999 // We could infer inaccesible type arguments
6001 if (type_arguments == null && member.IsGeneric) {
6002 var ms = (MethodSpec) member;
6003 foreach (var ta in ms.TypeArguments) {
6004 if (!ta.IsAccessible (ec)) {
6005 ec.Report.SymbolRelatedToPreviousError (ta);
6006 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6016 public class ConstantExpr : MemberExpr
6018 readonly ConstSpec constant;
6020 public ConstantExpr (ConstSpec constant, Location loc)
6022 this.constant = constant;
6026 public override string Name {
6027 get { throw new NotImplementedException (); }
6030 public override string KindName {
6031 get { return "constant"; }
6034 public override bool IsInstance {
6035 get { return !IsStatic; }
6038 public override bool IsStatic {
6039 get { return true; }
6042 protected override TypeSpec DeclaringType {
6043 get { return constant.DeclaringType; }
6046 public override Expression CreateExpressionTree (ResolveContext ec)
6048 throw new NotSupportedException ("ET");
6051 protected override Expression DoResolve (ResolveContext rc)
6053 ResolveInstanceExpression (rc, null);
6054 DoBestMemberChecks (rc, constant);
6056 var c = constant.GetConstant (rc);
6058 // Creates reference expression to the constant value
6059 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6062 public override void Emit (EmitContext ec)
6064 throw new NotSupportedException ();
6067 public override string GetSignatureForError ()
6069 return constant.GetSignatureForError ();
6072 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6074 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6079 // Fully resolved expression that references a Field
6081 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6083 protected FieldSpec spec;
6084 VariableInfo variable_info;
6086 LocalTemporary temp;
6089 protected FieldExpr (Location l)
6094 public FieldExpr (FieldSpec spec, Location loc)
6099 type = spec.MemberType;
6102 public FieldExpr (FieldBase fi, Location l)
6109 public override string Name {
6115 public bool IsHoisted {
6117 IVariableReference hv = InstanceExpression as IVariableReference;
6118 return hv != null && hv.IsHoisted;
6122 public override bool IsInstance {
6124 return !spec.IsStatic;
6128 public override bool IsStatic {
6130 return spec.IsStatic;
6134 public override string KindName {
6135 get { return "field"; }
6138 public FieldSpec Spec {
6144 protected override TypeSpec DeclaringType {
6146 return spec.DeclaringType;
6150 public VariableInfo VariableInfo {
6152 return variable_info;
6158 public override string GetSignatureForError ()
6160 return spec.GetSignatureForError ();
6163 public bool IsMarshalByRefAccess (ResolveContext rc)
6165 // Checks possible ldflda of field access expression
6166 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6167 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6168 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6171 public void SetHasAddressTaken ()
6173 IVariableReference vr = InstanceExpression as IVariableReference;
6175 vr.SetHasAddressTaken ();
6179 protected override void CloneTo (CloneContext clonectx, Expression target)
6181 var t = (FieldExpr) target;
6183 if (InstanceExpression != null)
6184 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6187 public override Expression CreateExpressionTree (ResolveContext ec)
6189 if (ConditionalAccess) {
6190 Error_NullShortCircuitInsideExpressionTree (ec);
6193 return CreateExpressionTree (ec, true);
6196 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6199 Expression instance;
6201 if (InstanceExpression == null) {
6202 instance = new NullLiteral (loc);
6203 } else if (convertInstance) {
6204 instance = InstanceExpression.CreateExpressionTree (ec);
6206 args = new Arguments (1);
6207 args.Add (new Argument (InstanceExpression));
6208 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6211 args = Arguments.CreateForExpressionTree (ec, null,
6213 CreateTypeOfExpression ());
6215 return CreateExpressionFactoryCall (ec, "Field", args);
6218 public Expression CreateTypeOfExpression ()
6220 return new TypeOfField (spec, loc);
6223 protected override Expression DoResolve (ResolveContext ec)
6225 spec.MemberDefinition.SetIsUsed ();
6227 return DoResolve (ec, null);
6230 Expression DoResolve (ResolveContext ec, Expression rhs)
6232 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6235 ResolveConditionalAccessReceiver (ec);
6237 if (ResolveInstanceExpression (ec, rhs)) {
6238 // Resolve the field's instance expression while flow analysis is turned
6239 // off: when accessing a field "a.b", we must check whether the field
6240 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6242 if (lvalue_instance) {
6243 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6245 Expression right_side =
6246 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6248 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6250 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6253 if (InstanceExpression == null)
6257 DoBestMemberChecks (ec, spec);
6259 if (conditional_access_receiver)
6260 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6263 var fb = spec as FixedFieldSpec;
6264 IVariableReference var = InstanceExpression as IVariableReference;
6267 IFixedExpression fe = InstanceExpression as IFixedExpression;
6268 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6269 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6272 if (InstanceExpression.eclass != ExprClass.Variable) {
6273 ec.Report.SymbolRelatedToPreviousError (spec);
6274 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6275 TypeManager.GetFullNameSignature (spec));
6276 } else if (var != null && var.IsHoisted) {
6277 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6280 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6284 // Set flow-analysis variable info for struct member access. It will be check later
6285 // for precise error reporting
6287 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6288 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6291 if (conditional_access_receiver)
6292 type = LiftMemberType (ec, type);
6294 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6295 return Constant.CreateConstantFromValue (type, null, loc);
6297 eclass = ExprClass.Variable;
6301 public void SetFieldAssigned (FlowAnalysisContext fc)
6306 bool lvalue_instance = spec.DeclaringType.IsStruct;
6307 if (lvalue_instance) {
6308 var var = InstanceExpression as IVariableReference;
6309 if (var != null && var.VariableInfo != null) {
6310 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6314 var fe = InstanceExpression as FieldExpr;
6316 Expression instance;
6319 instance = fe.InstanceExpression;
6320 var fe_instance = instance as FieldExpr;
6321 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6322 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6323 var var = InstanceExpression as IVariableReference;
6324 if (var != null && var.VariableInfo == null) {
6325 var var_inst = instance as IVariableReference;
6326 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6327 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6331 if (fe_instance != null) {
6340 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6341 instance.FlowAnalysis (fc);
6343 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6344 InstanceExpression.FlowAnalysis (fc);
6348 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6350 // The return value is always null. Returning a value simplifies calling code.
6352 if (right_side == EmptyExpression.OutAccess) {
6354 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6355 GetSignatureForError ());
6357 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6358 GetSignatureForError ());
6364 if (right_side == EmptyExpression.LValueMemberAccess) {
6365 // Already reported as CS1648/CS1650
6369 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6371 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6372 GetSignatureForError ());
6374 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6375 GetSignatureForError ());
6381 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6382 GetSignatureForError ());
6384 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6385 GetSignatureForError ());
6391 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6393 if (HasConditionalAccess ())
6394 Error_NullPropagatingLValue (ec);
6396 if (spec is FixedFieldSpec) {
6397 // It could be much better error message but we want to be error compatible
6398 Error_ValueAssignment (ec, right_side);
6401 Expression e = DoResolve (ec, right_side);
6406 spec.MemberDefinition.SetIsAssigned ();
6408 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6409 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6410 ec.Report.Warning (420, 1, loc,
6411 "`{0}': A volatile field references will not be treated as volatile",
6412 spec.GetSignatureForError ());
6415 if (spec.IsReadOnly) {
6416 // InitOnly fields can only be assigned in constructors or initializers
6417 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6418 return Error_AssignToReadonly (ec, right_side);
6420 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6422 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6423 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6424 return Error_AssignToReadonly (ec, right_side);
6425 // static InitOnly fields cannot be assigned-to in an instance constructor
6426 if (IsStatic && !ec.IsStatic)
6427 return Error_AssignToReadonly (ec, right_side);
6428 // instance constructors can't modify InitOnly fields of other instances of the same type
6429 if (!IsStatic && !(InstanceExpression is This))
6430 return Error_AssignToReadonly (ec, right_side);
6434 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6435 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6436 ec.Report.Warning (197, 1, loc,
6437 "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",
6438 GetSignatureForError ());
6441 eclass = ExprClass.Variable;
6445 public override void FlowAnalysis (FlowAnalysisContext fc)
6447 var var = InstanceExpression as IVariableReference;
6449 var vi = var.VariableInfo;
6450 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6451 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6455 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6456 var le = SkipLeftValueTypeAccess (InstanceExpression);
6458 le.FlowAnalysis (fc);
6464 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6466 base.FlowAnalysis (fc);
6468 if (conditional_access_receiver)
6469 fc.DefiniteAssignment = da;
6472 static Expression SkipLeftValueTypeAccess (Expression expr)
6474 if (!TypeSpec.IsValueType (expr.Type))
6477 if (expr is VariableReference)
6480 var fe = expr as FieldExpr;
6484 if (fe.InstanceExpression == null)
6487 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6490 public override int GetHashCode ()
6492 return spec.GetHashCode ();
6495 public bool IsFixed {
6498 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6500 IVariableReference variable = InstanceExpression as IVariableReference;
6501 if (variable != null)
6502 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6504 IFixedExpression fe = InstanceExpression as IFixedExpression;
6505 return fe != null && fe.IsFixed;
6509 public override bool Equals (object obj)
6511 FieldExpr fe = obj as FieldExpr;
6515 if (spec != fe.spec)
6518 if (InstanceExpression == null || fe.InstanceExpression == null)
6521 return InstanceExpression.Equals (fe.InstanceExpression);
6524 public void Emit (EmitContext ec, bool leave_copy)
6526 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6530 ec.Emit (OpCodes.Volatile);
6532 ec.Emit (OpCodes.Ldsfld, spec);
6535 if (conditional_access_receiver)
6536 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6538 EmitInstance (ec, false);
6541 // Optimization for build-in types
6542 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6543 ec.EmitLoadFromPtr (type);
6545 var ff = spec as FixedFieldSpec;
6547 ec.Emit (OpCodes.Ldflda, spec);
6548 ec.Emit (OpCodes.Ldflda, ff.Element);
6551 ec.Emit (OpCodes.Volatile);
6553 ec.Emit (OpCodes.Ldfld, spec);
6557 if (conditional_access_receiver) {
6558 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6563 ec.Emit (OpCodes.Dup);
6565 temp = new LocalTemporary (this.Type);
6571 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6573 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6574 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6579 if (ConditionalAccess)
6580 throw new NotImplementedException ("null operator assignment");
6582 if (has_await_source)
6583 source = source.EmitToField (ec);
6585 EmitInstance (ec, prepared);
6590 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6591 ec.Emit (OpCodes.Dup);
6593 temp = new LocalTemporary (this.Type);
6598 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6599 ec.Emit (OpCodes.Volatile);
6601 spec.MemberDefinition.SetIsAssigned ();
6604 ec.Emit (OpCodes.Stsfld, spec);
6606 ec.Emit (OpCodes.Stfld, spec);
6608 if (ec.NotifyEvaluatorOnStore) {
6610 throw new NotImplementedException ("instance field write");
6613 ec.Emit (OpCodes.Dup);
6615 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6626 // Emits store to field with prepared values on stack
6628 public void EmitAssignFromStack (EmitContext ec)
6631 ec.Emit (OpCodes.Stsfld, spec);
6633 ec.Emit (OpCodes.Stfld, spec);
6637 public override void Emit (EmitContext ec)
6642 public override void EmitSideEffect (EmitContext ec)
6644 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6646 if (is_volatile) // || is_marshal_by_ref ())
6647 base.EmitSideEffect (ec);
6650 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6652 if ((mode & AddressOp.Store) != 0)
6653 spec.MemberDefinition.SetIsAssigned ();
6654 if ((mode & AddressOp.Load) != 0)
6655 spec.MemberDefinition.SetIsUsed ();
6658 // Handle initonly fields specially: make a copy and then
6659 // get the address of the copy.
6662 if (spec.IsReadOnly){
6664 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6676 var temp = ec.GetTemporaryLocal (type);
6677 ec.Emit (OpCodes.Stloc, temp);
6678 ec.Emit (OpCodes.Ldloca, temp);
6684 ec.Emit (OpCodes.Ldsflda, spec);
6687 EmitInstance (ec, false);
6688 ec.Emit (OpCodes.Ldflda, spec);
6692 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6694 return MakeExpression (ctx);
6697 public override SLE.Expression MakeExpression (BuilderContext ctx)
6700 return base.MakeExpression (ctx);
6702 return SLE.Expression.Field (
6703 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6704 spec.GetMetaInfo ());
6708 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6710 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6716 // Expression that evaluates to a Property.
6718 // This is not an LValue because we need to re-write the expression. We
6719 // can not take data from the stack and store it.
6721 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6723 Arguments arguments;
6724 FieldExpr backing_field;
6726 public PropertyExpr (PropertySpec spec, Location l)
6729 best_candidate = spec;
6730 type = spec.MemberType;
6735 protected override Arguments Arguments {
6744 protected override TypeSpec DeclaringType {
6746 return best_candidate.DeclaringType;
6750 public override string Name {
6752 return best_candidate.Name;
6756 public bool IsAutoPropertyAccess {
6758 var prop = best_candidate.MemberDefinition as Property;
6759 return prop != null && prop.BackingField != null;
6763 public override bool IsInstance {
6769 public override bool IsStatic {
6771 return best_candidate.IsStatic;
6775 public override string KindName {
6776 get { return "property"; }
6779 public PropertySpec PropertyInfo {
6781 return best_candidate;
6787 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6789 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6792 var args_count = arguments == null ? 0 : arguments.Count;
6793 if (args_count != body.Parameters.Count && args_count == 0)
6796 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6797 mg.InstanceExpression = InstanceExpression;
6802 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6804 return new PropertyExpr (spec, loc) {
6810 public override Expression CreateExpressionTree (ResolveContext ec)
6812 if (ConditionalAccess) {
6813 Error_NullShortCircuitInsideExpressionTree (ec);
6817 if (IsSingleDimensionalArrayLength ()) {
6818 args = new Arguments (1);
6819 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6820 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6823 args = new Arguments (2);
6824 if (InstanceExpression == null)
6825 args.Add (new Argument (new NullLiteral (loc)));
6827 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6828 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6829 return CreateExpressionFactoryCall (ec, "Property", args);
6832 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6834 DoResolveLValue (rc, null);
6835 return new TypeOfMethod (Setter, loc);
6838 public override string GetSignatureForError ()
6840 return best_candidate.GetSignatureForError ();
6843 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6846 return base.MakeExpression (ctx);
6848 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6852 public override SLE.Expression MakeExpression (BuilderContext ctx)
6855 return base.MakeExpression (ctx);
6857 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6861 void Error_PropertyNotValid (ResolveContext ec)
6863 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6864 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6865 GetSignatureForError ());
6868 bool IsSingleDimensionalArrayLength ()
6870 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6873 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6874 return ac != null && ac.Rank == 1;
6877 public override void Emit (EmitContext ec, bool leave_copy)
6880 // Special case: length of single dimension array property is turned into ldlen
6882 if (IsSingleDimensionalArrayLength ()) {
6883 if (conditional_access_receiver) {
6884 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6887 EmitInstance (ec, false);
6889 ec.Emit (OpCodes.Ldlen);
6890 ec.Emit (OpCodes.Conv_I4);
6892 if (conditional_access_receiver) {
6893 ec.CloseConditionalAccess (type);
6899 base.Emit (ec, leave_copy);
6902 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6904 if (backing_field != null) {
6905 backing_field.EmitAssign (ec, source, false, false);
6910 LocalTemporary await_source_arg = null;
6912 if (isCompound && !(source is DynamicExpressionStatement)) {
6913 emitting_compound_assignment = true;
6916 if (has_await_arguments) {
6917 await_source_arg = new LocalTemporary (Type);
6918 await_source_arg.Store (ec);
6920 args = new Arguments (1);
6921 args.Add (new Argument (await_source_arg));
6924 temp = await_source_arg;
6927 has_await_arguments = false;
6932 ec.Emit (OpCodes.Dup);
6933 temp = new LocalTemporary (this.Type);
6938 args = arguments ?? new Arguments (1);
6942 temp = new LocalTemporary (this.Type);
6944 args.Add (new Argument (temp));
6946 args.Add (new Argument (source));
6950 emitting_compound_assignment = false;
6952 var call = new CallEmitter ();
6953 call.InstanceExpression = InstanceExpression;
6955 call.InstanceExpressionOnStack = true;
6957 if (ConditionalAccess) {
6958 call.ConditionalAccess = true;
6962 call.Emit (ec, Setter, args, loc);
6964 call.EmitStatement (ec, Setter, args, loc);
6971 if (await_source_arg != null) {
6972 await_source_arg.Release (ec);
6976 public override void FlowAnalysis (FlowAnalysisContext fc)
6978 var prop = best_candidate.MemberDefinition as Property;
6979 if (prop != null && prop.BackingField != null) {
6980 var var = InstanceExpression as IVariableReference;
6982 var vi = var.VariableInfo;
6983 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6984 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6988 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6993 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6995 base.FlowAnalysis (fc);
6997 if (conditional_access_receiver)
6998 fc.DefiniteAssignment = da;
7001 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7003 eclass = ExprClass.PropertyAccess;
7005 if (best_candidate.IsNotCSharpCompatible) {
7006 Error_PropertyNotValid (rc);
7009 ResolveInstanceExpression (rc, right_side);
7011 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7012 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7013 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7015 type = p.MemberType;
7019 DoBestMemberChecks (rc, best_candidate);
7021 // Handling of com-imported properties with any number of default property parameters
7022 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7023 var p = best_candidate.Get.Parameters;
7024 arguments = new Arguments (p.Count);
7025 for (int i = 0; i < p.Count; ++i) {
7026 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7028 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7029 var p = best_candidate.Set.Parameters;
7030 arguments = new Arguments (p.Count - 1);
7031 for (int i = 0; i < p.Count - 1; ++i) {
7032 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7039 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7041 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7044 var prop = best_candidate.MemberDefinition as Property;
7045 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7046 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7050 prop = (Property)ps.MemberDefinition;
7053 var spec = prop.BackingField;
7057 if (rc.IsStatic != spec.IsStatic)
7060 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7063 backing_field = new FieldExpr (prop.BackingField, loc);
7064 backing_field.ResolveLValue (rc, rhs);
7068 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7070 if (backing_field != null) {
7071 backing_field.SetFieldAssigned (fc);
7075 if (!IsAutoPropertyAccess)
7078 var prop = best_candidate.MemberDefinition as Property;
7079 if (prop != null && prop.BackingField != null) {
7080 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7081 if (lvalue_instance) {
7082 var var = InstanceExpression as IVariableReference;
7083 if (var != null && var.VariableInfo != null) {
7084 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7090 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7092 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7096 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7098 // getter and setter can be different for base calls
7099 MethodSpec getter, setter;
7100 protected T best_candidate;
7102 protected LocalTemporary temp;
7103 protected bool emitting_compound_assignment;
7104 protected bool has_await_arguments;
7106 protected PropertyOrIndexerExpr (Location l)
7113 protected abstract Arguments Arguments { get; set; }
7115 public MethodSpec Getter {
7124 public MethodSpec Setter {
7135 protected override Expression DoResolve (ResolveContext ec)
7137 if (eclass == ExprClass.Unresolved) {
7138 ResolveConditionalAccessReceiver (ec);
7140 var expr = OverloadResolve (ec, null);
7145 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7146 return expr.Resolve (ec);
7149 if (conditional_access_receiver) {
7150 type = LiftMemberType (ec, type);
7154 if (!ResolveGetter (ec))
7160 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7162 if (HasConditionalAccess ())
7163 Error_NullPropagatingLValue (rc);
7165 if (right_side == EmptyExpression.OutAccess) {
7166 // TODO: best_candidate can be null at this point
7167 INamedBlockVariable variable = null;
7168 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7169 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7170 best_candidate.Name);
7172 right_side.DoResolveLValue (rc, this);
7177 if (eclass == ExprClass.Unresolved) {
7178 var expr = OverloadResolve (rc, right_side);
7183 return expr.ResolveLValue (rc, right_side);
7185 ResolveInstanceExpression (rc, right_side);
7188 if (!best_candidate.HasSet) {
7189 if (ResolveAutopropertyAssignment (rc, right_side))
7192 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7193 GetSignatureForError ());
7197 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7198 if (best_candidate.HasDifferentAccessibility) {
7199 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7200 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7201 GetSignatureForError ());
7203 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7204 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7208 if (best_candidate.HasDifferentAccessibility)
7209 CheckProtectedMemberAccess (rc, best_candidate.Set);
7211 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7215 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7217 var ca = ec.ConditionalAccess;
7218 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7220 call.Emit (ec, method, arguments, loc);
7222 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7223 ec.ConditionalAccess = ca;
7227 // Implements the IAssignMethod interface for assignments
7229 public virtual void Emit (EmitContext ec, bool leave_copy)
7231 var call = new CallEmitter ();
7232 call.ConditionalAccess = ConditionalAccess;
7233 call.InstanceExpression = InstanceExpression;
7234 if (has_await_arguments)
7235 call.HasAwaitArguments = true;
7237 call.DuplicateArguments = emitting_compound_assignment;
7239 if (conditional_access_receiver)
7240 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7242 call.Emit (ec, Getter, Arguments, loc);
7244 if (call.HasAwaitArguments) {
7245 InstanceExpression = call.InstanceExpression;
7246 Arguments = call.EmittedArguments;
7247 has_await_arguments = true;
7251 ec.Emit (OpCodes.Dup);
7252 temp = new LocalTemporary (Type);
7257 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7259 public override void Emit (EmitContext ec)
7264 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7266 has_await_arguments = true;
7271 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7273 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7275 bool ResolveGetter (ResolveContext rc)
7277 if (!best_candidate.HasGet) {
7278 if (InstanceExpression != EmptyExpression.Null) {
7279 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7280 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7281 best_candidate.GetSignatureForError ());
7284 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7285 if (best_candidate.HasDifferentAccessibility) {
7286 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7287 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7288 TypeManager.CSharpSignature (best_candidate));
7290 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7291 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7295 if (best_candidate.HasDifferentAccessibility) {
7296 CheckProtectedMemberAccess (rc, best_candidate.Get);
7299 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7303 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7310 /// Fully resolved expression that evaluates to an Event
7312 public class EventExpr : MemberExpr, IAssignMethod
7314 readonly EventSpec spec;
7317 public EventExpr (EventSpec spec, Location loc)
7325 protected override TypeSpec DeclaringType {
7327 return spec.DeclaringType;
7331 public override string Name {
7337 public override bool IsInstance {
7339 return !spec.IsStatic;
7343 public override bool IsStatic {
7345 return spec.IsStatic;
7349 public override string KindName {
7350 get { return "event"; }
7353 public MethodSpec Operator {
7361 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7364 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7366 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7367 if (spec.BackingField != null &&
7368 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7370 spec.MemberDefinition.SetIsUsed ();
7372 spec.CheckObsoleteness (ec, loc);
7374 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7375 Error_AssignmentEventOnly (ec);
7377 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7379 InstanceExpression = null;
7381 return ml.ResolveMemberAccess (ec, left, original);
7385 return base.ResolveMemberAccess (ec, left, original);
7388 public override Expression CreateExpressionTree (ResolveContext ec)
7390 throw new NotSupportedException ("ET");
7393 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7395 if (right_side == EmptyExpression.EventAddition) {
7396 op = spec.AccessorAdd;
7397 } else if (right_side == EmptyExpression.EventSubtraction) {
7398 op = spec.AccessorRemove;
7402 Error_AssignmentEventOnly (ec);
7406 if (HasConditionalAccess ())
7407 Error_NullPropagatingLValue (ec);
7409 op = CandidateToBaseOverride (ec, op);
7413 protected override Expression DoResolve (ResolveContext ec)
7415 eclass = ExprClass.EventAccess;
7416 type = spec.MemberType;
7418 ResolveInstanceExpression (ec, null);
7420 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7421 Error_AssignmentEventOnly (ec);
7424 DoBestMemberChecks (ec, spec);
7428 public override void Emit (EmitContext ec)
7430 throw new NotSupportedException ();
7431 //Error_CannotAssign ();
7434 #region IAssignMethod Members
7436 public void Emit (EmitContext ec, bool leave_copy)
7438 throw new NotImplementedException ();
7441 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7443 if (leave_copy || !isCompound)
7444 throw new NotImplementedException ("EventExpr::EmitAssign");
7446 Arguments args = new Arguments (1);
7447 args.Add (new Argument (source));
7449 // TODO: Wrong, needs receiver
7450 // if (NullShortCircuit) {
7451 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7454 var call = new CallEmitter ();
7455 call.InstanceExpression = InstanceExpression;
7456 call.ConditionalAccess = ConditionalAccess;
7457 call.EmitStatement (ec, op, args, loc);
7459 // if (NullShortCircuit)
7460 // ec.CloseConditionalAccess (null);
7465 void Error_AssignmentEventOnly (ResolveContext ec)
7467 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7468 ec.Report.Error (79, loc,
7469 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7470 GetSignatureForError ());
7472 ec.Report.Error (70, loc,
7473 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7474 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7478 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7480 name = name.Substring (0, name.LastIndexOf ('.'));
7481 base.Error_CannotCallAbstractBase (rc, name);
7484 public override string GetSignatureForError ()
7486 return TypeManager.CSharpSignature (spec);
7489 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7491 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7495 public class TemporaryVariableReference : VariableReference
7497 public class Declarator : Statement
7499 TemporaryVariableReference variable;
7501 public Declarator (TemporaryVariableReference variable)
7503 this.variable = variable;
7507 protected override void DoEmit (EmitContext ec)
7509 variable.li.CreateBuilder (ec);
7512 public override void Emit (EmitContext ec)
7514 // Don't create sequence point
7518 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7523 protected override void CloneTo (CloneContext clonectx, Statement target)
7531 public TemporaryVariableReference (LocalVariable li, Location loc)
7534 this.type = li.Type;
7538 public override bool IsLockedByStatement {
7546 public LocalVariable LocalInfo {
7552 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7554 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7555 return new TemporaryVariableReference (li, loc);
7558 protected override Expression DoResolve (ResolveContext ec)
7560 eclass = ExprClass.Variable;
7563 // Don't capture temporary variables except when using
7564 // state machine redirection and block yields
7566 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7567 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7568 ec.IsVariableCapturingRequired) {
7569 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7570 storey.CaptureLocalVariable (ec, li);
7576 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7578 return Resolve (ec);
7581 public override void Emit (EmitContext ec)
7583 li.CreateBuilder (ec);
7588 public void EmitAssign (EmitContext ec, Expression source)
7590 li.CreateBuilder (ec);
7592 EmitAssign (ec, source, false, false);
7595 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7597 return li.HoistedVariant;
7600 public override bool IsFixed {
7601 get { return true; }
7604 public override bool IsRef {
7605 get { return false; }
7608 public override string Name {
7609 get { throw new NotImplementedException (); }
7612 public override void SetHasAddressTaken ()
7614 throw new NotImplementedException ();
7617 protected override ILocalVariable Variable {
7621 public override VariableInfo VariableInfo {
7622 get { return null; }
7627 /// Handles `var' contextual keyword; var becomes a keyword only
7628 /// if no type called var exists in a variable scope
7630 class VarExpr : SimpleName
7632 public VarExpr (Location loc)
7637 public bool InferType (ResolveContext ec, Expression right_side)
7640 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7642 type = right_side.Type;
7643 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7644 ec.Report.Error (815, loc,
7645 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7646 type.GetSignatureForError ());
7647 type = InternalType.ErrorType;
7651 eclass = ExprClass.Variable;
7655 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7657 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7658 base.Error_TypeOrNamespaceNotFound (ec);
7660 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");