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 && !ec.HasSet (ResolveContext.Options.NameOfScope) && 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);
4258 emg.ConditionalAccess = ConditionalAccess;
4265 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4267 public ConstructorInstanceQualifier (TypeSpec type)
4270 InstanceType = type;
4273 public TypeSpec InstanceType { get; private set; }
4275 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4277 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4281 public struct OverloadResolver
4284 public enum Restrictions
4288 ProbingOnly = 1 << 1,
4289 CovariantDelegate = 1 << 2,
4290 NoBaseMembers = 1 << 3,
4291 BaseMembersIncluded = 1 << 4,
4292 GetEnumeratorLookup = 1 << 5
4295 public interface IBaseMembersProvider
4297 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4298 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4299 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4302 public interface IErrorHandler
4304 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4305 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4306 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4307 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4310 public interface IInstanceQualifier
4312 TypeSpec InstanceType { get; }
4313 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4316 sealed class NoBaseMembers : IBaseMembersProvider
4318 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4320 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4325 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4330 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4336 struct AmbiguousCandidate
4338 public readonly MemberSpec Member;
4339 public readonly bool Expanded;
4340 public readonly AParametersCollection Parameters;
4342 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4345 Parameters = parameters;
4346 Expanded = expanded;
4351 IList<MemberSpec> members;
4352 TypeArguments type_arguments;
4353 IBaseMembersProvider base_provider;
4354 IErrorHandler custom_errors;
4355 IInstanceQualifier instance_qualifier;
4356 Restrictions restrictions;
4357 MethodGroupExpr best_candidate_extension_group;
4358 TypeSpec best_candidate_return_type;
4360 SessionReportPrinter lambda_conv_msgs;
4362 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4363 : this (members, null, restrictions, loc)
4367 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4370 if (members == null || members.Count == 0)
4371 throw new ArgumentException ("empty members set");
4373 this.members = members;
4375 type_arguments = targs;
4376 this.restrictions = restrictions;
4377 if (IsDelegateInvoke)
4378 this.restrictions |= Restrictions.NoBaseMembers;
4380 base_provider = NoBaseMembers.Instance;
4385 public IBaseMembersProvider BaseMembersProvider {
4387 return base_provider;
4390 base_provider = value;
4394 public bool BestCandidateIsDynamic { get; set; }
4397 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4399 public MethodGroupExpr BestCandidateNewMethodGroup {
4401 return best_candidate_extension_group;
4406 // Return type can be different between best candidate and closest override
4408 public TypeSpec BestCandidateReturnType {
4410 return best_candidate_return_type;
4414 public IErrorHandler CustomErrors {
4416 return custom_errors;
4419 custom_errors = value;
4423 TypeSpec DelegateType {
4425 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4426 throw new InternalErrorException ("Not running in delegate mode", loc);
4428 return members [0].DeclaringType;
4432 public IInstanceQualifier InstanceQualifier {
4434 return instance_qualifier;
4437 instance_qualifier = value;
4441 bool IsProbingOnly {
4443 return (restrictions & Restrictions.ProbingOnly) != 0;
4447 bool IsDelegateInvoke {
4449 return (restrictions & Restrictions.DelegateInvoke) != 0;
4456 // 7.4.3.3 Better conversion from expression
4457 // Returns : 1 if a->p is better,
4458 // 2 if a->q is better,
4459 // 0 if neither is better
4461 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4463 TypeSpec argument_type = a.Type;
4466 // If argument is an anonymous function
4468 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4470 // p and q are delegate types or expression tree types
4472 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4473 if (q.MemberDefinition != p.MemberDefinition) {
4478 // Uwrap delegate from Expression<T>
4480 q = TypeManager.GetTypeArguments (q)[0];
4481 p = TypeManager.GetTypeArguments (p)[0];
4484 var p_m = Delegate.GetInvokeMethod (p);
4485 var q_m = Delegate.GetInvokeMethod (q);
4488 // With identical parameter lists
4490 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4498 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4500 if (p.Kind == MemberKind.Void) {
4501 return q.Kind != MemberKind.Void ? 2 : 0;
4505 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4507 if (q.Kind == MemberKind.Void) {
4508 return p.Kind != MemberKind.Void ? 1: 0;
4511 var am = (AnonymousMethodExpression) a.Expr;
4514 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4515 // better conversion is performed between underlying types Y1 and Y2
4517 if (p.IsGenericTask || q.IsGenericTask) {
4518 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4519 q = q.TypeArguments[0];
4520 p = p.TypeArguments[0];
4526 // An inferred return type X exists for E in the context of that parameter list, and
4527 // the conversion from X to Y1 is better than the conversion from X to Y2
4529 argument_type = am.InferReturnType (ec, null, orig_q);
4530 if (argument_type == null) {
4531 // TODO: Can this be hit?
4535 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4536 argument_type = ec.BuiltinTypes.Object;
4540 if (argument_type == p)
4543 if (argument_type == q)
4547 // The parameters are identicial and return type is not void, use better type conversion
4548 // on return type to determine better one
4550 return BetterTypeConversion (ec, p, q);
4554 // 7.4.3.4 Better conversion from type
4556 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4558 if (p == null || q == null)
4559 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4561 switch (p.BuiltinType) {
4562 case BuiltinTypeSpec.Type.Int:
4563 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4566 case BuiltinTypeSpec.Type.Long:
4567 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4570 case BuiltinTypeSpec.Type.SByte:
4571 switch (q.BuiltinType) {
4572 case BuiltinTypeSpec.Type.Byte:
4573 case BuiltinTypeSpec.Type.UShort:
4574 case BuiltinTypeSpec.Type.UInt:
4575 case BuiltinTypeSpec.Type.ULong:
4579 case BuiltinTypeSpec.Type.Short:
4580 switch (q.BuiltinType) {
4581 case BuiltinTypeSpec.Type.UShort:
4582 case BuiltinTypeSpec.Type.UInt:
4583 case BuiltinTypeSpec.Type.ULong:
4587 case BuiltinTypeSpec.Type.Dynamic:
4588 // Dynamic is never better
4592 switch (q.BuiltinType) {
4593 case BuiltinTypeSpec.Type.Int:
4594 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4597 case BuiltinTypeSpec.Type.Long:
4598 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4601 case BuiltinTypeSpec.Type.SByte:
4602 switch (p.BuiltinType) {
4603 case BuiltinTypeSpec.Type.Byte:
4604 case BuiltinTypeSpec.Type.UShort:
4605 case BuiltinTypeSpec.Type.UInt:
4606 case BuiltinTypeSpec.Type.ULong:
4610 case BuiltinTypeSpec.Type.Short:
4611 switch (p.BuiltinType) {
4612 case BuiltinTypeSpec.Type.UShort:
4613 case BuiltinTypeSpec.Type.UInt:
4614 case BuiltinTypeSpec.Type.ULong:
4618 case BuiltinTypeSpec.Type.Dynamic:
4619 // Dynamic is never better
4623 // FIXME: handle lifted operators
4625 // TODO: this is expensive
4626 Expression p_tmp = new EmptyExpression (p);
4627 Expression q_tmp = new EmptyExpression (q);
4629 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4630 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4632 if (p_to_q && !q_to_p)
4635 if (q_to_p && !p_to_q)
4642 /// Determines "Better function" between candidate
4643 /// and the current best match
4646 /// Returns a boolean indicating :
4647 /// false if candidate ain't better
4648 /// true if candidate is better than the current best match
4650 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4651 MemberSpec best, AParametersCollection bparam, bool best_params)
4653 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4654 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4656 bool better_at_least_one = false;
4657 bool are_equivalent = true;
4658 int args_count = args == null ? 0 : args.Count;
4662 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4665 // Default arguments are ignored for better decision
4666 if (a.IsDefaultArgument)
4670 // When comparing named argument the parameter type index has to be looked up
4671 // in original parameter set (override version for virtual members)
4673 NamedArgument na = a as NamedArgument;
4675 int idx = cparam.GetParameterIndexByName (na.Name);
4676 ct = candidate_pd.Types[idx];
4677 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4678 ct = TypeManager.GetElementType (ct);
4680 idx = bparam.GetParameterIndexByName (na.Name);
4681 bt = best_pd.Types[idx];
4682 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4683 bt = TypeManager.GetElementType (bt);
4685 ct = candidate_pd.Types[c_idx];
4686 bt = best_pd.Types[b_idx];
4688 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4689 ct = TypeManager.GetElementType (ct);
4693 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4694 bt = TypeManager.GetElementType (bt);
4699 if (TypeSpecComparer.IsEqual (ct, bt))
4702 are_equivalent = false;
4703 int result = BetterExpressionConversion (ec, a, ct, bt);
4705 // for each argument, the conversion to 'ct' should be no worse than
4706 // the conversion to 'bt'.
4709 // No optional parameters tie breaking rules for delegates overload resolution
4711 if ((this.restrictions & Restrictions.CovariantDelegate) != 0)
4714 better_at_least_one = false;
4717 while (j < args_count && !args [j++].IsDefaultArgument) ;
4722 // for at least one argument, the conversion to 'ct' should be better than
4723 // the conversion to 'bt'.
4725 better_at_least_one = true;
4728 if (better_at_least_one)
4732 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4734 if (!are_equivalent) {
4736 // A candidate with no default parameters is still better when there
4737 // is no better expression conversion
4739 if (candidate_pd.Count < best_pd.Count) {
4740 if (!candidate_params && !candidate_pd.FixedParameters [j - j].HasDefaultValue) {
4743 } else if (candidate_pd.Count == best_pd.Count) {
4744 if (candidate_params)
4747 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4750 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4758 // If candidate is applicable in its normal form and best has a params array and is applicable
4759 // only in its expanded form, then candidate is better
4761 if (candidate_params != best_params)
4762 return !candidate_params;
4765 // We have not reached end of parameters list due to params or used default parameters
4767 bool defaults_ambiguity = false;
4768 while (j < candidate_pd.Count && j < best_pd.Count) {
4769 var cand_param = candidate_pd.FixedParameters [j];
4770 var best_param = best_pd.FixedParameters [j];
4772 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4773 return cand_param.HasDefaultValue;
4775 defaults_ambiguity = true;
4776 if (candidate_pd.Count == best_pd.Count) {
4780 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4781 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4783 if (cand_param.HasDefaultValue) {
4792 // Neither is better when not all arguments are provided
4794 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4795 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4796 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4801 if (candidate_pd.Count != best_pd.Count) {
4802 if (defaults_ambiguity && best_pd.Count - 1 == j)
4803 return best_pd.HasParams;
4805 return candidate_pd.Count < best_pd.Count;
4809 // One is a non-generic method and second is a generic method, then non-generic is better
4811 if (best.IsGeneric != candidate.IsGeneric)
4812 return best.IsGeneric;
4815 // Both methods have the same number of parameters, and the parameters have equal types
4816 // Pick the "more specific" signature using rules over original (non-inflated) types
4818 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4819 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4821 bool specific_at_least_once = false;
4822 for (j = 0; j < args_count; ++j) {
4823 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4825 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4826 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4828 ct = candidate_def_pd.Types[j];
4829 bt = best_def_pd.Types[j];
4834 TypeSpec specific = MoreSpecific (ct, bt);
4838 specific_at_least_once = true;
4841 if (specific_at_least_once)
4847 static bool CheckInflatedArguments (MethodSpec ms)
4849 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4852 // Setup constraint checker for probing only
4853 ConstraintChecker cc = new ConstraintChecker (null);
4855 var mp = ms.Parameters.Types;
4856 for (int i = 0; i < mp.Length; ++i) {
4857 var type = mp[i] as InflatedTypeSpec;
4861 var targs = type.TypeArguments;
4862 if (targs.Length == 0)
4865 // TODO: Checking inflated MVAR arguments should be enough
4866 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4873 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4875 rc.Report.Error (1729, loc,
4876 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4877 type.GetSignatureForError (), argCount.ToString ());
4881 // Determines if the candidate method is applicable to the given set of arguments
4882 // There could be two different set of parameters for same candidate where one
4883 // is the closest override for default values and named arguments checks and second
4884 // one being the virtual base for the parameter types and modifiers.
4886 // A return value rates candidate method compatibility,
4888 // 0 = the best, int.MaxValue = the worst
4890 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)
4893 // Each step has allocated 10 values, it can overflow for
4894 // more than 10 arguments but that's ok as it's used for
4895 // better error reporting only
4897 const int ArgumentCountMismatch = 1000000000;
4898 const int NamedArgumentsMismatch = 100000000;
4899 const int DefaultArgumentMismatch = 10000000;
4900 const int UnexpectedTypeArguments = 1000000;
4901 const int TypeArgumentsMismatch = 100000;
4902 const int InflatedTypesMismatch = 10000;
4904 // Parameters of most-derived type used mainly for named and optional parameters
4905 var pd = pm.Parameters;
4907 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4908 // params modifier instead of most-derived type
4909 var cpd = ((IParametersMember) candidate).Parameters;
4910 int param_count = pd.Count;
4911 int optional_count = 0;
4913 Arguments orig_args = arguments;
4915 if (arg_count != param_count) {
4917 // No arguments expansion when doing exact match for delegates
4919 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4920 for (int i = 0; i < pd.Count; ++i) {
4921 if (pd.FixedParameters[i].HasDefaultValue) {
4922 optional_count = pd.Count - i;
4928 if (optional_count != 0) {
4929 // Readjust expected number when params used
4930 if (cpd.HasParams) {
4932 if (arg_count < param_count)
4934 } else if (arg_count > param_count) {
4935 int args_gap = System.Math.Abs (arg_count - param_count);
4936 return ArgumentCountMismatch + args_gap;
4937 } else if (arg_count < param_count - optional_count) {
4938 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4939 return ArgumentCountMismatch + args_gap;
4941 } else if (arg_count != param_count) {
4942 int args_gap = System.Math.Abs (arg_count - param_count);
4944 return ArgumentCountMismatch + args_gap;
4945 if (arg_count < param_count - 1)
4946 return ArgumentCountMismatch + args_gap;
4949 // Resize to fit optional arguments
4950 if (optional_count != 0) {
4951 if (arguments == null) {
4952 arguments = new Arguments (optional_count);
4954 // Have to create a new container, so the next run can do same
4955 var resized = new Arguments (param_count);
4956 resized.AddRange (arguments);
4957 arguments = resized;
4960 for (int i = arg_count; i < param_count; ++i)
4961 arguments.Add (null);
4965 if (arg_count > 0) {
4967 // Shuffle named arguments to the right positions if there are any
4969 if (arguments[arg_count - 1] is NamedArgument) {
4970 arg_count = arguments.Count;
4972 for (int i = 0; i < arg_count; ++i) {
4973 bool arg_moved = false;
4975 NamedArgument na = arguments[i] as NamedArgument;
4979 int index = pd.GetParameterIndexByName (na.Name);
4981 // Named parameter not found
4983 return NamedArgumentsMismatch - i;
4985 // already reordered
4990 if (index >= param_count) {
4991 // When using parameters which should not be available to the user
4992 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4995 arguments.Add (null);
4999 if (index == arg_count)
5000 return NamedArgumentsMismatch - i - 1;
5002 temp = arguments [index];
5004 // The slot has been taken by positional argument
5005 if (temp != null && !(temp is NamedArgument))
5010 arguments = arguments.MarkOrderedArgument (na);
5014 if (arguments == orig_args) {
5015 arguments = new Arguments (orig_args.Count);
5016 arguments.AddRange (orig_args);
5019 arguments[index] = arguments[i];
5020 arguments[i] = temp;
5027 arg_count = arguments.Count;
5029 } else if (arguments != null) {
5030 arg_count = arguments.Count;
5034 // Don't do any expensive checks when the candidate cannot succeed
5036 if (arg_count != param_count && !cpd.HasParams)
5037 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5039 var dep = candidate.GetMissingDependencies ();
5041 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5046 // 1. Handle generic method using type arguments when specified or type inference
5049 var ms = candidate as MethodSpec;
5050 if (ms != null && ms.IsGeneric) {
5051 if (type_arguments != null) {
5052 var g_args_count = ms.Arity;
5053 if (g_args_count != type_arguments.Count)
5054 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5056 if (type_arguments.Arguments != null)
5057 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5060 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5061 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5062 // candidate was found use the set to report more details about what was wrong with lambda body.
5063 // The general idea is to distinguish between code errors and errors caused by
5064 // trial-and-error type inference
5066 if (lambda_conv_msgs == null) {
5067 for (int i = 0; i < arg_count; i++) {
5068 Argument a = arguments[i];
5072 var am = a.Expr as AnonymousMethodExpression;
5074 if (lambda_conv_msgs == null)
5075 lambda_conv_msgs = new SessionReportPrinter ();
5077 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5082 var ti = new TypeInference (arguments);
5083 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5086 return TypeArgumentsMismatch - ti.InferenceScore;
5089 // Clear any error messages when the result was success
5091 if (lambda_conv_msgs != null)
5092 lambda_conv_msgs.ClearSession ();
5094 if (i_args.Length != 0) {
5096 for (int i = 0; i < i_args.Length; ++i) {
5097 var ta = i_args [i];
5098 if (!ta.IsAccessible (ec))
5099 return TypeArgumentsMismatch - i;
5103 ms = ms.MakeGenericMethod (ec, i_args);
5108 // Type arguments constraints have to match for the method to be applicable
5110 if (!CheckInflatedArguments (ms)) {
5112 return InflatedTypesMismatch;
5116 // We have a generic return type and at same time the method is override which
5117 // means we have to also inflate override return type in case the candidate is
5118 // best candidate and override return type is different to base return type.
5120 // virtual Foo<T, object> with override Foo<T, dynamic>
5122 if (candidate != pm) {
5123 MethodSpec override_ms = (MethodSpec) pm;
5124 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5125 returnType = inflator.Inflate (returnType);
5127 returnType = ms.ReturnType;
5134 if (type_arguments != null)
5135 return UnexpectedTypeArguments;
5141 // 2. Each argument has to be implicitly convertible to method parameter
5143 Parameter.Modifier p_mod = 0;
5146 for (int i = 0; i < arg_count; i++) {
5147 Argument a = arguments[i];
5149 var fp = pd.FixedParameters[i];
5150 if (!fp.HasDefaultValue) {
5151 arguments = orig_args;
5152 return arg_count * 2 + 2;
5156 // Get the default value expression, we can use the same expression
5157 // if the type matches
5159 Expression e = fp.DefaultValue;
5161 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5163 // Restore for possible error reporting
5164 for (int ii = i; ii < arg_count; ++ii)
5165 arguments.RemoveAt (i);
5167 return (arg_count - i) * 2 + 1;
5171 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5173 // LAMESPEC: Attributes can be mixed together with build-in priority
5175 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5176 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5177 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5178 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5179 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5180 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5184 arguments[i] = new Argument (e, Argument.AType.Default);
5188 if (p_mod != Parameter.Modifier.PARAMS) {
5189 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5191 } else if (!params_expanded_form) {
5192 params_expanded_form = true;
5193 pt = ((ElementTypeSpec) pt).Element;
5199 if (!params_expanded_form) {
5200 if (a.IsExtensionType) {
5201 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5206 score = IsArgumentCompatible (ec, a, p_mod, pt);
5209 dynamicArgument = true;
5214 // It can be applicable in expanded form (when not doing exact match like for delegates)
5216 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5217 if (!params_expanded_form) {
5218 pt = ((ElementTypeSpec) pt).Element;
5222 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5225 params_expanded_form = true;
5226 dynamicArgument = true;
5227 } else if (score == 0 || arg_count > pd.Count) {
5228 params_expanded_form = true;
5233 if (params_expanded_form)
5235 return (arg_count - i) * 2 + score;
5240 // Restore original arguments for dynamic binder to keep the intention of original source code
5242 if (dynamicArgument)
5243 arguments = orig_args;
5248 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5250 if (e is Constant && e.Type == ptype)
5254 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5256 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5257 e = new MemberAccess (new MemberAccess (new MemberAccess (
5258 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5259 } else if (e is Constant) {
5261 // Handles int to int? conversions, DefaultParameterValue check
5263 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5267 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5270 return e.Resolve (ec);
5274 // Tests argument compatibility with the parameter
5275 // The possible return values are
5277 // 1 - modifier mismatch
5278 // 2 - type mismatch
5279 // -1 - dynamic binding required
5281 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5284 // Types have to be identical when ref or out modifer
5285 // is used and argument is not of dynamic type
5287 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5288 var arg_type = argument.Type;
5290 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5292 // Using dynamic for ref/out parameter can still succeed at runtime
5294 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5300 if (arg_type != parameter) {
5301 if (arg_type == InternalType.VarOutType)
5305 // Do full equality check after quick path
5307 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5309 // Using dynamic for ref/out parameter can still succeed at runtime
5311 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5319 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5323 // Use implicit conversion in all modes to return same candidates when the expression
5324 // is used as argument or delegate conversion
5326 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5327 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5334 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5336 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5338 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5341 var ac_p = p as ArrayContainer;
5343 var ac_q = q as ArrayContainer;
5347 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5348 if (specific == ac_p.Element)
5350 if (specific == ac_q.Element)
5352 } else if (p.IsGeneric && q.IsGeneric) {
5353 var pargs = TypeManager.GetTypeArguments (p);
5354 var qargs = TypeManager.GetTypeArguments (q);
5356 bool p_specific_at_least_once = false;
5357 bool q_specific_at_least_once = false;
5359 for (int i = 0; i < pargs.Length; i++) {
5360 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5361 if (specific == pargs[i])
5362 p_specific_at_least_once = true;
5363 if (specific == qargs[i])
5364 q_specific_at_least_once = true;
5367 if (p_specific_at_least_once && !q_specific_at_least_once)
5369 if (!p_specific_at_least_once && q_specific_at_least_once)
5377 // Find the best method from candidate list
5379 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5381 List<AmbiguousCandidate> ambiguous_candidates = null;
5383 MemberSpec best_candidate;
5384 Arguments best_candidate_args = null;
5385 bool best_candidate_params = false;
5386 bool best_candidate_dynamic = false;
5387 int best_candidate_rate;
5388 IParametersMember best_parameter_member = null;
5390 int args_count = args != null ? args.Count : 0;
5392 Arguments candidate_args = args;
5393 bool error_mode = false;
5394 MemberSpec invocable_member = null;
5395 int applicable_candidates = 0;
5398 best_candidate = null;
5399 best_candidate_rate = int.MaxValue;
5401 var type_members = members;
5403 for (int i = 0; i < type_members.Count; ++i) {
5404 var member = type_members[i];
5407 // Methods in a base class are not candidates if any method in a derived
5408 // class is applicable
5410 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5414 if (!member.IsAccessible (rc))
5417 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5420 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5421 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5426 IParametersMember pm = member as IParametersMember;
5429 // Will use it later to report ambiguity between best method and invocable member
5431 if (Invocation.IsMemberInvocable (member))
5432 invocable_member = member;
5438 // Overload resolution is looking for base member but using parameter names
5439 // and default values from the closest member. That means to do expensive lookup
5440 // for the closest override for virtual or abstract members
5442 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5443 var override_params = base_provider.GetOverrideMemberParameters (member);
5444 if (override_params != null)
5445 pm = override_params;
5449 // Check if the member candidate is applicable
5451 bool params_expanded_form = false;
5452 bool dynamic_argument = false;
5453 TypeSpec rt = pm.MemberType;
5454 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5456 if (lambda_conv_msgs != null)
5457 lambda_conv_msgs.EndSession ();
5460 // How does it score compare to others
5462 if (candidate_rate < best_candidate_rate) {
5464 // Fatal error (missing dependency), cannot continue
5465 if (candidate_rate < 0)
5468 applicable_candidates = 1;
5469 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5470 // Only parameterless methods are considered
5472 best_candidate_rate = candidate_rate;
5473 best_candidate = member;
5474 best_candidate_args = candidate_args;
5475 best_candidate_params = params_expanded_form;
5476 best_candidate_dynamic = dynamic_argument;
5477 best_parameter_member = pm;
5478 best_candidate_return_type = rt;
5480 } else if (candidate_rate == 0) {
5482 // The member look is done per type for most operations but sometimes
5483 // it's not possible like for binary operators overload because they
5484 // are unioned between 2 sides
5486 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5487 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5491 ++applicable_candidates;
5493 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5495 // We pack all interface members into top level type which makes the overload resolution
5496 // more complicated for interfaces. We compensate it by removing methods with same
5497 // signature when building the cache hence this path should not really be hit often
5500 // interface IA { void Foo (int arg); }
5501 // interface IB : IA { void Foo (params int[] args); }
5503 // IB::Foo is the best overload when calling IB.Foo (1)
5506 if (ambiguous_candidates != null) {
5507 foreach (var amb_cand in ambiguous_candidates) {
5508 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5517 ambiguous_candidates = null;
5520 // Is the new candidate better
5521 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5525 best_candidate = member;
5526 best_candidate_args = candidate_args;
5527 best_candidate_params = params_expanded_form;
5528 best_candidate_dynamic = dynamic_argument;
5529 best_parameter_member = pm;
5530 best_candidate_return_type = rt;
5532 // It's not better but any other found later could be but we are not sure yet
5533 if (ambiguous_candidates == null)
5534 ambiguous_candidates = new List<AmbiguousCandidate> ();
5536 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5540 // Restore expanded arguments
5541 candidate_args = args;
5543 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5546 // We've found exact match
5548 if (best_candidate_rate == 0)
5552 // Try extension methods lookup when no ordinary method match was found and provider enables it
5555 var emg = base_provider.LookupExtensionMethod (rc);
5557 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5559 best_candidate_extension_group = emg;
5560 return (T) (MemberSpec) emg.BestCandidate;
5565 // Don't run expensive error reporting mode for probing
5572 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5575 lambda_conv_msgs = null;
5580 // No best member match found, report an error
5582 if (best_candidate_rate != 0 || error_mode) {
5583 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5587 if (best_candidate_dynamic) {
5588 if (args[0].IsExtensionType) {
5589 rc.Report.Error (1973, loc,
5590 "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",
5591 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5595 // Check type constraints only when explicit type arguments are used
5597 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5598 MethodSpec bc = best_candidate as MethodSpec;
5599 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5600 ConstraintChecker cc = new ConstraintChecker (rc);
5601 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5605 BestCandidateIsDynamic = true;
5610 // These flags indicates we are running delegate probing conversion. No need to
5611 // do more expensive checks
5613 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5614 return (T) best_candidate;
5616 if (ambiguous_candidates != null) {
5618 // Now check that there are no ambiguities i.e the selected method
5619 // should be better than all the others
5621 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5622 var candidate = ambiguous_candidates [ix];
5624 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5625 var ambiguous = candidate.Member;
5626 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5627 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5628 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5629 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5630 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5633 return (T) best_candidate;
5638 if (invocable_member != null && !IsProbingOnly) {
5639 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5640 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5641 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5642 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5646 // And now check if the arguments are all
5647 // compatible, perform conversions if
5648 // necessary etc. and return if everything is
5651 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5654 if (best_candidate == null)
5658 // Don't run possibly expensive checks in probing mode
5660 if (!IsProbingOnly && !rc.IsInProbingMode) {
5662 // Check ObsoleteAttribute on the best method
5664 best_candidate.CheckObsoleteness (rc, loc);
5666 best_candidate.MemberDefinition.SetIsUsed ();
5669 args = best_candidate_args;
5670 return (T) best_candidate;
5673 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5675 return ResolveMember<MethodSpec> (rc, ref args);
5678 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5679 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5681 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5684 if (a.Type == InternalType.ErrorType)
5687 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5688 ec.Report.SymbolRelatedToPreviousError (method);
5689 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5690 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5691 TypeManager.CSharpSignature (method));
5694 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5695 TypeManager.CSharpSignature (method));
5696 } else if (IsDelegateInvoke) {
5697 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5698 DelegateType.GetSignatureForError ());
5700 ec.Report.SymbolRelatedToPreviousError (method);
5701 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5702 method.GetSignatureForError ());
5705 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5707 string index = (idx + 1).ToString ();
5708 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5709 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5710 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5711 index, Parameter.GetModifierSignature (a.Modifier));
5713 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5714 index, Parameter.GetModifierSignature (mod));
5716 string p1 = a.GetSignatureForError ();
5717 string p2 = paramType.GetSignatureForError ();
5720 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5721 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5724 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5725 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5726 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5729 ec.Report.Error (1503, a.Expr.Location,
5730 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5735 // We have failed to find exact match so we return error info about the closest match
5737 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5739 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5740 int arg_count = args == null ? 0 : args.Count;
5742 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5743 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5744 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5748 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5753 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5754 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5755 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5759 // For candidates which match on parameters count report more details about incorrect arguments
5762 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5763 // Reject any inaccessible member
5764 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5765 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5766 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5770 var ms = best_candidate as MethodSpec;
5771 if (ms != null && ms.IsGeneric) {
5772 bool constr_ok = true;
5773 if (ms.TypeArguments != null)
5774 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5776 if (ta_count == 0 && ms.TypeArguments == null) {
5777 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5781 rc.Report.Error (411, loc,
5782 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5783 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5790 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5796 // We failed to find any method with correct argument count, report best candidate
5798 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5801 if (best_candidate.Kind == MemberKind.Constructor) {
5802 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5803 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5804 } else if (IsDelegateInvoke) {
5805 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5806 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5807 DelegateType.GetSignatureForError (), arg_count.ToString ());
5809 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5810 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5811 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5812 name, arg_count.ToString ());
5816 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5818 var p = ((IParametersMember)best_candidate).Parameters;
5823 for (int i = p.Count - 1; i != 0; --i) {
5824 var fp = p.FixedParameters [i];
5825 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5835 foreach (var arg in args) {
5836 var na = arg as NamedArgument;
5840 if (na.Name == name) {
5849 return args.Count + 1 == pm.Parameters.Count;
5852 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5854 var pd = pm.Parameters;
5855 var cpd = ((IParametersMember) member).Parameters;
5856 var ptypes = cpd.Types;
5858 Parameter.Modifier p_mod = 0;
5860 int a_idx = 0, a_pos = 0;
5862 ArrayInitializer params_initializers = null;
5863 bool has_unsafe_arg = pm.MemberType.IsPointer;
5864 int arg_count = args == null ? 0 : args.Count;
5866 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5871 if (p_mod != Parameter.Modifier.PARAMS) {
5872 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5874 has_unsafe_arg |= pt.IsPointer;
5876 if (p_mod == Parameter.Modifier.PARAMS) {
5877 if (chose_params_expanded) {
5878 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5879 pt = TypeManager.GetElementType (pt);
5885 // Types have to be identical when ref or out modifer is used
5887 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5888 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5891 var arg_type = a.Type;
5895 if (arg_type == InternalType.VarOutType) {
5897 // Set underlying variable type based on parameter type
5899 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5903 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5907 NamedArgument na = a as NamedArgument;
5909 int name_index = pd.GetParameterIndexByName (na.Name);
5910 if (name_index < 0 || name_index >= pd.Count) {
5911 if (IsDelegateInvoke) {
5912 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5913 ec.Report.Error (1746, na.Location,
5914 "The delegate `{0}' does not contain a parameter named `{1}'",
5915 DelegateType.GetSignatureForError (), na.Name);
5917 ec.Report.SymbolRelatedToPreviousError (member);
5918 ec.Report.Error (1739, na.Location,
5919 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5920 TypeManager.CSharpSignature (member), na.Name);
5922 } else if (args[name_index] != a && args[name_index] != null) {
5923 if (IsDelegateInvoke)
5924 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5926 ec.Report.SymbolRelatedToPreviousError (member);
5928 ec.Report.Error (1744, na.Location,
5929 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5934 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5937 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5938 if (a.IsExtensionType) {
5939 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5940 // CS1061 but that still better than confusing CS0123
5941 var ma = new MemberAccess (a.Expr, member.Name, loc);
5942 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5944 custom_errors.NoArgumentMatch (ec, member);
5950 if (a.IsExtensionType) {
5951 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5954 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5956 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5959 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5966 // Convert params arguments to an array initializer
5968 if (params_initializers != null) {
5969 // we choose to use 'a.Expr' rather than 'conv' so that
5970 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5971 params_initializers.Add (a.Expr);
5972 args.RemoveAt (a_idx--);
5978 // Update the argument with the implicit conversion
5982 if (a_idx != arg_count) {
5984 // Convert all var out argument to error type for less confusing error reporting
5985 // when no matching overload is found
5987 for (; a_idx < arg_count; a_idx++) {
5988 var arg = args [a_idx];
5992 if (arg.Type == InternalType.VarOutType) {
5993 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5997 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6002 // Fill not provided arguments required by params modifier
6004 if (params_initializers == null && arg_count + 1 == pd.Count) {
6006 args = new Arguments (1);
6008 pt = ptypes[pd.Count - 1];
6009 pt = TypeManager.GetElementType (pt);
6010 has_unsafe_arg |= pt.IsPointer;
6011 params_initializers = new ArrayInitializer (0, loc);
6015 // Append an array argument with all params arguments
6017 if (params_initializers != null) {
6018 args.Add (new Argument (
6019 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6023 if (has_unsafe_arg && !ec.IsUnsafe) {
6024 Expression.UnsafeError (ec, loc);
6028 // We could infer inaccesible type arguments
6030 if (type_arguments == null && member.IsGeneric) {
6031 var ms = (MethodSpec) member;
6032 foreach (var ta in ms.TypeArguments) {
6033 if (!ta.IsAccessible (ec)) {
6034 ec.Report.SymbolRelatedToPreviousError (ta);
6035 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6045 public class ConstantExpr : MemberExpr
6047 readonly ConstSpec constant;
6049 public ConstantExpr (ConstSpec constant, Location loc)
6051 this.constant = constant;
6055 public override string Name {
6056 get { throw new NotImplementedException (); }
6059 public override string KindName {
6060 get { return "constant"; }
6063 public override bool IsInstance {
6064 get { return !IsStatic; }
6067 public override bool IsStatic {
6068 get { return true; }
6071 protected override TypeSpec DeclaringType {
6072 get { return constant.DeclaringType; }
6075 public override Expression CreateExpressionTree (ResolveContext ec)
6077 throw new NotSupportedException ("ET");
6080 protected override Expression DoResolve (ResolveContext rc)
6082 ResolveInstanceExpression (rc, null);
6083 DoBestMemberChecks (rc, constant);
6085 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6086 eclass = ExprClass.Value;
6087 type = constant.MemberType;
6091 var c = constant.GetConstant (rc);
6093 // Creates reference expression to the constant value
6094 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6097 public override void Emit (EmitContext ec)
6099 throw new NotSupportedException ();
6102 public override string GetSignatureForError ()
6104 return constant.GetSignatureForError ();
6107 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6109 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6114 // Fully resolved expression that references a Field
6116 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6118 protected FieldSpec spec;
6119 VariableInfo variable_info;
6121 LocalTemporary temp;
6124 protected FieldExpr (Location l)
6129 public FieldExpr (FieldSpec spec, Location loc)
6134 type = spec.MemberType;
6137 public FieldExpr (FieldBase fi, Location l)
6144 public override string Name {
6150 public bool IsHoisted {
6152 IVariableReference hv = InstanceExpression as IVariableReference;
6153 return hv != null && hv.IsHoisted;
6157 public override bool IsInstance {
6159 return !spec.IsStatic;
6163 public override bool IsStatic {
6165 return spec.IsStatic;
6169 public override string KindName {
6170 get { return "field"; }
6173 public FieldSpec Spec {
6179 protected override TypeSpec DeclaringType {
6181 return spec.DeclaringType;
6185 public VariableInfo VariableInfo {
6187 return variable_info;
6193 public override string GetSignatureForError ()
6195 return spec.GetSignatureForError ();
6198 public bool IsMarshalByRefAccess (ResolveContext rc)
6200 // Checks possible ldflda of field access expression
6201 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6202 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6203 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6206 public void SetHasAddressTaken ()
6208 IVariableReference vr = InstanceExpression as IVariableReference;
6210 vr.SetHasAddressTaken ();
6214 protected override void CloneTo (CloneContext clonectx, Expression target)
6216 var t = (FieldExpr) target;
6218 if (InstanceExpression != null)
6219 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6222 public override Expression CreateExpressionTree (ResolveContext ec)
6224 if (ConditionalAccess) {
6225 Error_NullShortCircuitInsideExpressionTree (ec);
6228 return CreateExpressionTree (ec, true);
6231 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6234 Expression instance;
6236 if (InstanceExpression == null) {
6237 instance = new NullLiteral (loc);
6238 } else if (convertInstance) {
6239 instance = InstanceExpression.CreateExpressionTree (ec);
6241 args = new Arguments (1);
6242 args.Add (new Argument (InstanceExpression));
6243 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6246 args = Arguments.CreateForExpressionTree (ec, null,
6248 CreateTypeOfExpression ());
6250 return CreateExpressionFactoryCall (ec, "Field", args);
6253 public Expression CreateTypeOfExpression ()
6255 return new TypeOfField (spec, loc);
6258 protected override Expression DoResolve (ResolveContext ec)
6260 spec.MemberDefinition.SetIsUsed ();
6262 return DoResolve (ec, null);
6265 Expression DoResolve (ResolveContext ec, Expression rhs)
6267 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6270 ResolveConditionalAccessReceiver (ec);
6272 if (ResolveInstanceExpression (ec, rhs)) {
6273 // Resolve the field's instance expression while flow analysis is turned
6274 // off: when accessing a field "a.b", we must check whether the field
6275 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6277 if (lvalue_instance) {
6278 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6280 Expression right_side =
6281 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6283 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6285 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6288 if (InstanceExpression == null)
6292 DoBestMemberChecks (ec, spec);
6294 if (conditional_access_receiver)
6295 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6298 var fb = spec as FixedFieldSpec;
6299 IVariableReference var = InstanceExpression as IVariableReference;
6302 IFixedExpression fe = InstanceExpression as IFixedExpression;
6303 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6304 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6307 if (InstanceExpression.eclass != ExprClass.Variable) {
6308 ec.Report.SymbolRelatedToPreviousError (spec);
6309 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6310 TypeManager.GetFullNameSignature (spec));
6311 } else if (var != null && var.IsHoisted) {
6312 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6315 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6319 // Set flow-analysis variable info for struct member access. It will be check later
6320 // for precise error reporting
6322 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6323 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6326 if (conditional_access_receiver)
6327 type = LiftMemberType (ec, type);
6329 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6330 return Constant.CreateConstantFromValue (type, null, loc);
6332 eclass = ExprClass.Variable;
6336 public void SetFieldAssigned (FlowAnalysisContext fc)
6341 bool lvalue_instance = spec.DeclaringType.IsStruct;
6342 if (lvalue_instance) {
6343 var var = InstanceExpression as IVariableReference;
6344 if (var != null && var.VariableInfo != null) {
6345 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6349 var fe = InstanceExpression as FieldExpr;
6351 Expression instance;
6354 instance = fe.InstanceExpression;
6355 var fe_instance = instance as FieldExpr;
6356 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6357 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6358 var var = InstanceExpression as IVariableReference;
6359 if (var != null && var.VariableInfo == null) {
6360 var var_inst = instance as IVariableReference;
6361 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6362 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6366 if (fe_instance != null) {
6375 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6376 instance.FlowAnalysis (fc);
6378 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6379 InstanceExpression.FlowAnalysis (fc);
6383 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6385 // The return value is always null. Returning a value simplifies calling code.
6387 if (right_side == EmptyExpression.OutAccess) {
6389 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6390 GetSignatureForError ());
6392 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6393 GetSignatureForError ());
6399 if (right_side == EmptyExpression.LValueMemberAccess) {
6400 // Already reported as CS1648/CS1650
6404 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6406 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6407 GetSignatureForError ());
6409 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6410 GetSignatureForError ());
6416 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6417 GetSignatureForError ());
6419 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6420 GetSignatureForError ());
6426 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6428 if (HasConditionalAccess ())
6429 Error_NullPropagatingLValue (ec);
6431 if (spec is FixedFieldSpec) {
6432 // It could be much better error message but we want to be error compatible
6433 Error_ValueAssignment (ec, right_side);
6436 Expression e = DoResolve (ec, right_side);
6441 spec.MemberDefinition.SetIsAssigned ();
6443 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6444 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6445 ec.Report.Warning (420, 1, loc,
6446 "`{0}': A volatile field references will not be treated as volatile",
6447 spec.GetSignatureForError ());
6450 if (spec.IsReadOnly) {
6451 // InitOnly fields can only be assigned in constructors or initializers
6452 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6453 return Error_AssignToReadonly (ec, right_side);
6455 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6457 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6458 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6459 return Error_AssignToReadonly (ec, right_side);
6460 // static InitOnly fields cannot be assigned-to in an instance constructor
6461 if (IsStatic && !ec.IsStatic)
6462 return Error_AssignToReadonly (ec, right_side);
6463 // instance constructors can't modify InitOnly fields of other instances of the same type
6464 if (!IsStatic && !(InstanceExpression is This))
6465 return Error_AssignToReadonly (ec, right_side);
6469 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6470 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6471 ec.Report.Warning (197, 1, loc,
6472 "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",
6473 GetSignatureForError ());
6476 eclass = ExprClass.Variable;
6480 public override void FlowAnalysis (FlowAnalysisContext fc)
6482 var var = InstanceExpression as IVariableReference;
6484 var vi = var.VariableInfo;
6485 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6486 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6490 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6491 var le = SkipLeftValueTypeAccess (InstanceExpression);
6493 le.FlowAnalysis (fc);
6499 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6501 base.FlowAnalysis (fc);
6503 if (conditional_access_receiver)
6504 fc.DefiniteAssignment = da;
6507 static Expression SkipLeftValueTypeAccess (Expression expr)
6509 if (!TypeSpec.IsValueType (expr.Type))
6512 if (expr is VariableReference)
6515 var fe = expr as FieldExpr;
6519 if (fe.InstanceExpression == null)
6522 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6525 public override int GetHashCode ()
6527 return spec.GetHashCode ();
6530 public bool IsFixed {
6533 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6535 IVariableReference variable = InstanceExpression as IVariableReference;
6536 if (variable != null)
6537 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6539 IFixedExpression fe = InstanceExpression as IFixedExpression;
6540 return fe != null && fe.IsFixed;
6544 public override bool Equals (object obj)
6546 FieldExpr fe = obj as FieldExpr;
6550 if (spec != fe.spec)
6553 if (InstanceExpression == null || fe.InstanceExpression == null)
6556 return InstanceExpression.Equals (fe.InstanceExpression);
6559 public void Emit (EmitContext ec, bool leave_copy)
6561 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6565 ec.Emit (OpCodes.Volatile);
6567 ec.Emit (OpCodes.Ldsfld, spec);
6569 var ca = ec.ConditionalAccess;
6572 if (conditional_access_receiver)
6573 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6575 EmitInstance (ec, false);
6578 // Optimization for build-in types
6579 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6580 ec.EmitLoadFromPtr (type);
6582 var ff = spec as FixedFieldSpec;
6584 ec.Emit (OpCodes.Ldflda, spec);
6585 ec.Emit (OpCodes.Ldflda, ff.Element);
6588 ec.Emit (OpCodes.Volatile);
6590 ec.Emit (OpCodes.Ldfld, spec);
6594 if (conditional_access_receiver) {
6595 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6596 ec.ConditionalAccess = ca;
6601 ec.Emit (OpCodes.Dup);
6603 temp = new LocalTemporary (this.Type);
6609 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6611 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6612 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6617 if (ConditionalAccess)
6618 throw new NotImplementedException ("null operator assignment");
6620 if (has_await_source)
6621 source = source.EmitToField (ec);
6623 EmitInstance (ec, prepared);
6628 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6629 ec.Emit (OpCodes.Dup);
6631 temp = new LocalTemporary (this.Type);
6636 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6637 ec.Emit (OpCodes.Volatile);
6639 spec.MemberDefinition.SetIsAssigned ();
6642 ec.Emit (OpCodes.Stsfld, spec);
6644 ec.Emit (OpCodes.Stfld, spec);
6646 if (ec.NotifyEvaluatorOnStore) {
6648 throw new NotImplementedException ("instance field write");
6651 ec.Emit (OpCodes.Dup);
6653 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6664 // Emits store to field with prepared values on stack
6666 public void EmitAssignFromStack (EmitContext ec)
6669 ec.Emit (OpCodes.Stsfld, spec);
6671 ec.Emit (OpCodes.Stfld, spec);
6675 public override void Emit (EmitContext ec)
6680 public override void EmitSideEffect (EmitContext ec)
6682 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6684 if (is_volatile) // || is_marshal_by_ref ())
6685 base.EmitSideEffect (ec);
6688 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6690 if ((mode & AddressOp.Store) != 0)
6691 spec.MemberDefinition.SetIsAssigned ();
6692 if ((mode & AddressOp.Load) != 0)
6693 spec.MemberDefinition.SetIsUsed ();
6696 // Handle initonly fields specially: make a copy and then
6697 // get the address of the copy.
6700 if (spec.IsReadOnly){
6702 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6714 var temp = ec.GetTemporaryLocal (type);
6715 ec.Emit (OpCodes.Stloc, temp);
6716 ec.Emit (OpCodes.Ldloca, temp);
6722 ec.Emit (OpCodes.Ldsflda, spec);
6725 EmitInstance (ec, false);
6726 ec.Emit (OpCodes.Ldflda, spec);
6730 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6732 return MakeExpression (ctx);
6735 public override SLE.Expression MakeExpression (BuilderContext ctx)
6738 return base.MakeExpression (ctx);
6740 return SLE.Expression.Field (
6741 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6742 spec.GetMetaInfo ());
6746 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6748 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6754 // Expression that evaluates to a Property.
6756 // This is not an LValue because we need to re-write the expression. We
6757 // can not take data from the stack and store it.
6759 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6761 Arguments arguments;
6762 FieldExpr backing_field;
6764 public PropertyExpr (PropertySpec spec, Location l)
6767 best_candidate = spec;
6768 type = spec.MemberType;
6773 protected override Arguments Arguments {
6782 protected override TypeSpec DeclaringType {
6784 return best_candidate.DeclaringType;
6788 public override string Name {
6790 return best_candidate.Name;
6794 public bool IsAutoPropertyAccess {
6796 var prop = best_candidate.MemberDefinition as Property;
6797 return prop != null && prop.BackingField != null;
6801 public override bool IsInstance {
6807 public override bool IsStatic {
6809 return best_candidate.IsStatic;
6813 public override string KindName {
6814 get { return "property"; }
6817 public PropertySpec PropertyInfo {
6819 return best_candidate;
6825 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6827 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6830 var args_count = arguments == null ? 0 : arguments.Count;
6831 if (args_count != body.Parameters.Count && args_count == 0)
6834 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6835 mg.InstanceExpression = InstanceExpression;
6840 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6842 return new PropertyExpr (spec, loc) {
6848 public override Expression CreateExpressionTree (ResolveContext ec)
6850 if (ConditionalAccess) {
6851 Error_NullShortCircuitInsideExpressionTree (ec);
6855 if (IsSingleDimensionalArrayLength ()) {
6856 args = new Arguments (1);
6857 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6858 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6861 args = new Arguments (2);
6862 if (InstanceExpression == null)
6863 args.Add (new Argument (new NullLiteral (loc)));
6865 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6866 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6867 return CreateExpressionFactoryCall (ec, "Property", args);
6870 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6872 DoResolveLValue (rc, null);
6873 return new TypeOfMethod (Setter, loc);
6876 public override string GetSignatureForError ()
6878 return best_candidate.GetSignatureForError ();
6881 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6884 return base.MakeExpression (ctx);
6886 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6890 public override SLE.Expression MakeExpression (BuilderContext ctx)
6893 return base.MakeExpression (ctx);
6895 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6899 void Error_PropertyNotValid (ResolveContext ec)
6901 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6902 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6903 GetSignatureForError ());
6906 bool IsSingleDimensionalArrayLength ()
6908 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6911 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6912 return ac != null && ac.Rank == 1;
6915 public override void Emit (EmitContext ec, bool leave_copy)
6918 // Special case: length of single dimension array property is turned into ldlen
6920 if (IsSingleDimensionalArrayLength ()) {
6921 if (conditional_access_receiver) {
6922 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6925 EmitInstance (ec, false);
6927 ec.Emit (OpCodes.Ldlen);
6928 ec.Emit (OpCodes.Conv_I4);
6930 if (conditional_access_receiver) {
6931 ec.CloseConditionalAccess (type);
6937 base.Emit (ec, leave_copy);
6940 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6942 if (backing_field != null) {
6943 backing_field.EmitAssign (ec, source, false, false);
6948 LocalTemporary await_source_arg = null;
6950 if (isCompound && !(source is DynamicExpressionStatement)) {
6951 emitting_compound_assignment = true;
6954 if (has_await_arguments) {
6955 await_source_arg = new LocalTemporary (Type);
6956 await_source_arg.Store (ec);
6958 args = new Arguments (1);
6959 args.Add (new Argument (await_source_arg));
6962 temp = await_source_arg;
6965 has_await_arguments = false;
6970 ec.Emit (OpCodes.Dup);
6971 temp = new LocalTemporary (this.Type);
6976 args = arguments ?? new Arguments (1);
6980 temp = new LocalTemporary (this.Type);
6982 args.Add (new Argument (temp));
6984 args.Add (new Argument (source));
6988 emitting_compound_assignment = false;
6990 var call = new CallEmitter ();
6991 call.InstanceExpression = InstanceExpression;
6993 call.InstanceExpressionOnStack = true;
6995 if (ConditionalAccess) {
6996 call.ConditionalAccess = true;
7000 call.Emit (ec, Setter, args, loc);
7002 call.EmitStatement (ec, Setter, args, loc);
7009 if (await_source_arg != null) {
7010 await_source_arg.Release (ec);
7014 public override void FlowAnalysis (FlowAnalysisContext fc)
7016 var prop = best_candidate.MemberDefinition as Property;
7017 if (prop != null && prop.BackingField != null) {
7018 var var = InstanceExpression as IVariableReference;
7020 var vi = var.VariableInfo;
7021 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7022 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7026 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7031 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7033 base.FlowAnalysis (fc);
7035 if (conditional_access_receiver)
7036 fc.DefiniteAssignment = da;
7039 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7041 eclass = ExprClass.PropertyAccess;
7043 if (best_candidate.IsNotCSharpCompatible) {
7044 Error_PropertyNotValid (rc);
7047 ResolveInstanceExpression (rc, right_side);
7049 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7050 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7051 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7053 type = p.MemberType;
7057 DoBestMemberChecks (rc, best_candidate);
7059 // Handling of com-imported properties with any number of default property parameters
7060 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7061 var p = best_candidate.Get.Parameters;
7062 arguments = new Arguments (p.Count);
7063 for (int i = 0; i < p.Count; ++i) {
7064 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7066 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7067 var p = best_candidate.Set.Parameters;
7068 arguments = new Arguments (p.Count - 1);
7069 for (int i = 0; i < p.Count - 1; ++i) {
7070 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7077 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7079 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7082 var prop = best_candidate.MemberDefinition as Property;
7083 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7084 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7088 prop = (Property)ps.MemberDefinition;
7091 var spec = prop.BackingField;
7095 if (rc.IsStatic != spec.IsStatic)
7098 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7101 backing_field = new FieldExpr (prop.BackingField, loc);
7102 backing_field.ResolveLValue (rc, rhs);
7106 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7108 if (backing_field != null) {
7109 backing_field.SetFieldAssigned (fc);
7113 if (!IsAutoPropertyAccess)
7116 var prop = best_candidate.MemberDefinition as Property;
7117 if (prop != null && prop.BackingField != null) {
7118 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7119 if (lvalue_instance) {
7120 var var = InstanceExpression as IVariableReference;
7121 if (var != null && var.VariableInfo != null) {
7122 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7128 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7130 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7134 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7136 // getter and setter can be different for base calls
7137 MethodSpec getter, setter;
7138 protected T best_candidate;
7140 protected LocalTemporary temp;
7141 protected bool emitting_compound_assignment;
7142 protected bool has_await_arguments;
7144 protected PropertyOrIndexerExpr (Location l)
7151 protected abstract Arguments Arguments { get; set; }
7153 public MethodSpec Getter {
7162 public MethodSpec Setter {
7173 protected override Expression DoResolve (ResolveContext ec)
7175 if (eclass == ExprClass.Unresolved) {
7176 ResolveConditionalAccessReceiver (ec);
7178 var expr = OverloadResolve (ec, null);
7183 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7184 return expr.Resolve (ec);
7187 if (conditional_access_receiver) {
7188 type = LiftMemberType (ec, type);
7192 if (!ResolveGetter (ec))
7198 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7200 if (HasConditionalAccess ())
7201 Error_NullPropagatingLValue (rc);
7203 if (right_side == EmptyExpression.OutAccess) {
7204 // TODO: best_candidate can be null at this point
7205 INamedBlockVariable variable = null;
7206 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7207 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7208 best_candidate.Name);
7210 right_side.DoResolveLValue (rc, this);
7215 if (eclass == ExprClass.Unresolved) {
7216 var expr = OverloadResolve (rc, right_side);
7221 return expr.ResolveLValue (rc, right_side);
7223 ResolveInstanceExpression (rc, right_side);
7226 if (!best_candidate.HasSet) {
7227 if (ResolveAutopropertyAssignment (rc, right_side))
7230 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7231 GetSignatureForError ());
7235 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7236 if (best_candidate.HasDifferentAccessibility) {
7237 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7238 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7239 GetSignatureForError ());
7241 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7242 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7246 if (best_candidate.HasDifferentAccessibility)
7247 CheckProtectedMemberAccess (rc, best_candidate.Set);
7249 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7253 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7255 var ca = ec.ConditionalAccess;
7256 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7258 call.Emit (ec, method, arguments, loc);
7260 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7261 ec.ConditionalAccess = ca;
7265 // Implements the IAssignMethod interface for assignments
7267 public virtual void Emit (EmitContext ec, bool leave_copy)
7269 var call = new CallEmitter ();
7270 call.ConditionalAccess = ConditionalAccess;
7271 call.InstanceExpression = InstanceExpression;
7272 if (has_await_arguments)
7273 call.HasAwaitArguments = true;
7275 call.DuplicateArguments = emitting_compound_assignment;
7277 if (conditional_access_receiver)
7278 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7280 call.Emit (ec, Getter, Arguments, loc);
7282 if (call.HasAwaitArguments) {
7283 InstanceExpression = call.InstanceExpression;
7284 Arguments = call.EmittedArguments;
7285 has_await_arguments = true;
7289 ec.Emit (OpCodes.Dup);
7290 temp = new LocalTemporary (Type);
7295 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7297 public override void Emit (EmitContext ec)
7302 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7304 has_await_arguments = true;
7309 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7311 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7313 bool ResolveGetter (ResolveContext rc)
7315 if (!best_candidate.HasGet) {
7316 if (InstanceExpression != EmptyExpression.Null) {
7317 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7318 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7319 best_candidate.GetSignatureForError ());
7322 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7323 if (best_candidate.HasDifferentAccessibility) {
7324 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7325 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7326 TypeManager.CSharpSignature (best_candidate));
7328 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7329 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7333 if (best_candidate.HasDifferentAccessibility) {
7334 CheckProtectedMemberAccess (rc, best_candidate.Get);
7337 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7341 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7348 /// Fully resolved expression that evaluates to an Event
7350 public class EventExpr : MemberExpr, IAssignMethod
7352 readonly EventSpec spec;
7355 public EventExpr (EventSpec spec, Location loc)
7363 protected override TypeSpec DeclaringType {
7365 return spec.DeclaringType;
7369 public override string Name {
7375 public override bool IsInstance {
7377 return !spec.IsStatic;
7381 public override bool IsStatic {
7383 return spec.IsStatic;
7387 public override string KindName {
7388 get { return "event"; }
7391 public MethodSpec Operator {
7399 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7402 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7404 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7405 if (spec.BackingField != null &&
7406 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7408 spec.MemberDefinition.SetIsUsed ();
7410 spec.CheckObsoleteness (ec, loc);
7412 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7413 Error_AssignmentEventOnly (ec);
7415 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7417 InstanceExpression = null;
7419 return ml.ResolveMemberAccess (ec, left, original);
7423 return base.ResolveMemberAccess (ec, left, original);
7426 public override Expression CreateExpressionTree (ResolveContext ec)
7428 throw new NotSupportedException ("ET");
7431 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7433 if (right_side == EmptyExpression.EventAddition) {
7434 op = spec.AccessorAdd;
7435 } else if (right_side == EmptyExpression.EventSubtraction) {
7436 op = spec.AccessorRemove;
7440 Error_AssignmentEventOnly (ec);
7444 if (HasConditionalAccess ())
7445 Error_NullPropagatingLValue (ec);
7447 op = CandidateToBaseOverride (ec, op);
7451 protected override Expression DoResolve (ResolveContext ec)
7453 eclass = ExprClass.EventAccess;
7454 type = spec.MemberType;
7456 ResolveInstanceExpression (ec, null);
7458 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7459 Error_AssignmentEventOnly (ec);
7462 DoBestMemberChecks (ec, spec);
7466 public override void Emit (EmitContext ec)
7468 throw new NotSupportedException ();
7469 //Error_CannotAssign ();
7472 #region IAssignMethod Members
7474 public void Emit (EmitContext ec, bool leave_copy)
7476 throw new NotImplementedException ();
7479 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7481 if (leave_copy || !isCompound)
7482 throw new NotImplementedException ("EventExpr::EmitAssign");
7484 Arguments args = new Arguments (1);
7485 args.Add (new Argument (source));
7487 // TODO: Wrong, needs receiver
7488 // if (NullShortCircuit) {
7489 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7492 var call = new CallEmitter ();
7493 call.InstanceExpression = InstanceExpression;
7494 call.ConditionalAccess = ConditionalAccess;
7495 call.EmitStatement (ec, op, args, loc);
7497 // if (NullShortCircuit)
7498 // ec.CloseConditionalAccess (null);
7503 void Error_AssignmentEventOnly (ResolveContext ec)
7505 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7506 ec.Report.Error (79, loc,
7507 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7508 GetSignatureForError ());
7510 ec.Report.Error (70, loc,
7511 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7512 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7516 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7518 name = name.Substring (0, name.LastIndexOf ('.'));
7519 base.Error_CannotCallAbstractBase (rc, name);
7522 public override string GetSignatureForError ()
7524 return TypeManager.CSharpSignature (spec);
7527 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7529 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7533 public class TemporaryVariableReference : VariableReference
7535 public class Declarator : Statement
7537 TemporaryVariableReference variable;
7539 public Declarator (TemporaryVariableReference variable)
7541 this.variable = variable;
7545 protected override void DoEmit (EmitContext ec)
7547 variable.li.CreateBuilder (ec);
7550 public override void Emit (EmitContext ec)
7552 // Don't create sequence point
7556 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7561 protected override void CloneTo (CloneContext clonectx, Statement target)
7569 public TemporaryVariableReference (LocalVariable li, Location loc)
7572 this.type = li.Type;
7576 public override bool IsLockedByStatement {
7584 public LocalVariable LocalInfo {
7590 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7592 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7593 return new TemporaryVariableReference (li, loc);
7596 protected override Expression DoResolve (ResolveContext ec)
7598 eclass = ExprClass.Variable;
7601 // Don't capture temporary variables except when using
7602 // state machine redirection and block yields
7604 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7605 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7606 ec.IsVariableCapturingRequired) {
7607 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7608 storey.CaptureLocalVariable (ec, li);
7614 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7616 return Resolve (ec);
7619 public override void Emit (EmitContext ec)
7621 li.CreateBuilder (ec);
7626 public void EmitAssign (EmitContext ec, Expression source)
7628 li.CreateBuilder (ec);
7630 EmitAssign (ec, source, false, false);
7633 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7635 return li.HoistedVariant;
7638 public override bool IsFixed {
7639 get { return true; }
7642 public override bool IsRef {
7643 get { return false; }
7646 public override string Name {
7647 get { throw new NotImplementedException (); }
7650 public override void SetHasAddressTaken ()
7652 throw new NotImplementedException ();
7655 protected override ILocalVariable Variable {
7659 public override VariableInfo VariableInfo {
7660 get { return null; }
7665 /// Handles `var' contextual keyword; var becomes a keyword only
7666 /// if no type called var exists in a variable scope
7668 class VarExpr : SimpleName
7670 public VarExpr (Location loc)
7675 public bool InferType (ResolveContext ec, Expression right_side)
7678 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7680 type = right_side.Type;
7681 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7682 ec.Report.Error (815, loc,
7683 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7684 type.GetSignatureForError ());
7685 type = InternalType.ErrorType;
7689 eclass = ExprClass.Variable;
7693 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7695 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7696 base.Error_TypeOrNamespaceNotFound (ec);
7698 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");