2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression
131 public ExprClass eclass;
132 protected TypeSpec type;
133 protected Location loc;
135 public TypeSpec Type {
137 set { type = value; }
140 public virtual bool IsSideEffectFree {
146 public Location Location {
150 public virtual bool IsNull {
157 // Used to workaround parser limitation where we cannot get
158 // start of statement expression location
160 public virtual Location StartLocation {
166 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
169 // Return method-group expression when the expression can be used as
170 // lambda replacement. A good example is array sorting where instead of
173 // Array.Sort (s, (a, b) => String.Compare (a, b));
175 // we can use method group directly
177 // Array.Sort (s, String.Compare);
179 // Correct overload will be used because we do the reduction after
180 // best candidate was found.
186 // Returns true when the expression during Emit phase breaks stack
187 // by using await expression
189 public virtual bool ContainsEmitWithAwait ()
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 protected abstract Expression DoResolve (ResolveContext rc);
223 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
234 var rc = mc as ResolveContext ?? new ResolveContext (mc);
235 Expression e = Resolve (rc);
237 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
242 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
244 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
247 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
249 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
252 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
254 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
255 name, type.GetSignatureForError ());
258 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
260 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
263 public void Error_InvalidExpressionStatement (BlockContext bc)
265 Error_InvalidExpressionStatement (bc.Report, loc);
268 public void Error_InvalidExpressionStatement (Report report)
270 Error_InvalidExpressionStatement (report, loc);
273 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
275 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
278 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
280 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
283 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
285 // The error was already reported as CS1660
286 if (type == InternalType.AnonymousMethod)
289 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
292 if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
293 target.MemberDefinition.DeclaringAssembly.IsMissing)
296 string from_type = type.GetSignatureForError ();
297 string to_type = target.GetSignatureForError ();
298 if (from_type == to_type) {
299 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
300 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
304 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
309 ec.Report.DisableReporting ();
310 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
311 ec.Report.EnableReporting ();
314 ec.Report.Error (266, loc,
315 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
318 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
323 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
325 // Better message for possible generic expressions
326 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
327 var report = context.Module.Compiler.Report;
328 report.SymbolRelatedToPreviousError (member);
329 if (member is TypeSpec)
330 member = ((TypeSpec) member).GetDefinition ();
332 member = ((MethodSpec) member).GetGenericMethodDefinition ();
334 string name = member.Kind == MemberKind.Method ? "method" : "type";
335 if (member.IsGeneric) {
336 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
337 name, member.GetSignatureForError (), member.Arity.ToString ());
339 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
340 name, member.GetSignatureForError ());
343 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
347 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
349 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
353 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
355 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
358 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
360 ec.Report.SymbolRelatedToPreviousError (type);
361 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
362 type.GetSignatureForError (), name);
365 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
367 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
368 // Already reported as CS1612
369 } else if (rhs == EmptyExpression.OutAccess) {
370 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
372 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
376 protected void Error_VoidPointerOperation (ResolveContext rc)
378 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
381 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
383 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
386 public ResolveFlags ExprClassToResolveFlags {
390 case ExprClass.Namespace:
391 return ResolveFlags.Type;
393 case ExprClass.MethodGroup:
394 return ResolveFlags.MethodGroup;
396 case ExprClass.TypeParameter:
397 return ResolveFlags.TypeParameter;
399 case ExprClass.Value:
400 case ExprClass.Variable:
401 case ExprClass.PropertyAccess:
402 case ExprClass.EventAccess:
403 case ExprClass.IndexerAccess:
404 return ResolveFlags.VariableOrValue;
407 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
413 // Implements identical simple name and type-name resolution
415 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
418 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
421 // 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
422 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
424 if (left is MemberExpr || left is VariableReference) {
425 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
426 if (identical_type != null && identical_type.Type == left.Type)
427 return identical_type;
433 public virtual string GetSignatureForError ()
435 return type.GetDefinition ().GetSignatureForError ();
438 public static bool IsNeverNull (Expression expr)
440 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
443 var c = expr as Constant;
447 var tc = expr as TypeCast;
449 return IsNeverNull (tc.Child);
454 protected static bool IsNullPropagatingValid (TypeSpec type)
457 case MemberKind.Struct:
458 return type.IsNullableType;
459 case MemberKind.Enum:
460 case MemberKind.Void:
461 case MemberKind.PointerType:
463 case MemberKind.InternalCompilerType:
464 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
465 case MemberKind.TypeParameter:
466 return !((TypeParameterSpec) type).IsValueType;
472 public virtual bool HasConditionalAccess ()
477 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
479 var tps = type as TypeParameterSpec;
480 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
481 Error_OperatorCannotBeApplied (rc, loc, "?", type);
484 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
485 Nullable.NullableInfo.MakeType (rc.Module, type) :
490 /// Resolves an expression and performs semantic analysis on it.
494 /// Currently Resolve wraps DoResolve to perform sanity
495 /// checking and assertion checking on what we expect from Resolve.
497 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
499 if (eclass != ExprClass.Unresolved) {
500 if ((flags & ExprClassToResolveFlags) == 0) {
501 Error_UnexpectedKind (ec, flags, loc);
515 if ((flags & e.ExprClassToResolveFlags) == 0) {
516 e.Error_UnexpectedKind (ec, flags, loc);
521 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
524 } catch (Exception ex) {
525 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
526 ec.Report.Printer is NullReportPrinter)
529 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
530 return ErrorExpression.Instance; // TODO: Add location
535 /// Resolves an expression and performs semantic analysis on it.
537 public Expression Resolve (ResolveContext rc)
539 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
543 /// Resolves an expression for LValue assignment
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
550 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
552 int errors = ec.Report.Errors;
553 bool out_access = right_side == EmptyExpression.OutAccess;
555 Expression e = DoResolveLValue (ec, right_side);
557 if (e != null && out_access && !(e is IMemoryLocation)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
567 if (errors == ec.Report.Errors) {
568 Error_ValueAssignment (ec, right_side);
573 if (e.eclass == ExprClass.Unresolved)
574 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
576 if ((e.type == null) && !(e is GenericTypeExpr))
577 throw new Exception ("Expression " + e + " did not set its type after Resolve");
582 public Constant ResolveLabelConstant (ResolveContext rc)
584 var expr = Resolve (rc);
588 Constant c = expr as Constant;
590 if (expr.type != InternalType.ErrorType)
591 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
599 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
601 if (Attribute.IsValidArgumentType (parameterType)) {
602 rc.Module.Compiler.Report.Error (182, loc,
603 "An attribute argument must be a constant expression, typeof expression or array creation expression");
605 rc.Module.Compiler.Report.Error (181, loc,
606 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
607 targetType.GetSignatureForError ());
612 /// Emits the code for the expression
616 /// The Emit method is invoked to generate the code
617 /// for the expression.
619 public abstract void Emit (EmitContext ec);
622 // Emit code to branch to @target if this expression is equivalent to @on_true.
623 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
624 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
625 // including the use of conditional branches. Note also that a branch MUST be emitted
626 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
629 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
632 // Emit this expression for its side effects, not for its value.
633 // The default implementation is to emit the value, and then throw it away.
634 // Subclasses can provide more efficient implementations, but those MUST be equivalent
635 public virtual void EmitSideEffect (EmitContext ec)
638 ec.Emit (OpCodes.Pop);
642 // Emits the expression into temporary field variable. The method
643 // should be used for await expressions only
645 public virtual Expression EmitToField (EmitContext ec)
648 // This is the await prepare Emit method. When emitting code like
649 // a + b we emit code like
655 // For await a + await b we have to interfere the flow to keep the
656 // stack clean because await yields from the expression. The emit
659 // a = a.EmitToField () // a is changed to temporary field access
660 // b = b.EmitToField ()
666 // The idea is to emit expression and leave the stack empty with
667 // result value still available.
669 // Expressions should override this default implementation when
670 // optimized version can be provided (e.g. FieldExpr)
673 // We can optimize for side-effect free expressions, they can be
674 // emitted out of order
676 if (IsSideEffectFree)
679 bool needs_temporary = ContainsEmitWithAwait ();
680 if (!needs_temporary)
683 // Emit original code
684 var field = EmitToFieldSource (ec);
687 // Store the result to temporary field when we
688 // cannot load `this' directly
690 field = ec.GetTemporaryField (type);
691 if (needs_temporary) {
693 // Create temporary local (we cannot load `this' before Emit)
695 var temp = ec.GetTemporaryLocal (type);
696 ec.Emit (OpCodes.Stloc, temp);
699 ec.Emit (OpCodes.Ldloc, temp);
700 field.EmitAssignFromStack (ec);
702 ec.FreeTemporaryLocal (temp, type);
704 field.EmitAssignFromStack (ec);
711 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
714 // Default implementation calls Emit method
720 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
722 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
723 bool contains_await = false;
725 for (int i = 1; i < expressions.Count; ++i) {
726 if (expressions[i].ContainsEmitWithAwait ()) {
727 contains_await = true;
732 if (contains_await) {
733 for (int i = 0; i < expressions.Count; ++i) {
734 expressions[i] = expressions[i].EmitToField (ec);
739 for (int i = 0; i < expressions.Count; ++i) {
740 expressions[i].Emit (ec);
745 /// Protected constructor. Only derivate types should
746 /// be able to be created
749 protected Expression ()
754 /// Returns a fully formed expression after a MemberLookup
757 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
759 if (spec is EventSpec)
760 return new EventExpr ((EventSpec) spec, loc);
761 if (spec is ConstSpec)
762 return new ConstantExpr ((ConstSpec) spec, loc);
763 if (spec is FieldSpec)
764 return new FieldExpr ((FieldSpec) spec, loc);
765 if (spec is PropertySpec)
766 return new PropertyExpr ((PropertySpec) spec, loc);
767 if (spec is TypeSpec)
768 return new TypeExpression (((TypeSpec) spec), loc);
773 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
775 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
778 case MemberKind.Struct:
779 // Every struct has implicit default constructor if not provided by user
783 rc.Report.SymbolRelatedToPreviousError (type);
784 // Report meaningful error for struct as they always have default ctor in C# context
785 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
787 case MemberKind.MissingType:
788 case MemberKind.InternalCompilerType:
789 // LAMESPEC: dynamic is not really object
790 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
794 rc.Report.SymbolRelatedToPreviousError (type);
795 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
796 type.GetSignatureForError ());
803 if (args == null && type.IsStruct) {
804 bool includes_empty = false;
805 foreach (MethodSpec ctor in ctors) {
806 if (ctor.Parameters.IsEmpty) {
807 includes_empty = true;
815 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
816 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
817 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
820 return r.ResolveMember<MethodSpec> (rc, ref args);
824 public enum MemberLookupRestrictions
830 EmptyArguments = 1 << 4,
831 IgnoreArity = 1 << 5,
832 IgnoreAmbiguity = 1 << 6,
833 NameOfExcluded = 1 << 7,
834 DontSetConditionalAccess = 1 << 8
838 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
839 // `qualifier_type' or null to lookup members in the current class.
841 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
843 var members = MemberCache.FindMembers (queried_type, name, false);
849 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
853 if (members [0].DeclaringType.BaseType == null)
856 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
857 } while (members != null);
862 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
864 MemberSpec non_method = null;
865 MemberSpec ambig_non_method = null;
867 for (int i = 0; i < members.Count; ++i) {
868 var member = members [i];
870 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
871 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
874 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
877 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
881 if (!member.IsAccessible (rc))
885 // With runtime binder we can have a situation where queried type is inaccessible
886 // because it came via dynamic object, the check about inconsisted accessibility
887 // had no effect as the type was unknown during compilation
890 // private class N { }
892 // public dynamic Foo ()
898 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
902 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
903 if (member is MethodSpec) {
905 // Interface members that are hidden by class members are removed from the set. This
906 // step only has an effect if T is a type parameter and T has both an effective base
907 // class other than object and a non-empty effective interface set
909 var tps = queried_type as TypeParameterSpec;
910 if (tps != null && tps.HasTypeConstraint)
911 members = RemoveHiddenTypeParameterMethods (members);
913 return new MethodGroupExpr (members, queried_type, loc);
916 if (!Invocation.IsMemberInvocable (member))
920 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
922 } else if (!errorMode && !member.IsNotCSharpCompatible) {
924 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
925 // T has both an effective base class other than object and a non-empty effective interface set.
927 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
929 var tps = queried_type as TypeParameterSpec;
930 if (tps != null && tps.HasTypeConstraint) {
931 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
934 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
940 ambig_non_method = member;
944 if (non_method != null) {
945 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
946 var report = rc.Module.Compiler.Report;
947 report.SymbolRelatedToPreviousError (non_method);
948 report.SymbolRelatedToPreviousError (ambig_non_method);
949 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
950 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
953 if (non_method is MethodSpec)
954 return new MethodGroupExpr (members, queried_type, loc);
956 return ExprClassFromMemberInfo (non_method, loc);
962 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
964 if (members.Count < 2)
968 // If M is a method, then all non-method members declared in an interface declaration
969 // are removed from the set, and all methods with the same signature as M declared in
970 // an interface declaration are removed from the set
974 for (int i = 0; i < members.Count; ++i) {
975 var method = members[i] as MethodSpec;
976 if (method == null) {
979 members = new List<MemberSpec> (members);
982 members.RemoveAt (i--);
986 if (!method.DeclaringType.IsInterface)
989 for (int ii = 0; ii < members.Count; ++ii) {
990 var candidate = members[ii] as MethodSpec;
991 if (candidate == null || !candidate.DeclaringType.IsClass)
994 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
997 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
1002 members = new List<MemberSpec> (members);
1005 members.RemoveAt (i--);
1013 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1015 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1018 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1020 throw new NotImplementedException ();
1023 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1025 if (t == InternalType.ErrorType)
1028 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1029 oper, t.GetSignatureForError ());
1032 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1034 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1037 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1039 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1042 protected void Error_NullPropagatingLValue (ResolveContext rc)
1044 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1047 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1052 // Special version of flow analysis for expressions which can return different
1053 // on-true and on-false result. Used by &&, ||, ?: expressions
1055 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1058 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1062 /// Returns an expression that can be used to invoke operator true
1063 /// on the expression if it exists.
1065 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1067 return GetOperatorTrueOrFalse (ec, e, true, loc);
1071 /// Returns an expression that can be used to invoke operator false
1072 /// on the expression if it exists.
1074 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1076 return GetOperatorTrueOrFalse (ec, e, false, loc);
1079 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1081 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1083 if (type.IsNullableType)
1084 type = Nullable.NullableInfo.GetUnderlyingType (type);
1086 var methods = MemberCache.GetUserOperator (type, op, false);
1087 if (methods == null)
1090 Arguments arguments = new Arguments (1);
1091 arguments.Add (new Argument (e));
1093 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1094 var oper = res.ResolveOperator (ec, ref arguments);
1099 return new UserOperatorCall (oper, arguments, null, loc);
1102 public virtual string ExprClassName
1106 case ExprClass.Unresolved:
1107 return "Unresolved";
1108 case ExprClass.Value:
1110 case ExprClass.Variable:
1112 case ExprClass.Namespace:
1114 case ExprClass.Type:
1116 case ExprClass.MethodGroup:
1117 return "method group";
1118 case ExprClass.PropertyAccess:
1119 return "property access";
1120 case ExprClass.EventAccess:
1121 return "event access";
1122 case ExprClass.IndexerAccess:
1123 return "indexer access";
1124 case ExprClass.Nothing:
1126 case ExprClass.TypeParameter:
1127 return "type parameter";
1129 throw new Exception ("Should not happen");
1134 /// Reports that we were expecting `expr' to be of class `expected'
1136 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1138 var name = memberExpr.GetSignatureForError ();
1140 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1143 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1145 string [] valid = new string [4];
1148 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1149 valid [count++] = "variable";
1150 valid [count++] = "value";
1153 if ((flags & ResolveFlags.Type) != 0)
1154 valid [count++] = "type";
1156 if ((flags & ResolveFlags.MethodGroup) != 0)
1157 valid [count++] = "method group";
1160 valid [count++] = "unknown";
1162 StringBuilder sb = new StringBuilder (valid [0]);
1163 for (int i = 1; i < count - 1; i++) {
1165 sb.Append (valid [i]);
1168 sb.Append ("' or `");
1169 sb.Append (valid [count - 1]);
1172 ec.Report.Error (119, loc,
1173 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1176 public static void UnsafeError (ResolveContext ec, Location loc)
1178 UnsafeError (ec.Report, loc);
1181 public static void UnsafeError (Report Report, Location loc)
1183 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1187 // Converts `source' to an int, uint, long or ulong.
1189 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1191 var btypes = ec.BuiltinTypes;
1193 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1194 Arguments args = new Arguments (1);
1195 args.Add (new Argument (source));
1196 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1199 Expression converted;
1201 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1202 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1203 if (converted == null)
1204 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1205 if (converted == null)
1206 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1207 if (converted == null)
1208 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1210 if (converted == null) {
1211 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1220 // Only positive constants are allowed at compile time
1222 Constant c = converted as Constant;
1223 if (c != null && c.IsNegative)
1224 Error_NegativeArrayIndex (ec, source.loc);
1226 // No conversion needed to array index
1227 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1230 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1233 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1235 if (args.Count != 1){
1236 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1241 if (arg is NamedArgument)
1242 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1244 var index = arg.Expr.Resolve (rc);
1248 index = ConvertExpressionToArrayIndex (rc, index, true);
1250 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1251 return new Indirection (p, loc);
1255 // Derived classes implement this method by cloning the fields that
1256 // could become altered during the Resolve stage
1258 // Only expressions that are created for the parser need to implement
1261 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1263 throw new NotImplementedException (
1265 "CloneTo not implemented for expression {0}", this.GetType ()));
1269 // Clones an expression created by the parser.
1271 // We only support expressions created by the parser so far, not
1272 // expressions that have been resolved (many more classes would need
1273 // to implement CloneTo).
1275 // This infrastructure is here merely for Lambda expressions which
1276 // compile the same code using different type values for the same
1277 // arguments to find the correct overload
1279 public virtual Expression Clone (CloneContext clonectx)
1281 Expression cloned = (Expression) MemberwiseClone ();
1282 CloneTo (clonectx, cloned);
1288 // Implementation of expression to expression tree conversion
1290 public abstract Expression CreateExpressionTree (ResolveContext ec);
1292 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1294 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1297 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1299 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1302 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1304 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1307 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1309 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1313 return new TypeExpression (t, loc);
1317 // Implemented by all expressions which support conversion from
1318 // compiler expression to invokable runtime expression. Used by
1319 // dynamic C# binder.
1321 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1323 throw new NotImplementedException ("MakeExpression for " + GetType ());
1326 public virtual object Accept (StructuralVisitor visitor)
1328 return visitor.Visit (this);
1333 /// This is just a base class for expressions that can
1334 /// appear on statements (invocations, object creation,
1335 /// assignments, post/pre increment and decrement). The idea
1336 /// being that they would support an extra Emition interface that
1337 /// does not leave a result on the stack.
1339 public abstract class ExpressionStatement : Expression
1341 public virtual void MarkReachable (Reachability rc)
1345 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1347 Expression e = Resolve (ec);
1351 ExpressionStatement es = e as ExpressionStatement;
1352 if (es == null || e is AnonymousMethodBody) {
1353 var reduced = e as IReducedExpressionStatement;
1354 if (reduced != null) {
1355 return EmptyExpressionStatement.Instance;
1358 Error_InvalidExpressionStatement (ec);
1362 // This is quite expensive warning, try to limit the damage
1364 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1365 WarningAsyncWithoutWait (ec, e);
1371 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1373 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1374 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1379 // Need to do full resolve because GetAwaiter can be extension method
1380 // available only in this context
1382 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1386 var arguments = new Arguments (0);
1387 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1392 // Use same check rules as for real await
1394 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1395 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1398 bc.Report.Warning (4014, 1, e.Location,
1399 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1403 var inv = e as Invocation;
1404 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1405 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1406 bc.Report.Warning (4014, 1, e.Location,
1407 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1413 /// Requests the expression to be emitted in a `statement'
1414 /// context. This means that no new value is left on the
1415 /// stack after invoking this method (constrasted with
1416 /// Emit that will always leave a value on the stack).
1418 public abstract void EmitStatement (EmitContext ec);
1420 public override void EmitSideEffect (EmitContext ec)
1426 interface IReducedExpressionStatement
1431 /// This kind of cast is used to encapsulate the child
1432 /// whose type is child.Type into an expression that is
1433 /// reported to return "return_type". This is used to encapsulate
1434 /// expressions which have compatible types, but need to be dealt
1435 /// at higher levels with.
1437 /// For example, a "byte" expression could be encapsulated in one
1438 /// of these as an "unsigned int". The type for the expression
1439 /// would be "unsigned int".
1442 public abstract class TypeCast : Expression
1444 protected readonly Expression child;
1446 protected TypeCast (Expression child, TypeSpec return_type)
1448 eclass = child.eclass;
1449 loc = child.Location;
1454 public Expression Child {
1460 public override bool ContainsEmitWithAwait ()
1462 return child.ContainsEmitWithAwait ();
1465 public override Expression CreateExpressionTree (ResolveContext ec)
1467 Arguments args = new Arguments (2);
1468 args.Add (new Argument (child.CreateExpressionTree (ec)));
1469 args.Add (new Argument (new TypeOf (type, loc)));
1471 if (type.IsPointer || child.Type.IsPointer)
1472 Error_PointerInsideExpressionTree (ec);
1474 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1477 protected override Expression DoResolve (ResolveContext ec)
1479 // This should never be invoked, we are born in fully
1480 // initialized state.
1485 public override void Emit (EmitContext ec)
1490 public override void FlowAnalysis (FlowAnalysisContext fc)
1492 child.FlowAnalysis (fc);
1495 public override SLE.Expression MakeExpression (BuilderContext ctx)
1498 return base.MakeExpression (ctx);
1500 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1501 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1502 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1506 protected override void CloneTo (CloneContext clonectx, Expression t)
1511 public override bool IsNull {
1512 get { return child.IsNull; }
1516 public class EmptyCast : TypeCast {
1517 EmptyCast (Expression child, TypeSpec target_type)
1518 : base (child, target_type)
1522 public static Expression Create (Expression child, TypeSpec type)
1524 Constant c = child as Constant;
1526 var enum_constant = c as EnumConstant;
1527 if (enum_constant != null)
1528 c = enum_constant.Child;
1530 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1534 var res = c.ConvertImplicitly (type);
1540 EmptyCast e = child as EmptyCast;
1542 return new EmptyCast (e.child, type);
1544 return new EmptyCast (child, type);
1547 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1549 child.EmitBranchable (ec, label, on_true);
1552 public override void EmitSideEffect (EmitContext ec)
1554 child.EmitSideEffect (ec);
1559 // Used for predefined type user operator (no obsolete check, etc.)
1561 public class OperatorCast : TypeCast
1563 readonly MethodSpec conversion_operator;
1565 public OperatorCast (Expression expr, TypeSpec target_type)
1566 : this (expr, target_type, target_type, false)
1570 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1571 : this (expr, target_type, target_type, find_explicit)
1575 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1576 : base (expr, returnType)
1578 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1579 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1582 foreach (MethodSpec oper in mi) {
1583 if (oper.ReturnType != returnType)
1586 if (oper.Parameters.Types[0] == expr.Type) {
1587 conversion_operator = oper;
1593 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1594 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1597 public override void Emit (EmitContext ec)
1600 ec.Emit (OpCodes.Call, conversion_operator);
1605 // Constant specialization of EmptyCast.
1606 // We need to special case this since an empty cast of
1607 // a constant is still a constant.
1609 public class EmptyConstantCast : Constant
1611 public readonly Constant child;
1613 public EmptyConstantCast (Constant child, TypeSpec type)
1614 : base (child.Location)
1617 throw new ArgumentNullException ("child");
1620 this.eclass = child.eclass;
1624 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1626 if (child.Type == target_type)
1629 // FIXME: check that 'type' can be converted to 'target_type' first
1630 return child.ConvertExplicitly (in_checked_context, target_type);
1633 public override Expression CreateExpressionTree (ResolveContext ec)
1635 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1636 child.CreateExpressionTree (ec),
1637 new TypeOf (type, loc));
1640 Error_PointerInsideExpressionTree (ec);
1642 return CreateExpressionFactoryCall (ec, "Convert", args);
1645 public override bool IsDefaultValue {
1646 get { return child.IsDefaultValue; }
1649 public override bool IsNegative {
1650 get { return child.IsNegative; }
1653 public override bool IsNull {
1654 get { return child.IsNull; }
1657 public override bool IsOneInteger {
1658 get { return child.IsOneInteger; }
1661 public override bool IsSideEffectFree {
1663 return child.IsSideEffectFree;
1667 public override bool IsZeroInteger {
1668 get { return child.IsZeroInteger; }
1671 public override void Emit (EmitContext ec)
1676 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1678 child.EmitBranchable (ec, label, on_true);
1680 // Only to make verifier happy
1681 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1682 ec.Emit (OpCodes.Unbox_Any, type);
1685 public override void EmitSideEffect (EmitContext ec)
1687 child.EmitSideEffect (ec);
1690 public override object GetValue ()
1692 return child.GetValue ();
1695 public override string GetValueAsLiteral ()
1697 return child.GetValueAsLiteral ();
1700 public override long GetValueAsLong ()
1702 return child.GetValueAsLong ();
1705 public override Constant ConvertImplicitly (TypeSpec target_type)
1707 if (type == target_type)
1710 // FIXME: Do we need to check user conversions?
1711 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1714 return child.ConvertImplicitly (target_type);
1719 /// This class is used to wrap literals which belong inside Enums
1721 public class EnumConstant : Constant
1723 public Constant Child;
1725 public EnumConstant (Constant child, TypeSpec enum_type)
1726 : base (child.Location)
1730 this.eclass = ExprClass.Value;
1731 this.type = enum_type;
1734 protected EnumConstant (Location loc)
1739 public override void Emit (EmitContext ec)
1744 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1746 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1749 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1751 Child.EmitBranchable (ec, label, on_true);
1754 public override void EmitSideEffect (EmitContext ec)
1756 Child.EmitSideEffect (ec);
1759 public override string GetSignatureForError()
1761 return Type.GetSignatureForError ();
1764 public override object GetValue ()
1766 return Child.GetValue ();
1770 public override object GetTypedValue ()
1773 // The method can be used in dynamic context only (on closed types)
1775 // System.Enum.ToObject cannot be called on dynamic types
1776 // EnumBuilder has to be used, but we cannot use EnumBuilder
1777 // because it does not properly support generics
1779 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1783 public override string GetValueAsLiteral ()
1785 return Child.GetValueAsLiteral ();
1788 public override long GetValueAsLong ()
1790 return Child.GetValueAsLong ();
1793 public EnumConstant Increment()
1795 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1798 public override bool IsDefaultValue {
1800 return Child.IsDefaultValue;
1804 public override bool IsSideEffectFree {
1806 return Child.IsSideEffectFree;
1810 public override bool IsZeroInteger {
1811 get { return Child.IsZeroInteger; }
1814 public override bool IsNegative {
1816 return Child.IsNegative;
1820 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1822 if (Child.Type == target_type)
1825 return Child.ConvertExplicitly (in_checked_context, target_type);
1828 public override Constant ConvertImplicitly (TypeSpec type)
1830 if (this.type == type) {
1834 if (!Convert.ImplicitStandardConversionExists (this, type)){
1838 return Child.ConvertImplicitly (type);
1843 /// This kind of cast is used to encapsulate Value Types in objects.
1845 /// The effect of it is to box the value type emitted by the previous
1848 public class BoxedCast : TypeCast {
1850 public BoxedCast (Expression expr, TypeSpec target_type)
1851 : base (expr, target_type)
1853 eclass = ExprClass.Value;
1856 protected override Expression DoResolve (ResolveContext ec)
1858 // This should never be invoked, we are born in fully
1859 // initialized state.
1864 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1866 // Only boxing to object type is supported
1867 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1868 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1872 enc.Encode (child.Type);
1873 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1876 public override void Emit (EmitContext ec)
1880 ec.Emit (OpCodes.Box, child.Type);
1883 public override void EmitSideEffect (EmitContext ec)
1885 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1886 // so, we need to emit the box+pop instructions in most cases
1887 if (child.Type.IsStruct &&
1888 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1889 child.EmitSideEffect (ec);
1891 base.EmitSideEffect (ec);
1895 public class UnboxCast : TypeCast {
1896 public UnboxCast (Expression expr, TypeSpec return_type)
1897 : base (expr, return_type)
1901 protected override Expression DoResolve (ResolveContext ec)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1909 public override void Emit (EmitContext ec)
1913 ec.Emit (OpCodes.Unbox_Any, type);
1918 /// This is used to perform explicit numeric conversions.
1920 /// Explicit numeric conversions might trigger exceptions in a checked
1921 /// context, so they should generate the conv.ovf opcodes instead of
1924 public class ConvCast : TypeCast {
1925 public enum Mode : byte {
1926 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1928 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1929 U2_I1, U2_U1, U2_I2, U2_CH,
1930 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1931 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1932 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1933 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1934 CH_I1, CH_U1, CH_I2,
1935 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1936 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1942 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1943 : base (child, return_type)
1948 protected override Expression DoResolve (ResolveContext ec)
1950 // This should never be invoked, we are born in fully
1951 // initialized state.
1956 public override string ToString ()
1958 return String.Format ("ConvCast ({0}, {1})", mode, child);
1961 public override void Emit (EmitContext ec)
1967 public static void Emit (EmitContext ec, Mode mode)
1969 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1971 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1972 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1974 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1975 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1977 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.U1_CH: /* nothing */ break;
1980 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1981 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1982 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1983 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1984 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1985 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1988 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1989 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1990 case Mode.U2_CH: /* nothing */ break;
1992 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1993 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1994 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1995 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1996 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1997 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1998 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2000 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2001 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2002 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2003 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2004 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2005 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2007 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2008 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2009 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2010 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2012 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2013 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2014 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2017 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2018 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2019 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2020 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2021 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2022 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2023 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2024 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2025 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2027 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2028 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2029 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2031 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2032 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2033 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2034 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2035 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2036 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2037 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2038 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2039 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2041 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2042 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2043 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2044 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2045 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2046 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2047 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2048 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2049 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2050 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2052 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2056 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2057 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2059 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2060 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2062 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2063 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2065 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2066 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2067 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2068 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2069 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2070 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2073 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2074 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2075 case Mode.U2_CH: /* nothing */ break;
2077 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2078 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2079 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2080 case Mode.I4_U4: /* nothing */ break;
2081 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2083 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2085 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2086 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2087 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2088 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2089 case Mode.U4_I4: /* nothing */ break;
2090 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2092 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.I8_U8: /* nothing */ break;
2099 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2100 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2102 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2105 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2106 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2107 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2108 case Mode.U8_I8: /* nothing */ break;
2109 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2110 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2112 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2113 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2114 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2116 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2117 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2118 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2119 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2120 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2121 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2122 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2123 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2124 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2126 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2127 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2128 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2129 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2130 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2131 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2132 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2133 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2134 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2135 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2137 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2143 class OpcodeCast : TypeCast
2147 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2148 : base (child, return_type)
2153 protected override Expression DoResolve (ResolveContext ec)
2155 // This should never be invoked, we are born in fully
2156 // initialized state.
2161 public override void Emit (EmitContext ec)
2167 public TypeSpec UnderlyingType {
2168 get { return child.Type; }
2173 // Opcode casts expression with 2 opcodes but only
2174 // single expression tree node
2176 class OpcodeCastDuplex : OpcodeCast
2178 readonly OpCode second;
2180 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2181 : base (child, returnType, first)
2183 this.second = second;
2186 public override void Emit (EmitContext ec)
2194 /// This kind of cast is used to encapsulate a child and cast it
2195 /// to the class requested
2197 public sealed class ClassCast : TypeCast {
2198 readonly bool forced;
2200 public ClassCast (Expression child, TypeSpec return_type)
2201 : base (child, return_type)
2205 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2206 : base (child, return_type)
2208 this.forced = forced;
2211 public override void Emit (EmitContext ec)
2215 bool gen = TypeManager.IsGenericParameter (child.Type);
2217 ec.Emit (OpCodes.Box, child.Type);
2219 if (type.IsGenericParameter) {
2220 ec.Emit (OpCodes.Unbox_Any, type);
2227 ec.Emit (OpCodes.Castclass, type);
2232 // Created during resolving pahse when an expression is wrapped or constantified
2233 // and original expression can be used later (e.g. for expression trees)
2235 public class ReducedExpression : Expression
2237 public class ReducedConstantExpression : EmptyConstantCast
2239 readonly Expression orig_expr;
2241 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2242 : base (expr, expr.Type)
2244 this.orig_expr = orig_expr;
2247 public Expression OriginalExpression {
2253 public override Constant ConvertImplicitly (TypeSpec target_type)
2255 Constant c = base.ConvertImplicitly (target_type);
2257 c = new ReducedConstantExpression (c, orig_expr);
2262 public override Expression CreateExpressionTree (ResolveContext ec)
2264 return orig_expr.CreateExpressionTree (ec);
2267 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2269 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2271 c = new ReducedConstantExpression (c, orig_expr);
2275 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2278 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2280 if (orig_expr is Conditional)
2281 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2283 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2287 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2289 public ReducedConstantStatement (Constant expr, Expression origExpr)
2290 : base (expr, origExpr)
2295 sealed class ReducedExpressionStatement : ExpressionStatement
2297 readonly Expression orig_expr;
2298 readonly ExpressionStatement stm;
2300 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2302 this.orig_expr = orig;
2304 this.eclass = stm.eclass;
2305 this.type = stm.Type;
2307 this.loc = orig.Location;
2310 public override bool ContainsEmitWithAwait ()
2312 return stm.ContainsEmitWithAwait ();
2315 public override Expression CreateExpressionTree (ResolveContext ec)
2317 return orig_expr.CreateExpressionTree (ec);
2320 protected override Expression DoResolve (ResolveContext ec)
2325 public override void Emit (EmitContext ec)
2330 public override void EmitStatement (EmitContext ec)
2332 stm.EmitStatement (ec);
2335 public override void FlowAnalysis (FlowAnalysisContext fc)
2337 stm.FlowAnalysis (fc);
2341 readonly Expression expr, orig_expr;
2343 private ReducedExpression (Expression expr, Expression orig_expr)
2346 this.eclass = expr.eclass;
2347 this.type = expr.Type;
2348 this.orig_expr = orig_expr;
2349 this.loc = orig_expr.Location;
2354 public override bool IsSideEffectFree {
2356 return expr.IsSideEffectFree;
2360 public Expression OriginalExpression {
2368 public override bool ContainsEmitWithAwait ()
2370 return expr.ContainsEmitWithAwait ();
2374 // Creates fully resolved expression switcher
2376 public static Constant Create (Constant expr, Expression originalExpr)
2378 if (expr.eclass == ExprClass.Unresolved)
2379 throw new ArgumentException ("Unresolved expression");
2381 if (originalExpr is ExpressionStatement)
2382 return new ReducedConstantStatement (expr, originalExpr);
2384 return new ReducedConstantExpression (expr, originalExpr);
2387 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2389 return new ReducedExpressionStatement (s, orig);
2392 public static Expression Create (Expression expr, Expression original_expr)
2394 return Create (expr, original_expr, true);
2398 // Creates unresolved reduce expression. The original expression has to be
2399 // already resolved. Created expression is constant based based on `expr'
2400 // value unless canBeConstant is used
2402 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2404 if (canBeConstant) {
2405 Constant c = expr as Constant;
2407 return Create (c, original_expr);
2410 ExpressionStatement s = expr as ExpressionStatement;
2412 return Create (s, original_expr);
2414 if (expr.eclass == ExprClass.Unresolved)
2415 throw new ArgumentException ("Unresolved expression");
2417 return new ReducedExpression (expr, original_expr);
2420 public override Expression CreateExpressionTree (ResolveContext ec)
2422 return orig_expr.CreateExpressionTree (ec);
2425 protected override Expression DoResolve (ResolveContext ec)
2430 public override void Emit (EmitContext ec)
2435 public override Expression EmitToField (EmitContext ec)
2437 return expr.EmitToField(ec);
2440 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2442 expr.EmitBranchable (ec, target, on_true);
2445 public override void FlowAnalysis (FlowAnalysisContext fc)
2447 expr.FlowAnalysis (fc);
2450 public override SLE.Expression MakeExpression (BuilderContext ctx)
2452 return orig_expr.MakeExpression (ctx);
2457 // Standard composite pattern
2459 public abstract class CompositeExpression : Expression
2461 protected Expression expr;
2463 protected CompositeExpression (Expression expr)
2466 this.loc = expr.Location;
2469 public override bool ContainsEmitWithAwait ()
2471 return expr.ContainsEmitWithAwait ();
2474 public override Expression CreateExpressionTree (ResolveContext rc)
2476 return expr.CreateExpressionTree (rc);
2479 public Expression Child {
2480 get { return expr; }
2483 protected override Expression DoResolve (ResolveContext rc)
2485 expr = expr.Resolve (rc);
2490 eclass = expr.eclass;
2494 public override void Emit (EmitContext ec)
2499 public override bool IsNull {
2500 get { return expr.IsNull; }
2505 // Base of expressions used only to narrow resolve flow
2507 public abstract class ShimExpression : Expression
2509 protected Expression expr;
2511 protected ShimExpression (Expression expr)
2516 public Expression Expr {
2522 protected override void CloneTo (CloneContext clonectx, Expression t)
2527 ShimExpression target = (ShimExpression) t;
2528 target.expr = expr.Clone (clonectx);
2531 public override bool ContainsEmitWithAwait ()
2533 return expr.ContainsEmitWithAwait ();
2536 public override Expression CreateExpressionTree (ResolveContext ec)
2538 throw new NotSupportedException ("ET");
2541 public override void Emit (EmitContext ec)
2543 throw new InternalErrorException ("Missing Resolve call");
2547 public class UnreachableExpression : Expression
2549 public UnreachableExpression (Expression expr)
2551 this.loc = expr.Location;
2554 public override Expression CreateExpressionTree (ResolveContext ec)
2557 throw new NotImplementedException ();
2560 protected override Expression DoResolve (ResolveContext rc)
2562 throw new NotSupportedException ();
2565 public override void FlowAnalysis (FlowAnalysisContext fc)
2567 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2570 public override void Emit (EmitContext ec)
2574 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2580 // Unresolved type name expressions
2582 public abstract class ATypeNameExpression : FullNamedExpression
2585 protected TypeArguments targs;
2587 protected ATypeNameExpression (string name, Location l)
2593 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2600 protected ATypeNameExpression (string name, int arity, Location l)
2601 : this (name, new UnboundTypeArguments (arity, l), l)
2609 return targs == null ? 0 : targs.Count;
2613 public bool HasTypeArguments {
2615 return targs != null && !targs.IsEmpty;
2619 public string Name {
2628 public TypeArguments TypeArguments {
2636 public override bool Equals (object obj)
2638 ATypeNameExpression atne = obj as ATypeNameExpression;
2639 return atne != null && atne.Name == Name &&
2640 (targs == null || targs.Equals (atne.targs));
2643 public override int GetHashCode ()
2645 return Name.GetHashCode ();
2648 // TODO: Move it to MemberCore
2649 public static string GetMemberType (MemberCore mc)
2655 if (mc is FieldBase)
2657 if (mc is MethodCore)
2659 if (mc is EnumMember)
2667 public override string GetSignatureForError ()
2669 if (targs != null) {
2670 return Name + "<" + targs.GetSignatureForError () + ">";
2676 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2680 /// SimpleName expressions are formed of a single word and only happen at the beginning
2681 /// of a dotted-name.
2683 public class SimpleName : ATypeNameExpression
2685 public SimpleName (string name, Location l)
2690 public SimpleName (string name, TypeArguments args, Location l)
2691 : base (name, args, l)
2695 public SimpleName (string name, int arity, Location l)
2696 : base (name, arity, l)
2700 public SimpleName GetMethodGroup ()
2702 return new SimpleName (Name, targs, loc);
2705 protected override Expression DoResolve (ResolveContext rc)
2707 return SimpleNameResolve (rc, null);
2710 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2712 return SimpleNameResolve (ec, right_side);
2715 public void Error_NameDoesNotExist (ResolveContext rc)
2717 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2720 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2722 if (ctx.CurrentType != null) {
2723 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2724 if (member != null) {
2725 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2730 var report = ctx.Module.Compiler.Report;
2732 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2733 if (retval != null) {
2734 report.SymbolRelatedToPreviousError (retval.Type);
2735 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2739 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2740 if (retval != null) {
2741 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2745 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2746 if (ns_candidates != null) {
2747 if (ctx is UsingAliasNamespace.AliasContext) {
2748 report.Error (246, loc,
2749 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2750 ns_candidates[0], Name);
2752 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2753 report.Error (246, loc,
2754 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2758 report.Error (246, loc,
2759 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2764 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2766 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2769 if (fne.Type != null && Arity > 0) {
2770 if (HasTypeArguments) {
2771 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2772 if (ct.ResolveAsType (mc) == null)
2778 targs.Resolve (mc, allowUnboundTypeArguments);
2780 return new GenericOpenTypeExpr (fne.Type, loc);
2784 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2786 if (!(fne is NamespaceExpression))
2790 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2791 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2792 mc.Module.Compiler.Report.Error (1980, Location,
2793 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2794 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2797 fne = new DynamicTypeExpr (loc);
2798 fne.ResolveAsType (mc);
2804 Error_TypeOrNamespaceNotFound (mc);
2808 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2810 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2813 public bool IsPossibleType (IMemberContext mc)
2815 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2818 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2820 int lookup_arity = Arity;
2821 bool errorMode = false;
2823 Block current_block = rc.CurrentBlock;
2824 INamedBlockVariable variable = null;
2825 bool variable_found = false;
2829 // Stage 1: binding to local variables or parameters
2831 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2833 if (current_block != null && lookup_arity == 0) {
2834 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2835 if (!variable.IsDeclared) {
2836 // We found local name in accessible block but it's not
2837 // initialized yet, maybe the user wanted to bind to something else
2839 variable_found = true;
2841 e = variable.CreateReferenceExpression (rc, loc);
2844 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2853 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2855 TypeSpec member_type = rc.CurrentType;
2856 for (; member_type != null; member_type = member_type.DeclaringType) {
2857 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2861 var me = e as MemberExpr;
2863 // The name matches a type, defer to ResolveAsTypeStep
2871 if (variable != null) {
2872 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2873 rc.Report.Error (844, loc,
2874 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2875 Name, me.GetSignatureForError ());
2879 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2880 // Leave it to overload resolution to report correct error
2882 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2883 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2887 // MemberLookup does not check accessors availability, this is actually needed for properties only
2889 var pe = me as PropertyExpr;
2892 // Break as there is no other overload available anyway
2893 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2894 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2897 pe.Getter = pe.PropertyInfo.Get;
2899 if (!pe.PropertyInfo.HasSet) {
2900 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2901 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2902 var p = (Property) pe.PropertyInfo.MemberDefinition;
2903 return new FieldExpr (p.BackingField, loc);
2906 variable_found = true;
2910 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2911 variable_found = true;
2915 pe.Setter = pe.PropertyInfo.Set;
2920 // TODO: It's used by EventExpr -> FieldExpr transformation only
2921 // TODO: Should go to MemberAccess
2922 me = me.ResolveMemberAccess (rc, null, null);
2925 targs.Resolve (rc, false);
2926 me.SetTypeArguments (rc, targs);
2933 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2935 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2936 if (IsPossibleTypeOrNamespace (rc)) {
2937 return ResolveAsTypeOrNamespace (rc, false);
2941 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2944 targs.Resolve (rc, false);
2946 var me = expr as MemberExpr;
2948 me.SetTypeArguments (rc, targs);
2953 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2954 return new NameOf (this);
2957 if (variable_found) {
2958 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2961 var tparams = rc.CurrentTypeParameters;
2962 if (tparams != null) {
2963 if (tparams.Find (Name) != null) {
2964 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2969 var ct = rc.CurrentType;
2971 if (ct.MemberDefinition.TypeParametersCount > 0) {
2972 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2973 if (ctp.Name == Name) {
2974 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2980 ct = ct.DeclaringType;
2981 } while (ct != null);
2984 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2985 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2987 rc.Report.SymbolRelatedToPreviousError (e.Type);
2988 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2992 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2994 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2995 return ErrorExpression.Instance;
2999 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
3001 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
3002 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
3006 if (e is TypeExpr) {
3007 // TypeExpression does not have correct location
3008 if (e is TypeExpression)
3009 e = new TypeExpression (e.Type, loc);
3015 Error_NameDoesNotExist (rc);
3018 return ErrorExpression.Instance;
3021 if (rc.Module.Evaluator != null) {
3022 var fi = rc.Module.Evaluator.LookupField (Name);
3024 return new FieldExpr (fi.Item1, loc);
3032 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3034 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3039 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3040 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3044 if (right_side != null) {
3045 e = e.ResolveLValue (ec, right_side);
3053 public override object Accept (StructuralVisitor visitor)
3055 return visitor.Visit (this);
3060 /// Represents a namespace or a type. The name of the class was inspired by
3061 /// section 10.8.1 (Fully Qualified Names).
3063 public abstract class FullNamedExpression : Expression
3065 protected override void CloneTo (CloneContext clonectx, Expression target)
3067 // Do nothing, most unresolved type expressions cannot be
3068 // resolved to different type
3071 public override bool ContainsEmitWithAwait ()
3076 public override Expression CreateExpressionTree (ResolveContext ec)
3078 throw new NotSupportedException ("ET");
3081 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3084 // This is used to resolve the expression as a type, a null
3085 // value will be returned if the expression is not a type
3088 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3090 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3095 TypeExpr te = fne as TypeExpr;
3097 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3105 var dep = type.GetMissingDependencies ();
3107 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3110 if (type.Kind == MemberKind.Void) {
3111 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3115 // Obsolete checks cannot be done when resolving base context as they
3116 // require type dependencies to be set but we are in process of resolving them
3118 if (mc is ResolveContext) {
3119 var oa = type.GetAttributeObsolete ();
3120 if (oa != null && !mc.IsObsolete)
3121 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3128 public override void Emit (EmitContext ec)
3130 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3131 GetSignatureForError ());
3136 /// Expression that evaluates to a type
3138 public abstract class TypeExpr : FullNamedExpression
3140 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3146 protected sealed override Expression DoResolve (ResolveContext ec)
3152 public override bool Equals (object obj)
3154 TypeExpr tobj = obj as TypeExpr;
3158 return Type == tobj.Type;
3161 public override int GetHashCode ()
3163 return Type.GetHashCode ();
3168 /// Fully resolved Expression that already evaluated to a type
3170 public class TypeExpression : TypeExpr
3172 public TypeExpression (TypeSpec t, Location l)
3175 eclass = ExprClass.Type;
3179 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3185 public class NamespaceExpression : FullNamedExpression
3187 readonly Namespace ns;
3189 public NamespaceExpression (Namespace ns, Location loc)
3192 this.Type = InternalType.Namespace;
3193 this.eclass = ExprClass.Namespace;
3197 public Namespace Namespace {
3203 protected override Expression DoResolve (ResolveContext rc)
3205 throw new NotImplementedException ();
3208 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3213 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3215 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3216 if (retval != null) {
3217 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3218 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3222 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3223 if (retval != null) {
3224 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3229 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3230 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3234 string assembly = null;
3235 string possible_name = Namespace.GetSignatureForError () + "." + name;
3237 // Only assembly unique name should be added
3238 switch (possible_name) {
3239 case "System.Drawing":
3240 case "System.Web.Services":
3243 case "System.Configuration":
3244 case "System.Data.Services":
3245 case "System.DirectoryServices":
3247 case "System.Net.Http":
3248 case "System.Numerics":
3249 case "System.Runtime.Caching":
3250 case "System.ServiceModel":
3251 case "System.Transactions":
3252 case "System.Web.Routing":
3253 case "System.Xml.Linq":
3255 assembly = possible_name;
3259 case "System.Linq.Expressions":
3260 assembly = "System.Core";
3263 case "System.Windows.Forms":
3264 case "System.Windows.Forms.Layout":
3265 assembly = "System.Windows.Forms";
3269 assembly = assembly == null ? "an" : "`" + assembly + "'";
3271 if (Namespace is GlobalRootNamespace) {
3272 ctx.Module.Compiler.Report.Error (400, loc,
3273 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3276 ctx.Module.Compiler.Report.Error (234, loc,
3277 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3278 name, GetSignatureForError (), assembly);
3282 public override string GetSignatureForError ()
3284 return ns.GetSignatureForError ();
3287 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3289 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3292 public override string ToString ()
3294 return Namespace.Name;
3299 /// This class denotes an expression which evaluates to a member
3300 /// of a struct or a class.
3302 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3304 protected bool conditional_access_receiver;
3307 // An instance expression associated with this member, if it's a
3308 // non-static member
3310 public Expression InstanceExpression;
3313 /// The name of this member.
3315 public abstract string Name {
3320 // When base.member is used
3322 public bool IsBase {
3323 get { return InstanceExpression is BaseThis; }
3327 /// Whether this is an instance member.
3329 public abstract bool IsInstance {
3334 /// Whether this is a static member.
3336 public abstract bool IsStatic {
3340 public abstract string KindName {
3344 public bool ConditionalAccess { get; set; }
3346 protected abstract TypeSpec DeclaringType {
3350 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3352 return InstanceExpression.Type;
3357 // Converts best base candidate for virtual method starting from QueriedBaseType
3359 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3362 // Only when base.member is used and method is virtual
3368 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3369 // means for base.member access we have to find the closest match after we found best candidate
3371 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3373 // The method could already be what we are looking for
3375 TypeSpec[] targs = null;
3376 if (method.DeclaringType != InstanceExpression.Type) {
3378 // Candidate can have inflated MVAR parameters and we need to find
3379 // base match for original definition not inflated parameter types
3381 var parameters = method.Parameters;
3382 if (method.Arity > 0) {
3383 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3384 var inflated = method.DeclaringType as InflatedTypeSpec;
3385 if (inflated != null) {
3386 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3390 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3391 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3392 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3393 if (base_override.IsGeneric)
3394 targs = method.TypeArguments;
3396 method = base_override;
3401 // When base access is used inside anonymous method/iterator/etc we need to
3402 // get back to the context of original type. We do it by emiting proxy
3403 // method in original class and rewriting base call to this compiler
3404 // generated method call which does the actual base invocation. This may
3405 // introduce redundant storey but with `this' only but it's tricky to avoid
3406 // at this stage as we don't know what expressions follow base
3408 if (rc.CurrentAnonymousMethod != null) {
3409 if (targs == null && method.IsGeneric) {
3410 targs = method.TypeArguments;
3411 method = method.GetGenericMethodDefinition ();
3414 if (method.Parameters.HasArglist)
3415 throw new NotImplementedException ("__arglist base call proxy");
3417 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3419 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3420 // get/set member expressions second call would fail to proxy because left expression
3421 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3422 // FIXME: The async check is another hack but will probably fail with mutators
3423 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3424 InstanceExpression = new This (loc).Resolve (rc);
3428 method = method.MakeGenericMethod (rc, targs);
3432 // Only base will allow this invocation to happen.
3434 if (method.IsAbstract) {
3435 rc.Report.SymbolRelatedToPreviousError (method);
3436 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3442 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3444 if (InstanceExpression == null)
3447 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3448 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3449 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3454 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3456 if (InstanceExpression == null)
3459 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3462 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3464 var ct = rc.CurrentType;
3465 if (ct == qualifier)
3468 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3471 qualifier = qualifier.GetDefinition ();
3472 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3479 public override bool ContainsEmitWithAwait ()
3481 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3484 public override bool HasConditionalAccess ()
3486 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3489 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3492 type = type.GetDefinition ();
3494 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3497 type = type.DeclaringType;
3498 } while (type != null);
3503 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3505 if (InstanceExpression != null) {
3506 InstanceExpression = InstanceExpression.Resolve (rc);
3507 CheckProtectedMemberAccess (rc, member);
3510 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3511 UnsafeError (rc, loc);
3514 var dep = member.GetMissingDependencies ();
3516 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3519 member.CheckObsoleteness (rc, loc);
3521 if (!(member is FieldSpec))
3522 member.MemberDefinition.SetIsUsed ();
3525 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3527 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3530 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3532 rc.Report.SymbolRelatedToPreviousError (member);
3533 rc.Report.Error (1540, loc,
3534 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3535 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3538 public override void FlowAnalysis (FlowAnalysisContext fc)
3540 if (InstanceExpression != null) {
3541 InstanceExpression.FlowAnalysis (fc);
3545 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3547 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3548 conditional_access_receiver = true;
3552 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3554 if (!ResolveInstanceExpressionCore (rc, rhs))
3558 // Check intermediate value modification which won't have any effect
3560 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3561 var fexpr = InstanceExpression as FieldExpr;
3562 if (fexpr != null) {
3563 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3566 if (fexpr.IsStatic) {
3567 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3568 fexpr.GetSignatureForError ());
3570 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3571 fexpr.GetSignatureForError ());
3577 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3578 if (rc.CurrentInitializerVariable != null) {
3579 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3580 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3582 rc.Report.Error (1612, loc,
3583 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3584 InstanceExpression.GetSignatureForError ());
3590 var lvr = InstanceExpression as LocalVariableReference;
3593 if (!lvr.local_info.IsReadonly)
3596 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3597 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3604 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3607 if (InstanceExpression != null) {
3608 if (InstanceExpression is TypeExpr) {
3609 var t = InstanceExpression.Type;
3611 t.CheckObsoleteness (rc, loc);
3613 t = t.DeclaringType;
3614 } while (t != null);
3616 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3617 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3618 rc.Report.Error (176, loc,
3619 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3620 GetSignatureForError ());
3624 InstanceExpression = null;
3630 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3631 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3632 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3633 rc.Report.Error (236, loc,
3634 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3635 GetSignatureForError ());
3637 var fe = this as FieldExpr;
3638 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3639 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3640 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3642 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3646 rc.Report.Error (120, loc,
3647 "An object reference is required to access non-static member `{0}'",
3648 GetSignatureForError ());
3652 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3656 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3657 rc.Report.Error (38, loc,
3658 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3659 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3662 InstanceExpression = new This (loc).Resolve (rc);
3666 var me = InstanceExpression as MemberExpr;
3668 me.ResolveInstanceExpressionCore (rc, rhs);
3670 var fe = me as FieldExpr;
3671 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3672 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3673 rc.Report.Warning (1690, 1, loc,
3674 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3675 me.GetSignatureForError ());
3682 // Additional checks for l-value member access
3685 if (InstanceExpression is UnboxCast) {
3686 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3693 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3695 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3696 ec.Report.Warning (1720, 1, left.Location,
3697 "Expression will always cause a `{0}'", "System.NullReferenceException");
3700 InstanceExpression = left;
3704 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3706 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3707 inst.Emit (ec, ConditionalAccess);
3709 if (prepare_for_load)
3710 ec.Emit (OpCodes.Dup);
3713 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3716 public class ExtensionMethodCandidates
3718 readonly NamespaceContainer container;
3719 readonly IList<MethodSpec> methods;
3721 readonly IMemberContext context;
3723 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3725 this.context = context;
3726 this.methods = methods;
3727 this.container = nsContainer;
3728 this.index = lookupIndex;
3731 public NamespaceContainer Container {
3737 public IMemberContext Context {
3743 public int LookupIndex {
3749 public IList<MethodSpec> Methods {
3757 // Represents a group of extension method candidates for whole namespace
3759 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3761 ExtensionMethodCandidates candidates;
3762 public Expression ExtensionExpression;
3764 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3765 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3767 this.candidates = candidates;
3768 this.ExtensionExpression = extensionExpr;
3771 public override bool IsStatic {
3772 get { return true; }
3776 // For extension methodgroup we are not looking for base members but parent
3777 // namespace extension methods
3779 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3781 // TODO: candidates are null only when doing error reporting, that's
3782 // incorrect. We have to discover same extension methods in error mode
3783 if (candidates == null)
3786 int arity = type_arguments == null ? 0 : type_arguments.Count;
3788 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3789 if (candidates == null)
3792 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3795 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3798 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3800 // LAMESPEC: or implicit type parameter conversion
3802 return argType == extensionType ||
3803 TypeSpecComparer.IsEqual (argType, extensionType) ||
3804 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3805 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3808 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3810 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3812 // Not included in C#6
3814 ExtensionExpression = ExtensionExpression.Resolve (rc);
3815 if (ExtensionExpression == null)
3818 var argType = ExtensionExpression.Type;
3819 foreach (MethodSpec candidate in Candidates) {
3820 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3824 // TODO: Scan full hierarchy
3826 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3831 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3833 // We are already here
3837 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3839 if (arguments == null)
3840 arguments = new Arguments (1);
3842 ExtensionExpression = ExtensionExpression.Resolve (ec);
3843 if (ExtensionExpression == null)
3846 var cand = candidates;
3847 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3848 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3849 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3851 // Restore candidates in case we are running in probing mode
3854 // Store resolved argument and restore original arguments
3856 // Clean-up modified arguments for error reporting
3857 arguments.RemoveAt (0);
3861 var me = ExtensionExpression as MemberExpr;
3863 me.ResolveInstanceExpression (ec, null);
3864 var fe = me as FieldExpr;
3866 fe.Spec.MemberDefinition.SetIsUsed ();
3869 InstanceExpression = null;
3873 #region IErrorHandler Members
3875 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3880 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3882 rc.Report.SymbolRelatedToPreviousError (best);
3885 rc.Report.Error (1929, loc,
3886 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3887 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3889 rc.Report.Error (1928, loc,
3890 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3891 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3897 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3902 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3911 /// MethodGroupExpr represents a group of method candidates which
3912 /// can be resolved to the best method overload
3914 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3916 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3918 protected IList<MemberSpec> Methods;
3919 MethodSpec best_candidate;
3920 TypeSpec best_candidate_return;
3921 protected TypeArguments type_arguments;
3923 SimpleName simple_name;
3924 protected TypeSpec queried_type;
3926 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3930 this.type = InternalType.MethodGroup;
3932 eclass = ExprClass.MethodGroup;
3933 queried_type = type;
3936 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3937 : this (new MemberSpec[] { m }, type, loc)
3943 public MethodSpec BestCandidate {
3945 return best_candidate;
3949 public TypeSpec BestCandidateReturnType {
3951 return best_candidate_return;
3955 public IList<MemberSpec> Candidates {
3961 protected override TypeSpec DeclaringType {
3963 return queried_type;
3967 public bool IsConditionallyExcluded {
3969 return Methods == Excluded;
3973 public override bool IsInstance {
3975 if (best_candidate != null)
3976 return !best_candidate.IsStatic;
3982 public override bool IsSideEffectFree {
3984 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3988 public override bool IsStatic {
3990 if (best_candidate != null)
3991 return best_candidate.IsStatic;
3997 public override string KindName {
3998 get { return "method"; }
4001 public override string Name {
4003 if (best_candidate != null)
4004 return best_candidate.Name;
4007 return Methods.First ().Name;
4014 // When best candidate is already know this factory can be used
4015 // to avoid expensive overload resolution to be called
4017 // NOTE: InstanceExpression has to be set manually
4019 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4021 return new MethodGroupExpr (best, queriedType, loc) {
4022 best_candidate = best,
4023 best_candidate_return = best.ReturnType
4027 public override string GetSignatureForError ()
4029 if (best_candidate != null)
4030 return best_candidate.GetSignatureForError ();
4032 return Methods.First ().GetSignatureForError ();
4035 public override Expression CreateExpressionTree (ResolveContext ec)
4037 if (best_candidate == null) {
4038 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4042 if (IsConditionallyExcluded)
4043 ec.Report.Error (765, loc,
4044 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4046 if (ConditionalAccess)
4047 Error_NullShortCircuitInsideExpressionTree (ec);
4049 return new TypeOfMethod (best_candidate, loc);
4052 protected override Expression DoResolve (ResolveContext ec)
4054 this.eclass = ExprClass.MethodGroup;
4056 if (InstanceExpression != null) {
4057 InstanceExpression = InstanceExpression.Resolve (ec);
4058 if (InstanceExpression == null)
4065 public override void Emit (EmitContext ec)
4067 throw new NotSupportedException ();
4070 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4072 var call = new CallEmitter ();
4073 call.InstanceExpression = InstanceExpression;
4074 call.ConditionalAccess = ConditionalAccess;
4077 call.EmitStatement (ec, best_candidate, arguments, loc);
4079 call.Emit (ec, best_candidate, arguments, loc);
4082 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4084 var ca = ec.ConditionalAccess;
4085 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4086 Statement = statement
4089 EmitCall (ec, arguments, statement);
4091 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4092 ec.ConditionalAccess = ca;
4095 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4097 if (target != InternalType.ErrorType) {
4098 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4099 Name, target.GetSignatureForError ());
4103 public bool HasAccessibleCandidate (ResolveContext rc)
4105 foreach (var candidate in Candidates) {
4106 if (candidate.IsAccessible (rc))
4113 public static bool IsExtensionMethodArgument (Expression expr)
4116 // LAMESPEC: No details about which expressions are not allowed
4118 return !(expr is TypeExpr) && !(expr is BaseThis);
4122 /// Find the Applicable Function Members (7.4.2.1)
4124 /// me: Method Group expression with the members to select.
4125 /// it might contain constructors or methods (or anything
4126 /// that maps to a method).
4128 /// Arguments: ArrayList containing resolved Argument objects.
4130 /// loc: The location if we want an error to be reported, or a Null
4131 /// location for "probing" purposes.
4133 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4134 /// that is the best match of me on Arguments.
4137 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4139 // TODO: causes issues with probing mode, remove explicit Kind check
4140 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4143 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4144 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4145 r.BaseMembersProvider = this;
4146 r.InstanceQualifier = this;
4149 if (cerrors != null)
4150 r.CustomErrors = cerrors;
4152 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4153 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4154 if (best_candidate == null) {
4155 if (!r.BestCandidateIsDynamic)
4158 if (simple_name != null && ec.IsStatic)
4159 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4164 // Overload resolver had to create a new method group, all checks bellow have already been executed
4165 if (r.BestCandidateNewMethodGroup != null)
4166 return r.BestCandidateNewMethodGroup;
4168 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4169 if (InstanceExpression != null) {
4170 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4171 InstanceExpression = null;
4173 if (simple_name != null && best_candidate.IsStatic) {
4174 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4177 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4181 ResolveInstanceExpression (ec, null);
4184 var base_override = CandidateToBaseOverride (ec, best_candidate);
4185 if (base_override == best_candidate) {
4186 best_candidate_return = r.BestCandidateReturnType;
4188 best_candidate = base_override;
4189 best_candidate_return = best_candidate.ReturnType;
4192 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4193 ConstraintChecker cc = new ConstraintChecker (ec);
4194 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4198 // Additional check for possible imported base override method which
4199 // could not be done during IsOverrideMethodBaseTypeAccessible
4201 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4202 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4203 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4204 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4207 // Speed up the check by not doing it on disallowed targets
4208 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4214 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4216 var fe = left as FieldExpr;
4219 // Using method-group on struct fields makes the struct assigned. I am not sure
4220 // why but that's what .net does
4222 fe.Spec.MemberDefinition.SetIsAssigned ();
4225 simple_name = original;
4226 return base.ResolveMemberAccess (ec, left, original);
4229 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4231 type_arguments = ta;
4234 #region IBaseMembersProvider Members
4236 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4238 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4241 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4243 if (queried_type == member.DeclaringType)
4246 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4247 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4251 // Extension methods lookup after ordinary methods candidates failed to apply
4253 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4255 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4258 if (!IsExtensionMethodArgument (InstanceExpression))
4261 int arity = type_arguments == null ? 0 : type_arguments.Count;
4262 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4263 if (methods == null)
4266 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4267 emg.SetTypeArguments (rc, type_arguments);
4268 emg.ConditionalAccess = ConditionalAccess;
4275 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4277 public ConstructorInstanceQualifier (TypeSpec type)
4280 InstanceType = type;
4283 public TypeSpec InstanceType { get; private set; }
4285 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4287 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4291 public struct OverloadResolver
4294 public enum Restrictions
4298 ProbingOnly = 1 << 1,
4299 CovariantDelegate = 1 << 2,
4300 NoBaseMembers = 1 << 3,
4301 BaseMembersIncluded = 1 << 4,
4302 GetEnumeratorLookup = 1 << 5
4305 public interface IBaseMembersProvider
4307 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4308 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4309 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4312 public interface IErrorHandler
4314 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4315 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4316 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4317 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4320 public interface IInstanceQualifier
4322 TypeSpec InstanceType { get; }
4323 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4326 sealed class NoBaseMembers : IBaseMembersProvider
4328 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4330 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4335 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4340 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4346 struct AmbiguousCandidate
4348 public readonly MemberSpec Member;
4349 public readonly bool Expanded;
4350 public readonly AParametersCollection Parameters;
4352 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4355 Parameters = parameters;
4356 Expanded = expanded;
4361 IList<MemberSpec> members;
4362 TypeArguments type_arguments;
4363 IBaseMembersProvider base_provider;
4364 IErrorHandler custom_errors;
4365 IInstanceQualifier instance_qualifier;
4366 Restrictions restrictions;
4367 MethodGroupExpr best_candidate_extension_group;
4368 TypeSpec best_candidate_return_type;
4370 SessionReportPrinter lambda_conv_msgs;
4372 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4373 : this (members, null, restrictions, loc)
4377 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4380 if (members == null || members.Count == 0)
4381 throw new ArgumentException ("empty members set");
4383 this.members = members;
4385 type_arguments = targs;
4386 this.restrictions = restrictions;
4387 if (IsDelegateInvoke)
4388 this.restrictions |= Restrictions.NoBaseMembers;
4390 base_provider = NoBaseMembers.Instance;
4395 public IBaseMembersProvider BaseMembersProvider {
4397 return base_provider;
4400 base_provider = value;
4404 public bool BestCandidateIsDynamic { get; set; }
4407 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4409 public MethodGroupExpr BestCandidateNewMethodGroup {
4411 return best_candidate_extension_group;
4416 // Return type can be different between best candidate and closest override
4418 public TypeSpec BestCandidateReturnType {
4420 return best_candidate_return_type;
4424 public IErrorHandler CustomErrors {
4426 return custom_errors;
4429 custom_errors = value;
4433 TypeSpec DelegateType {
4435 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4436 throw new InternalErrorException ("Not running in delegate mode", loc);
4438 return members [0].DeclaringType;
4442 public IInstanceQualifier InstanceQualifier {
4444 return instance_qualifier;
4447 instance_qualifier = value;
4451 bool IsProbingOnly {
4453 return (restrictions & Restrictions.ProbingOnly) != 0;
4457 bool IsDelegateInvoke {
4459 return (restrictions & Restrictions.DelegateInvoke) != 0;
4466 // 7.4.3.3 Better conversion from expression
4467 // Returns : 1 if a->p is better,
4468 // 2 if a->q is better,
4469 // 0 if neither is better
4471 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4473 TypeSpec argument_type = a.Type;
4476 // Exactly matching Expression phase
4480 // If argument is an anonymous function
4482 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4484 // p and q are delegate types or expression tree types
4486 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4487 if (q.MemberDefinition != p.MemberDefinition) {
4492 // Uwrap delegate from Expression<T>
4494 q = TypeManager.GetTypeArguments (q) [0];
4495 p = TypeManager.GetTypeArguments (p) [0];
4498 var p_m = Delegate.GetInvokeMethod (p);
4499 var q_m = Delegate.GetInvokeMethod (q);
4502 // With identical parameter lists
4504 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4512 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4514 if (p.Kind == MemberKind.Void) {
4515 return q.Kind != MemberKind.Void ? 2 : 0;
4519 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4521 if (q.Kind == MemberKind.Void) {
4522 return p.Kind != MemberKind.Void ? 1 : 0;
4525 var am = (AnonymousMethodExpression)a.Expr;
4528 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4529 // better conversion is performed between underlying types Y1 and Y2
4531 if (p.IsGenericTask || q.IsGenericTask) {
4532 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4533 q = q.TypeArguments [0];
4534 p = p.TypeArguments [0];
4540 // An inferred return type X exists for E in the context of the parameter list, and
4541 // an identity conversion exists from X to the return type of D
4543 var inferred_type = am.InferReturnType (ec, null, orig_q);
4544 if (inferred_type != null) {
4545 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4546 inferred_type = ec.BuiltinTypes.Object;
4548 if (inferred_type == p)
4551 if (inferred_type == q)
4557 if (argument_type == p)
4560 if (argument_type == q)
4563 return IsBetterConversionTarget (ec, p, q);
4566 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4568 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4570 if (p.Kind != MemberKind.Delegate) {
4571 p = TypeManager.GetTypeArguments (p) [0];
4574 if (q.Kind != MemberKind.Delegate) {
4575 q = TypeManager.GetTypeArguments (q) [0];
4578 var p_m = Delegate.GetInvokeMethod (p);
4579 var q_m = Delegate.GetInvokeMethod (q);
4585 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4587 if (p.Kind == MemberKind.Void) {
4588 return q.Kind != MemberKind.Void ? 2 : 0;
4592 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4594 if (q.Kind == MemberKind.Void) {
4595 return p.Kind != MemberKind.Void ? 1 : 0;
4598 return IsBetterConversionTarget (rc, p, q);
4601 if (p.IsGenericTask && q.IsGenericTask) {
4602 q = q.TypeArguments [0];
4603 p = p.TypeArguments [0];
4604 return IsBetterConversionTarget (rc, p, q);
4608 if (p.IsNullableType) {
4609 p = Nullable.NullableInfo.GetUnderlyingType (p);
4610 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4611 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4614 // Spec expects implicit conversion check between p and q, q and p
4615 // to be done before nullable unwrapping but that's expensive operation.
4617 // Extra manual tweak is needed because BetterTypeConversion works on
4625 if (q.IsNullableType) {
4626 q = Nullable.NullableInfo.GetUnderlyingType (q);
4627 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4628 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4634 return BetterTypeConversion (rc, p, q);
4638 // 7.4.3.4 Better conversion from type
4640 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4642 if (p == null || q == null)
4643 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4645 switch (p.BuiltinType) {
4646 case BuiltinTypeSpec.Type.Int:
4647 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4650 case BuiltinTypeSpec.Type.Long:
4651 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4654 case BuiltinTypeSpec.Type.SByte:
4655 switch (q.BuiltinType) {
4656 case BuiltinTypeSpec.Type.Byte:
4657 case BuiltinTypeSpec.Type.UShort:
4658 case BuiltinTypeSpec.Type.UInt:
4659 case BuiltinTypeSpec.Type.ULong:
4663 case BuiltinTypeSpec.Type.Short:
4664 switch (q.BuiltinType) {
4665 case BuiltinTypeSpec.Type.UShort:
4666 case BuiltinTypeSpec.Type.UInt:
4667 case BuiltinTypeSpec.Type.ULong:
4671 case BuiltinTypeSpec.Type.Dynamic:
4672 // LAMESPEC: Dynamic conversions is not considered
4673 p = ec.Module.Compiler.BuiltinTypes.Object;
4677 switch (q.BuiltinType) {
4678 case BuiltinTypeSpec.Type.Int:
4679 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4682 case BuiltinTypeSpec.Type.Long:
4683 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4686 case BuiltinTypeSpec.Type.SByte:
4687 switch (p.BuiltinType) {
4688 case BuiltinTypeSpec.Type.Byte:
4689 case BuiltinTypeSpec.Type.UShort:
4690 case BuiltinTypeSpec.Type.UInt:
4691 case BuiltinTypeSpec.Type.ULong:
4695 case BuiltinTypeSpec.Type.Short:
4696 switch (p.BuiltinType) {
4697 case BuiltinTypeSpec.Type.UShort:
4698 case BuiltinTypeSpec.Type.UInt:
4699 case BuiltinTypeSpec.Type.ULong:
4703 case BuiltinTypeSpec.Type.Dynamic:
4704 // LAMESPEC: Dynamic conversions is not considered
4705 q = ec.Module.Compiler.BuiltinTypes.Object;
4709 return BetterTypeConversionImplicitConversion (ec, p, q);
4712 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4714 // TODO: this is expensive
4715 Expression p_tmp = new EmptyExpression (p);
4716 Expression q_tmp = new EmptyExpression (q);
4718 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4719 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4721 if (p_to_q && !q_to_p)
4724 if (q_to_p && !p_to_q)
4731 /// Determines "Better function" between candidate
4732 /// and the current best match
4735 /// Returns a boolean indicating :
4736 /// false if candidate ain't better
4737 /// true if candidate is better than the current best match
4739 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4740 MemberSpec best, AParametersCollection bparam, bool best_params)
4742 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4743 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4745 int candidate_better_count = 0;
4746 int best_better_count = 0;
4748 bool are_equivalent = true;
4749 int args_count = args == null ? 0 : args.Count;
4753 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4756 // Default arguments are ignored for better decision
4757 if (a.IsDefaultArgument)
4761 // When comparing named argument the parameter type index has to be looked up
4762 // in original parameter set (override version for virtual members)
4764 NamedArgument na = a as NamedArgument;
4766 int idx = cparam.GetParameterIndexByName (na.Name);
4767 ct = candidate_pd.Types[idx];
4768 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4769 ct = TypeManager.GetElementType (ct);
4771 idx = bparam.GetParameterIndexByName (na.Name);
4772 bt = best_pd.Types[idx];
4773 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4774 bt = TypeManager.GetElementType (bt);
4776 ct = candidate_pd.Types[c_idx];
4777 bt = best_pd.Types[b_idx];
4779 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4780 ct = TypeManager.GetElementType (ct);
4784 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4785 bt = TypeManager.GetElementType (bt);
4790 if (TypeSpecComparer.IsEqual (ct, bt))
4793 are_equivalent = false;
4794 int result = BetterExpressionConversion (ec, a, ct, bt);
4796 // for each argument, the conversion to 'ct' should be no worse than
4797 // the conversion to 'bt'.
4800 // No optional parameters tie breaking rules for delegates overload resolution
4802 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4805 ++best_better_count;
4809 // for at least one argument, the conversion to 'ct' should be better than
4810 // the conversion to 'bt'.
4812 ++candidate_better_count;
4815 if (candidate_better_count != 0 && best_better_count == 0)
4818 if (best_better_count > 0 && candidate_better_count == 0)
4822 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4824 if (!are_equivalent) {
4825 while (j < args_count && !args [j++].IsDefaultArgument) ;
4828 // A candidate with no default parameters is still better when there
4829 // is no better expression conversion
4831 if (candidate_pd.Count < best_pd.Count) {
4832 if (!candidate_params && !candidate_pd.FixedParameters [j - j].HasDefaultValue) {
4835 } else if (candidate_pd.Count == best_pd.Count) {
4836 if (candidate_params)
4839 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4842 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4850 // If candidate is applicable in its normal form and best has a params array and is applicable
4851 // only in its expanded form, then candidate is better
4853 if (candidate_params != best_params)
4854 return !candidate_params;
4857 // We have not reached end of parameters list due to params or used default parameters
4859 bool defaults_ambiguity = false;
4860 while (j < candidate_pd.Count && j < best_pd.Count) {
4861 var cand_param = candidate_pd.FixedParameters [j];
4862 var best_param = best_pd.FixedParameters [j];
4864 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4865 return cand_param.HasDefaultValue;
4867 defaults_ambiguity = true;
4868 if (candidate_pd.Count == best_pd.Count) {
4872 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4873 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4875 if (cand_param.HasDefaultValue) {
4884 // Neither is better when not all arguments are provided
4886 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4887 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4888 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4893 if (candidate_pd.Count != best_pd.Count) {
4894 if (defaults_ambiguity && best_pd.Count - 1 == j)
4895 return best_pd.HasParams;
4897 return candidate_pd.Count < best_pd.Count;
4901 // One is a non-generic method and second is a generic method, then non-generic is better
4903 if (best.IsGeneric != candidate.IsGeneric)
4904 return best.IsGeneric;
4907 // Both methods have the same number of parameters, and the parameters have equal types
4908 // Pick the "more specific" signature using rules over original (non-inflated) types
4910 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4911 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4913 bool specific_at_least_once = false;
4914 for (j = 0; j < args_count; ++j) {
4915 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4917 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4918 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4920 ct = candidate_def_pd.Types[j];
4921 bt = best_def_pd.Types[j];
4926 TypeSpec specific = MoreSpecific (ct, bt);
4930 specific_at_least_once = true;
4933 if (specific_at_least_once)
4939 static bool CheckInflatedArguments (MethodSpec ms)
4941 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4944 // Setup constraint checker for probing only
4945 ConstraintChecker cc = new ConstraintChecker (null);
4947 var mp = ms.Parameters.Types;
4948 for (int i = 0; i < mp.Length; ++i) {
4949 var type = mp[i] as InflatedTypeSpec;
4953 var targs = type.TypeArguments;
4954 if (targs.Length == 0)
4957 // TODO: Checking inflated MVAR arguments should be enough
4958 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4965 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4967 rc.Report.Error (1729, loc,
4968 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4969 type.GetSignatureForError (), argCount.ToString ());
4973 // Determines if the candidate method is applicable to the given set of arguments
4974 // There could be two different set of parameters for same candidate where one
4975 // is the closest override for default values and named arguments checks and second
4976 // one being the virtual base for the parameter types and modifiers.
4978 // A return value rates candidate method compatibility,
4980 // 0 = the best, int.MaxValue = the worst
4982 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)
4985 // Each step has allocated 10 values, it can overflow for
4986 // more than 10 arguments but that's ok as it's used for
4987 // better error reporting only
4989 const int ArgumentCountMismatch = 1000000000;
4990 const int NamedArgumentsMismatch = 100000000;
4991 const int DefaultArgumentMismatch = 10000000;
4992 const int UnexpectedTypeArguments = 1000000;
4993 const int TypeArgumentsMismatch = 100000;
4994 const int InflatedTypesMismatch = 10000;
4996 // Parameters of most-derived type used mainly for named and optional parameters
4997 var pd = pm.Parameters;
4999 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
5000 // params modifier instead of most-derived type
5001 var cpd = ((IParametersMember) candidate).Parameters;
5002 int param_count = pd.Count;
5003 int optional_count = 0;
5005 Arguments orig_args = arguments;
5007 if (arg_count != param_count) {
5009 // No arguments expansion when doing exact match for delegates
5011 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5012 for (int i = 0; i < pd.Count; ++i) {
5013 if (pd.FixedParameters[i].HasDefaultValue) {
5014 optional_count = pd.Count - i;
5020 if (optional_count != 0) {
5021 // Readjust expected number when params used
5022 if (cpd.HasParams) {
5024 if (arg_count < param_count)
5026 } else if (arg_count > param_count) {
5027 int args_gap = System.Math.Abs (arg_count - param_count);
5028 return ArgumentCountMismatch + args_gap;
5029 } else if (arg_count < param_count - optional_count) {
5030 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5031 return ArgumentCountMismatch + args_gap;
5033 } else if (arg_count != param_count) {
5034 int args_gap = System.Math.Abs (arg_count - param_count);
5036 return ArgumentCountMismatch + args_gap;
5037 if (arg_count < param_count - 1)
5038 return ArgumentCountMismatch + args_gap;
5041 // Resize to fit optional arguments
5042 if (optional_count != 0) {
5043 if (arguments == null) {
5044 arguments = new Arguments (optional_count);
5046 // Have to create a new container, so the next run can do same
5047 var resized = new Arguments (param_count);
5048 resized.AddRange (arguments);
5049 arguments = resized;
5052 for (int i = arg_count; i < param_count; ++i)
5053 arguments.Add (null);
5057 if (arg_count > 0) {
5059 // Shuffle named arguments to the right positions if there are any
5061 if (arguments[arg_count - 1] is NamedArgument) {
5062 arg_count = arguments.Count;
5064 for (int i = 0; i < arg_count; ++i) {
5065 bool arg_moved = false;
5067 NamedArgument na = arguments[i] as NamedArgument;
5071 int index = pd.GetParameterIndexByName (na.Name);
5073 // Named parameter not found
5075 return NamedArgumentsMismatch - i;
5077 // already reordered
5082 if (index >= param_count) {
5083 // When using parameters which should not be available to the user
5084 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5087 arguments.Add (null);
5091 if (index == arg_count)
5092 return NamedArgumentsMismatch - i - 1;
5094 temp = arguments [index];
5096 // The slot has been taken by positional argument
5097 if (temp != null && !(temp is NamedArgument))
5102 arguments = arguments.MarkOrderedArgument (na);
5106 if (arguments == orig_args) {
5107 arguments = new Arguments (orig_args.Count);
5108 arguments.AddRange (orig_args);
5111 arguments[index] = arguments[i];
5112 arguments[i] = temp;
5119 arg_count = arguments.Count;
5121 } else if (arguments != null) {
5122 arg_count = arguments.Count;
5126 // Don't do any expensive checks when the candidate cannot succeed
5128 if (arg_count != param_count && !cpd.HasParams)
5129 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5131 var dep = candidate.GetMissingDependencies ();
5133 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5138 // 1. Handle generic method using type arguments when specified or type inference
5141 var ms = candidate as MethodSpec;
5142 if (ms != null && ms.IsGeneric) {
5143 if (type_arguments != null) {
5144 var g_args_count = ms.Arity;
5145 if (g_args_count != type_arguments.Count)
5146 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5148 if (type_arguments.Arguments != null)
5149 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5152 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5153 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5154 // candidate was found use the set to report more details about what was wrong with lambda body.
5155 // The general idea is to distinguish between code errors and errors caused by
5156 // trial-and-error type inference
5158 if (lambda_conv_msgs == null) {
5159 for (int i = 0; i < arg_count; i++) {
5160 Argument a = arguments[i];
5164 var am = a.Expr as AnonymousMethodExpression;
5166 if (lambda_conv_msgs == null)
5167 lambda_conv_msgs = new SessionReportPrinter ();
5169 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5174 var ti = new TypeInference (arguments);
5175 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5178 return TypeArgumentsMismatch - ti.InferenceScore;
5181 // Clear any error messages when the result was success
5183 if (lambda_conv_msgs != null)
5184 lambda_conv_msgs.ClearSession ();
5186 if (i_args.Length != 0) {
5188 for (int i = 0; i < i_args.Length; ++i) {
5189 var ta = i_args [i];
5190 if (!ta.IsAccessible (ec))
5191 return TypeArgumentsMismatch - i;
5195 ms = ms.MakeGenericMethod (ec, i_args);
5200 // Type arguments constraints have to match for the method to be applicable
5202 if (!CheckInflatedArguments (ms)) {
5204 return InflatedTypesMismatch;
5208 // We have a generic return type and at same time the method is override which
5209 // means we have to also inflate override return type in case the candidate is
5210 // best candidate and override return type is different to base return type.
5212 // virtual Foo<T, object> with override Foo<T, dynamic>
5214 if (candidate != pm) {
5215 MethodSpec override_ms = (MethodSpec) pm;
5216 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5217 returnType = inflator.Inflate (returnType);
5219 returnType = ms.ReturnType;
5226 if (type_arguments != null)
5227 return UnexpectedTypeArguments;
5233 // 2. Each argument has to be implicitly convertible to method parameter
5235 Parameter.Modifier p_mod = 0;
5238 for (int i = 0; i < arg_count; i++) {
5239 Argument a = arguments[i];
5241 var fp = pd.FixedParameters[i];
5242 if (!fp.HasDefaultValue) {
5243 arguments = orig_args;
5244 return arg_count * 2 + 2;
5248 // Get the default value expression, we can use the same expression
5249 // if the type matches
5251 Expression e = fp.DefaultValue;
5253 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5255 // Restore for possible error reporting
5256 for (int ii = i; ii < arg_count; ++ii)
5257 arguments.RemoveAt (i);
5259 return (arg_count - i) * 2 + 1;
5263 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5265 // LAMESPEC: Attributes can be mixed together with build-in priority
5267 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5268 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5269 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5270 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5271 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5272 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5276 arguments[i] = new Argument (e, Argument.AType.Default);
5280 if (p_mod != Parameter.Modifier.PARAMS) {
5281 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5283 } else if (!params_expanded_form) {
5284 params_expanded_form = true;
5285 pt = ((ElementTypeSpec) pt).Element;
5291 if (!params_expanded_form) {
5292 if (a.IsExtensionType) {
5293 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5298 score = IsArgumentCompatible (ec, a, p_mod, pt);
5301 dynamicArgument = true;
5306 // It can be applicable in expanded form (when not doing exact match like for delegates)
5308 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5309 if (!params_expanded_form) {
5310 pt = ((ElementTypeSpec) pt).Element;
5314 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5317 params_expanded_form = true;
5318 dynamicArgument = true;
5319 } else if (score == 0 || arg_count > pd.Count) {
5320 params_expanded_form = true;
5325 if (params_expanded_form)
5327 return (arg_count - i) * 2 + score;
5332 // Restore original arguments for dynamic binder to keep the intention of original source code
5334 if (dynamicArgument)
5335 arguments = orig_args;
5340 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5342 if (e is Constant && e.Type == ptype)
5346 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5348 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5349 e = new MemberAccess (new MemberAccess (new MemberAccess (
5350 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5351 } else if (e is Constant) {
5353 // Handles int to int? conversions, DefaultParameterValue check
5355 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5359 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5362 return e.Resolve (ec);
5366 // Tests argument compatibility with the parameter
5367 // The possible return values are
5369 // 1 - modifier mismatch
5370 // 2 - type mismatch
5371 // -1 - dynamic binding required
5373 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5376 // Types have to be identical when ref or out modifer
5377 // is used and argument is not of dynamic type
5379 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5380 var arg_type = argument.Type;
5382 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5384 // Using dynamic for ref/out parameter can still succeed at runtime
5386 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5392 if (arg_type != parameter) {
5393 if (arg_type == InternalType.VarOutType)
5397 // Do full equality check after quick path
5399 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5401 // Using dynamic for ref/out parameter can still succeed at runtime
5403 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5411 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5415 // Use implicit conversion in all modes to return same candidates when the expression
5416 // is used as argument or delegate conversion
5418 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5419 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5426 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5428 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5430 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5433 var ac_p = p as ArrayContainer;
5435 var ac_q = q as ArrayContainer;
5439 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5440 if (specific == ac_p.Element)
5442 if (specific == ac_q.Element)
5444 } else if (p.IsGeneric && q.IsGeneric) {
5445 var pargs = TypeManager.GetTypeArguments (p);
5446 var qargs = TypeManager.GetTypeArguments (q);
5448 bool p_specific_at_least_once = false;
5449 bool q_specific_at_least_once = false;
5451 for (int i = 0; i < pargs.Length; i++) {
5452 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5453 if (specific == pargs[i])
5454 p_specific_at_least_once = true;
5455 if (specific == qargs[i])
5456 q_specific_at_least_once = true;
5459 if (p_specific_at_least_once && !q_specific_at_least_once)
5461 if (!p_specific_at_least_once && q_specific_at_least_once)
5469 // Find the best method from candidate list
5471 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5473 List<AmbiguousCandidate> ambiguous_candidates = null;
5475 MemberSpec best_candidate;
5476 Arguments best_candidate_args = null;
5477 bool best_candidate_params = false;
5478 bool best_candidate_dynamic = false;
5479 int best_candidate_rate;
5480 IParametersMember best_parameter_member = null;
5482 int args_count = args != null ? args.Count : 0;
5484 Arguments candidate_args = args;
5485 bool error_mode = false;
5486 MemberSpec invocable_member = null;
5487 int applicable_candidates = 0;
5490 best_candidate = null;
5491 best_candidate_rate = int.MaxValue;
5493 var type_members = members;
5495 for (int i = 0; i < type_members.Count; ++i) {
5496 var member = type_members[i];
5499 // Methods in a base class are not candidates if any method in a derived
5500 // class is applicable
5502 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5506 if (!member.IsAccessible (rc))
5509 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5512 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5513 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5518 IParametersMember pm = member as IParametersMember;
5521 // Will use it later to report ambiguity between best method and invocable member
5523 if (Invocation.IsMemberInvocable (member))
5524 invocable_member = member;
5530 // Overload resolution is looking for base member but using parameter names
5531 // and default values from the closest member. That means to do expensive lookup
5532 // for the closest override for virtual or abstract members
5534 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5535 var override_params = base_provider.GetOverrideMemberParameters (member);
5536 if (override_params != null)
5537 pm = override_params;
5541 // Check if the member candidate is applicable
5543 bool params_expanded_form = false;
5544 bool dynamic_argument = false;
5545 TypeSpec rt = pm.MemberType;
5546 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5548 if (lambda_conv_msgs != null)
5549 lambda_conv_msgs.EndSession ();
5552 // How does it score compare to others
5554 if (candidate_rate < best_candidate_rate) {
5556 // Fatal error (missing dependency), cannot continue
5557 if (candidate_rate < 0)
5560 applicable_candidates = 1;
5561 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5562 // Only parameterless methods are considered
5564 best_candidate_rate = candidate_rate;
5565 best_candidate = member;
5566 best_candidate_args = candidate_args;
5567 best_candidate_params = params_expanded_form;
5568 best_candidate_dynamic = dynamic_argument;
5569 best_parameter_member = pm;
5570 best_candidate_return_type = rt;
5572 } else if (candidate_rate == 0) {
5574 // The member look is done per type for most operations but sometimes
5575 // it's not possible like for binary operators overload because they
5576 // are unioned between 2 sides
5578 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5579 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5583 ++applicable_candidates;
5585 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5587 // We pack all interface members into top level type which makes the overload resolution
5588 // more complicated for interfaces. We compensate it by removing methods with same
5589 // signature when building the cache hence this path should not really be hit often
5592 // interface IA { void Foo (int arg); }
5593 // interface IB : IA { void Foo (params int[] args); }
5595 // IB::Foo is the best overload when calling IB.Foo (1)
5598 if (ambiguous_candidates != null) {
5599 foreach (var amb_cand in ambiguous_candidates) {
5600 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5609 ambiguous_candidates = null;
5612 // Is the new candidate better
5613 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5617 best_candidate = member;
5618 best_candidate_args = candidate_args;
5619 best_candidate_params = params_expanded_form;
5620 best_candidate_dynamic = dynamic_argument;
5621 best_parameter_member = pm;
5622 best_candidate_return_type = rt;
5624 // It's not better but any other found later could be but we are not sure yet
5625 if (ambiguous_candidates == null)
5626 ambiguous_candidates = new List<AmbiguousCandidate> ();
5628 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5632 // Restore expanded arguments
5633 candidate_args = args;
5635 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5638 // We've found exact match
5640 if (best_candidate_rate == 0)
5644 // Try extension methods lookup when no ordinary method match was found and provider enables it
5647 var emg = base_provider.LookupExtensionMethod (rc);
5649 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5651 best_candidate_extension_group = emg;
5652 return (T) (MemberSpec) emg.BestCandidate;
5657 // Don't run expensive error reporting mode for probing
5664 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5667 lambda_conv_msgs = null;
5672 // No best member match found, report an error
5674 if (best_candidate_rate != 0 || error_mode) {
5675 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5679 if (best_candidate_dynamic) {
5680 if (args[0].IsExtensionType) {
5681 rc.Report.Error (1973, loc,
5682 "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",
5683 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5687 // Check type constraints only when explicit type arguments are used
5689 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5690 MethodSpec bc = best_candidate as MethodSpec;
5691 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5692 ConstraintChecker cc = new ConstraintChecker (rc);
5693 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5697 BestCandidateIsDynamic = true;
5702 // These flags indicates we are running delegate probing conversion. No need to
5703 // do more expensive checks
5705 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5706 return (T) best_candidate;
5708 if (ambiguous_candidates != null) {
5710 // Now check that there are no ambiguities i.e the selected method
5711 // should be better than all the others
5713 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5714 var candidate = ambiguous_candidates [ix];
5716 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5717 var ambiguous = candidate.Member;
5718 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5719 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5720 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5721 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5722 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5725 return (T) best_candidate;
5730 if (invocable_member != null && !IsProbingOnly) {
5731 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5732 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5733 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5734 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5738 // And now check if the arguments are all
5739 // compatible, perform conversions if
5740 // necessary etc. and return if everything is
5743 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5746 if (best_candidate == null)
5750 // Don't run possibly expensive checks in probing mode
5752 if (!IsProbingOnly && !rc.IsInProbingMode) {
5754 // Check ObsoleteAttribute on the best method
5756 best_candidate.CheckObsoleteness (rc, loc);
5758 best_candidate.MemberDefinition.SetIsUsed ();
5761 args = best_candidate_args;
5762 return (T) best_candidate;
5765 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5767 return ResolveMember<MethodSpec> (rc, ref args);
5770 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5771 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5773 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5776 if (a.Type == InternalType.ErrorType)
5779 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5780 ec.Report.SymbolRelatedToPreviousError (method);
5781 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5782 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5783 TypeManager.CSharpSignature (method));
5786 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5787 TypeManager.CSharpSignature (method));
5788 } else if (IsDelegateInvoke) {
5789 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5790 DelegateType.GetSignatureForError ());
5792 ec.Report.SymbolRelatedToPreviousError (method);
5793 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5794 method.GetSignatureForError ());
5797 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5799 string index = (idx + 1).ToString ();
5800 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5801 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5802 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5803 index, Parameter.GetModifierSignature (a.Modifier));
5805 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5806 index, Parameter.GetModifierSignature (mod));
5808 string p1 = a.GetSignatureForError ();
5809 string p2 = paramType.GetSignatureForError ();
5812 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5813 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5816 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5817 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5818 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5821 ec.Report.Error (1503, a.Expr.Location,
5822 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5827 // We have failed to find exact match so we return error info about the closest match
5829 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5831 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5832 int arg_count = args == null ? 0 : args.Count;
5834 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5835 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5836 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5840 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5845 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5846 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5847 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5851 // For candidates which match on parameters count report more details about incorrect arguments
5854 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5855 // Reject any inaccessible member
5856 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5857 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5858 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5862 var ms = best_candidate as MethodSpec;
5863 if (ms != null && ms.IsGeneric) {
5864 bool constr_ok = true;
5865 if (ms.TypeArguments != null)
5866 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5868 if (ta_count == 0 && ms.TypeArguments == null) {
5869 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5873 rc.Report.Error (411, loc,
5874 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5875 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5882 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5888 // We failed to find any method with correct argument count, report best candidate
5890 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5893 if (best_candidate.Kind == MemberKind.Constructor) {
5894 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5895 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5896 } else if (IsDelegateInvoke) {
5897 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5898 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5899 DelegateType.GetSignatureForError (), arg_count.ToString ());
5901 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5902 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5903 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5904 name, arg_count.ToString ());
5908 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5910 var p = ((IParametersMember)best_candidate).Parameters;
5915 for (int i = p.Count - 1; i != 0; --i) {
5916 var fp = p.FixedParameters [i];
5917 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5927 foreach (var arg in args) {
5928 var na = arg as NamedArgument;
5932 if (na.Name == name) {
5941 return args.Count + 1 == pm.Parameters.Count;
5944 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5946 var pd = pm.Parameters;
5947 var cpd = ((IParametersMember) member).Parameters;
5948 var ptypes = cpd.Types;
5950 Parameter.Modifier p_mod = 0;
5952 int a_idx = 0, a_pos = 0;
5954 ArrayInitializer params_initializers = null;
5955 bool has_unsafe_arg = pm.MemberType.IsPointer;
5956 int arg_count = args == null ? 0 : args.Count;
5958 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5963 if (p_mod != Parameter.Modifier.PARAMS) {
5964 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5966 has_unsafe_arg |= pt.IsPointer;
5968 if (p_mod == Parameter.Modifier.PARAMS) {
5969 if (chose_params_expanded) {
5970 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5971 pt = TypeManager.GetElementType (pt);
5977 // Types have to be identical when ref or out modifer is used
5979 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5980 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5983 var arg_type = a.Type;
5987 if (arg_type == InternalType.VarOutType) {
5989 // Set underlying variable type based on parameter type
5991 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5995 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5999 NamedArgument na = a as NamedArgument;
6001 int name_index = pd.GetParameterIndexByName (na.Name);
6002 if (name_index < 0 || name_index >= pd.Count) {
6003 if (IsDelegateInvoke) {
6004 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6005 ec.Report.Error (1746, na.Location,
6006 "The delegate `{0}' does not contain a parameter named `{1}'",
6007 DelegateType.GetSignatureForError (), na.Name);
6009 ec.Report.SymbolRelatedToPreviousError (member);
6010 ec.Report.Error (1739, na.Location,
6011 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6012 TypeManager.CSharpSignature (member), na.Name);
6014 } else if (args[name_index] != a && args[name_index] != null) {
6015 if (IsDelegateInvoke)
6016 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6018 ec.Report.SymbolRelatedToPreviousError (member);
6020 ec.Report.Error (1744, na.Location,
6021 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6026 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6029 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6030 if (a.IsExtensionType) {
6031 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6032 // CS1061 but that still better than confusing CS0123
6033 var ma = new MemberAccess (a.Expr, member.Name, loc);
6034 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6036 custom_errors.NoArgumentMatch (ec, member);
6042 if (a.IsExtensionType) {
6043 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6046 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6048 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6051 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6058 // Convert params arguments to an array initializer
6060 if (params_initializers != null) {
6061 // we choose to use 'a.Expr' rather than 'conv' so that
6062 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6063 params_initializers.Add (a.Expr);
6064 args.RemoveAt (a_idx--);
6070 // Update the argument with the implicit conversion
6074 if (a_idx != arg_count) {
6076 // Convert all var out argument to error type for less confusing error reporting
6077 // when no matching overload is found
6079 for (; a_idx < arg_count; a_idx++) {
6080 var arg = args [a_idx];
6084 if (arg.Type == InternalType.VarOutType) {
6085 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6089 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6094 // Fill not provided arguments required by params modifier
6096 if (params_initializers == null && arg_count + 1 == pd.Count) {
6098 args = new Arguments (1);
6100 pt = ptypes[pd.Count - 1];
6101 pt = TypeManager.GetElementType (pt);
6102 has_unsafe_arg |= pt.IsPointer;
6103 params_initializers = new ArrayInitializer (0, loc);
6107 // Append an array argument with all params arguments
6109 if (params_initializers != null) {
6110 args.Add (new Argument (
6111 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6115 if (has_unsafe_arg && !ec.IsUnsafe) {
6116 Expression.UnsafeError (ec, loc);
6120 // We could infer inaccesible type arguments
6122 if (type_arguments == null && member.IsGeneric) {
6123 var ms = (MethodSpec) member;
6124 foreach (var ta in ms.TypeArguments) {
6125 if (!ta.IsAccessible (ec)) {
6126 ec.Report.SymbolRelatedToPreviousError (ta);
6127 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6137 public class ConstantExpr : MemberExpr
6139 readonly ConstSpec constant;
6141 public ConstantExpr (ConstSpec constant, Location loc)
6143 this.constant = constant;
6147 public override string Name {
6148 get { throw new NotImplementedException (); }
6151 public override string KindName {
6152 get { return "constant"; }
6155 public override bool IsInstance {
6156 get { return !IsStatic; }
6159 public override bool IsStatic {
6160 get { return true; }
6163 protected override TypeSpec DeclaringType {
6164 get { return constant.DeclaringType; }
6167 public override Expression CreateExpressionTree (ResolveContext ec)
6169 throw new NotSupportedException ("ET");
6172 protected override Expression DoResolve (ResolveContext rc)
6174 ResolveInstanceExpression (rc, null);
6175 DoBestMemberChecks (rc, constant);
6177 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6178 eclass = ExprClass.Value;
6179 type = constant.MemberType;
6183 var c = constant.GetConstant (rc);
6185 // Creates reference expression to the constant value
6186 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6189 public override void Emit (EmitContext ec)
6191 throw new NotSupportedException ();
6194 public override string GetSignatureForError ()
6196 return constant.GetSignatureForError ();
6199 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6201 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6206 // Fully resolved expression that references a Field
6208 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6210 protected FieldSpec spec;
6211 VariableInfo variable_info;
6213 LocalTemporary temp;
6216 protected FieldExpr (Location l)
6221 public FieldExpr (FieldSpec spec, Location loc)
6226 type = spec.MemberType;
6229 public FieldExpr (FieldBase fi, Location l)
6236 public override string Name {
6242 public bool IsHoisted {
6244 IVariableReference hv = InstanceExpression as IVariableReference;
6245 return hv != null && hv.IsHoisted;
6249 public override bool IsInstance {
6251 return !spec.IsStatic;
6255 public override bool IsStatic {
6257 return spec.IsStatic;
6261 public override string KindName {
6262 get { return "field"; }
6265 public FieldSpec Spec {
6271 protected override TypeSpec DeclaringType {
6273 return spec.DeclaringType;
6277 public VariableInfo VariableInfo {
6279 return variable_info;
6285 public override string GetSignatureForError ()
6287 return spec.GetSignatureForError ();
6290 public bool IsMarshalByRefAccess (ResolveContext rc)
6292 // Checks possible ldflda of field access expression
6293 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6294 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6295 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6298 public void SetHasAddressTaken ()
6300 IVariableReference vr = InstanceExpression as IVariableReference;
6302 vr.SetHasAddressTaken ();
6306 protected override void CloneTo (CloneContext clonectx, Expression target)
6308 var t = (FieldExpr) target;
6310 if (InstanceExpression != null)
6311 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6314 public override Expression CreateExpressionTree (ResolveContext ec)
6316 if (ConditionalAccess) {
6317 Error_NullShortCircuitInsideExpressionTree (ec);
6320 return CreateExpressionTree (ec, true);
6323 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6326 Expression instance;
6328 if (InstanceExpression == null) {
6329 instance = new NullLiteral (loc);
6330 } else if (convertInstance) {
6331 instance = InstanceExpression.CreateExpressionTree (ec);
6333 args = new Arguments (1);
6334 args.Add (new Argument (InstanceExpression));
6335 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6338 args = Arguments.CreateForExpressionTree (ec, null,
6340 CreateTypeOfExpression ());
6342 return CreateExpressionFactoryCall (ec, "Field", args);
6345 public Expression CreateTypeOfExpression ()
6347 return new TypeOfField (spec, loc);
6350 protected override Expression DoResolve (ResolveContext ec)
6352 spec.MemberDefinition.SetIsUsed ();
6354 return DoResolve (ec, null);
6357 Expression DoResolve (ResolveContext ec, Expression rhs)
6359 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6362 ResolveConditionalAccessReceiver (ec);
6364 if (ResolveInstanceExpression (ec, rhs)) {
6365 // Resolve the field's instance expression while flow analysis is turned
6366 // off: when accessing a field "a.b", we must check whether the field
6367 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6369 if (lvalue_instance) {
6370 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6372 Expression right_side =
6373 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6375 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6377 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6380 if (InstanceExpression == null)
6384 DoBestMemberChecks (ec, spec);
6386 if (conditional_access_receiver)
6387 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6390 var fb = spec as FixedFieldSpec;
6391 IVariableReference var = InstanceExpression as IVariableReference;
6394 IFixedExpression fe = InstanceExpression as IFixedExpression;
6395 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6396 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6399 if (InstanceExpression.eclass != ExprClass.Variable) {
6400 ec.Report.SymbolRelatedToPreviousError (spec);
6401 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6402 TypeManager.GetFullNameSignature (spec));
6403 } else if (var != null && var.IsHoisted) {
6404 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6407 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6411 // Set flow-analysis variable info for struct member access. It will be check later
6412 // for precise error reporting
6414 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6415 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6418 if (conditional_access_receiver)
6419 type = LiftMemberType (ec, type);
6421 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6422 return Constant.CreateConstantFromValue (type, null, loc);
6424 eclass = ExprClass.Variable;
6428 public void SetFieldAssigned (FlowAnalysisContext fc)
6433 bool lvalue_instance = spec.DeclaringType.IsStruct;
6434 if (lvalue_instance) {
6435 var var = InstanceExpression as IVariableReference;
6436 if (var != null && var.VariableInfo != null) {
6437 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6441 var fe = InstanceExpression as FieldExpr;
6443 Expression instance;
6446 instance = fe.InstanceExpression;
6447 var fe_instance = instance as FieldExpr;
6448 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6449 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6450 var var = InstanceExpression as IVariableReference;
6451 if (var != null && var.VariableInfo == null) {
6452 var var_inst = instance as IVariableReference;
6453 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6454 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6458 if (fe_instance != null) {
6467 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6468 instance.FlowAnalysis (fc);
6470 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6471 InstanceExpression.FlowAnalysis (fc);
6475 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6477 // The return value is always null. Returning a value simplifies calling code.
6479 if (right_side == EmptyExpression.OutAccess) {
6481 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6482 GetSignatureForError ());
6484 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6485 GetSignatureForError ());
6491 if (right_side == EmptyExpression.LValueMemberAccess) {
6492 // Already reported as CS1648/CS1650
6496 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6498 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6499 GetSignatureForError ());
6501 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6502 GetSignatureForError ());
6508 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6509 GetSignatureForError ());
6511 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6512 GetSignatureForError ());
6518 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6520 if (HasConditionalAccess ())
6521 Error_NullPropagatingLValue (ec);
6523 if (spec is FixedFieldSpec) {
6524 // It could be much better error message but we want to be error compatible
6525 Error_ValueAssignment (ec, right_side);
6528 Expression e = DoResolve (ec, right_side);
6533 spec.MemberDefinition.SetIsAssigned ();
6535 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6536 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6537 ec.Report.Warning (420, 1, loc,
6538 "`{0}': A volatile field references will not be treated as volatile",
6539 spec.GetSignatureForError ());
6542 if (spec.IsReadOnly) {
6543 // InitOnly fields can only be assigned in constructors or initializers
6544 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6545 return Error_AssignToReadonly (ec, right_side);
6547 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6549 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6550 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6551 return Error_AssignToReadonly (ec, right_side);
6552 // static InitOnly fields cannot be assigned-to in an instance constructor
6553 if (IsStatic && !ec.IsStatic)
6554 return Error_AssignToReadonly (ec, right_side);
6555 // instance constructors can't modify InitOnly fields of other instances of the same type
6556 if (!IsStatic && !(InstanceExpression is This))
6557 return Error_AssignToReadonly (ec, right_side);
6561 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6562 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6563 ec.Report.Warning (197, 1, loc,
6564 "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",
6565 GetSignatureForError ());
6568 eclass = ExprClass.Variable;
6572 public override void FlowAnalysis (FlowAnalysisContext fc)
6574 var var = InstanceExpression as IVariableReference;
6576 var vi = var.VariableInfo;
6577 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6578 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6582 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6583 var le = SkipLeftValueTypeAccess (InstanceExpression);
6585 le.FlowAnalysis (fc);
6591 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6593 base.FlowAnalysis (fc);
6595 if (conditional_access_receiver)
6596 fc.DefiniteAssignment = da;
6599 static Expression SkipLeftValueTypeAccess (Expression expr)
6601 if (!TypeSpec.IsValueType (expr.Type))
6604 if (expr is VariableReference)
6607 var fe = expr as FieldExpr;
6611 if (fe.InstanceExpression == null)
6614 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6617 public override int GetHashCode ()
6619 return spec.GetHashCode ();
6622 public bool IsFixed {
6625 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6627 IVariableReference variable = InstanceExpression as IVariableReference;
6628 if (variable != null)
6629 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6631 IFixedExpression fe = InstanceExpression as IFixedExpression;
6632 return fe != null && fe.IsFixed;
6636 public override bool Equals (object obj)
6638 FieldExpr fe = obj as FieldExpr;
6642 if (spec != fe.spec)
6645 if (InstanceExpression == null || fe.InstanceExpression == null)
6648 return InstanceExpression.Equals (fe.InstanceExpression);
6651 public void Emit (EmitContext ec, bool leave_copy)
6653 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6657 ec.Emit (OpCodes.Volatile);
6659 ec.Emit (OpCodes.Ldsfld, spec);
6661 var ca = ec.ConditionalAccess;
6664 if (conditional_access_receiver)
6665 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6667 EmitInstance (ec, false);
6670 // Optimization for build-in types
6671 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6672 ec.EmitLoadFromPtr (type);
6674 var ff = spec as FixedFieldSpec;
6676 ec.Emit (OpCodes.Ldflda, spec);
6677 ec.Emit (OpCodes.Ldflda, ff.Element);
6680 ec.Emit (OpCodes.Volatile);
6682 ec.Emit (OpCodes.Ldfld, spec);
6686 if (conditional_access_receiver) {
6687 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6688 ec.ConditionalAccess = ca;
6693 ec.Emit (OpCodes.Dup);
6695 temp = new LocalTemporary (this.Type);
6701 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6703 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6704 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6709 if (ConditionalAccess)
6710 throw new NotImplementedException ("null operator assignment");
6712 if (has_await_source)
6713 source = source.EmitToField (ec);
6715 EmitInstance (ec, prepared);
6720 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6721 ec.Emit (OpCodes.Dup);
6723 temp = new LocalTemporary (this.Type);
6728 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6729 ec.Emit (OpCodes.Volatile);
6731 spec.MemberDefinition.SetIsAssigned ();
6734 ec.Emit (OpCodes.Stsfld, spec);
6736 ec.Emit (OpCodes.Stfld, spec);
6738 if (ec.NotifyEvaluatorOnStore) {
6740 throw new NotImplementedException ("instance field write");
6743 ec.Emit (OpCodes.Dup);
6745 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6756 // Emits store to field with prepared values on stack
6758 public void EmitAssignFromStack (EmitContext ec)
6761 ec.Emit (OpCodes.Stsfld, spec);
6763 ec.Emit (OpCodes.Stfld, spec);
6767 public override void Emit (EmitContext ec)
6772 public override void EmitSideEffect (EmitContext ec)
6774 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6776 if (is_volatile) // || is_marshal_by_ref ())
6777 base.EmitSideEffect (ec);
6780 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6782 if ((mode & AddressOp.Store) != 0)
6783 spec.MemberDefinition.SetIsAssigned ();
6784 if ((mode & AddressOp.Load) != 0)
6785 spec.MemberDefinition.SetIsUsed ();
6788 // Handle initonly fields specially: make a copy and then
6789 // get the address of the copy.
6792 if (spec.IsReadOnly){
6794 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6806 var temp = ec.GetTemporaryLocal (type);
6807 ec.Emit (OpCodes.Stloc, temp);
6808 ec.Emit (OpCodes.Ldloca, temp);
6814 ec.Emit (OpCodes.Ldsflda, spec);
6817 EmitInstance (ec, false);
6818 ec.Emit (OpCodes.Ldflda, spec);
6822 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6824 return MakeExpression (ctx);
6827 public override SLE.Expression MakeExpression (BuilderContext ctx)
6830 return base.MakeExpression (ctx);
6832 return SLE.Expression.Field (
6833 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6834 spec.GetMetaInfo ());
6838 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6840 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6846 // Expression that evaluates to a Property.
6848 // This is not an LValue because we need to re-write the expression. We
6849 // can not take data from the stack and store it.
6851 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6853 Arguments arguments;
6854 FieldExpr backing_field;
6856 public PropertyExpr (PropertySpec spec, Location l)
6859 best_candidate = spec;
6860 type = spec.MemberType;
6865 protected override Arguments Arguments {
6874 protected override TypeSpec DeclaringType {
6876 return best_candidate.DeclaringType;
6880 public override string Name {
6882 return best_candidate.Name;
6886 public bool IsAutoPropertyAccess {
6888 var prop = best_candidate.MemberDefinition as Property;
6889 return prop != null && prop.BackingField != null;
6893 public override bool IsInstance {
6899 public override bool IsStatic {
6901 return best_candidate.IsStatic;
6905 public override string KindName {
6906 get { return "property"; }
6909 public PropertySpec PropertyInfo {
6911 return best_candidate;
6917 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6919 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6922 var args_count = arguments == null ? 0 : arguments.Count;
6923 if (args_count != body.Parameters.Count && args_count == 0)
6926 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6927 mg.InstanceExpression = InstanceExpression;
6932 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6934 return new PropertyExpr (spec, loc) {
6940 public override Expression CreateExpressionTree (ResolveContext ec)
6942 if (ConditionalAccess) {
6943 Error_NullShortCircuitInsideExpressionTree (ec);
6947 if (IsSingleDimensionalArrayLength ()) {
6948 args = new Arguments (1);
6949 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6950 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6953 args = new Arguments (2);
6954 if (InstanceExpression == null)
6955 args.Add (new Argument (new NullLiteral (loc)));
6957 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6958 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6959 return CreateExpressionFactoryCall (ec, "Property", args);
6962 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6964 DoResolveLValue (rc, null);
6965 return new TypeOfMethod (Setter, loc);
6968 public override string GetSignatureForError ()
6970 return best_candidate.GetSignatureForError ();
6973 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6976 return base.MakeExpression (ctx);
6978 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6982 public override SLE.Expression MakeExpression (BuilderContext ctx)
6985 return base.MakeExpression (ctx);
6987 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6991 void Error_PropertyNotValid (ResolveContext ec)
6993 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6994 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6995 GetSignatureForError ());
6998 bool IsSingleDimensionalArrayLength ()
7000 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7003 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7004 return ac != null && ac.Rank == 1;
7007 public override void Emit (EmitContext ec, bool leave_copy)
7010 // Special case: length of single dimension array property is turned into ldlen
7012 if (IsSingleDimensionalArrayLength ()) {
7013 if (conditional_access_receiver) {
7014 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7017 EmitInstance (ec, false);
7019 ec.Emit (OpCodes.Ldlen);
7020 ec.Emit (OpCodes.Conv_I4);
7022 if (conditional_access_receiver) {
7023 ec.CloseConditionalAccess (type);
7029 base.Emit (ec, leave_copy);
7032 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7034 if (backing_field != null) {
7035 backing_field.EmitAssign (ec, source, false, false);
7040 LocalTemporary await_source_arg = null;
7042 if (isCompound && !(source is DynamicExpressionStatement)) {
7043 emitting_compound_assignment = true;
7046 if (has_await_arguments) {
7047 await_source_arg = new LocalTemporary (Type);
7048 await_source_arg.Store (ec);
7050 args = new Arguments (1);
7051 args.Add (new Argument (await_source_arg));
7054 temp = await_source_arg;
7057 has_await_arguments = false;
7062 ec.Emit (OpCodes.Dup);
7063 temp = new LocalTemporary (this.Type);
7068 args = arguments ?? new Arguments (1);
7072 temp = new LocalTemporary (this.Type);
7074 args.Add (new Argument (temp));
7076 args.Add (new Argument (source));
7080 emitting_compound_assignment = false;
7082 var call = new CallEmitter ();
7083 call.InstanceExpression = InstanceExpression;
7085 call.InstanceExpressionOnStack = true;
7087 if (ConditionalAccess) {
7088 call.ConditionalAccess = true;
7092 call.Emit (ec, Setter, args, loc);
7094 call.EmitStatement (ec, Setter, args, loc);
7101 if (await_source_arg != null) {
7102 await_source_arg.Release (ec);
7106 public override void FlowAnalysis (FlowAnalysisContext fc)
7108 var prop = best_candidate.MemberDefinition as Property;
7109 if (prop != null && prop.BackingField != null) {
7110 var var = InstanceExpression as IVariableReference;
7112 var vi = var.VariableInfo;
7113 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7114 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7118 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7123 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7125 base.FlowAnalysis (fc);
7127 if (conditional_access_receiver)
7128 fc.DefiniteAssignment = da;
7131 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7133 eclass = ExprClass.PropertyAccess;
7135 if (best_candidate.IsNotCSharpCompatible) {
7136 Error_PropertyNotValid (rc);
7139 ResolveInstanceExpression (rc, right_side);
7141 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7142 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7143 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7145 type = p.MemberType;
7149 DoBestMemberChecks (rc, best_candidate);
7151 // Handling of com-imported properties with any number of default property parameters
7152 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7153 var p = best_candidate.Get.Parameters;
7154 arguments = new Arguments (p.Count);
7155 for (int i = 0; i < p.Count; ++i) {
7156 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7158 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7159 var p = best_candidate.Set.Parameters;
7160 arguments = new Arguments (p.Count - 1);
7161 for (int i = 0; i < p.Count - 1; ++i) {
7162 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7169 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7171 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7174 var prop = best_candidate.MemberDefinition as Property;
7175 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7176 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7180 prop = (Property)ps.MemberDefinition;
7183 var spec = prop.BackingField;
7187 if (rc.IsStatic != spec.IsStatic)
7190 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7193 backing_field = new FieldExpr (prop.BackingField, loc);
7194 backing_field.ResolveLValue (rc, rhs);
7198 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7200 if (backing_field != null) {
7201 backing_field.SetFieldAssigned (fc);
7205 if (!IsAutoPropertyAccess)
7208 var prop = best_candidate.MemberDefinition as Property;
7209 if (prop != null && prop.BackingField != null) {
7210 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7211 if (lvalue_instance) {
7212 var var = InstanceExpression as IVariableReference;
7213 if (var != null && var.VariableInfo != null) {
7214 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7220 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7222 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7226 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7228 // getter and setter can be different for base calls
7229 MethodSpec getter, setter;
7230 protected T best_candidate;
7232 protected LocalTemporary temp;
7233 protected bool emitting_compound_assignment;
7234 protected bool has_await_arguments;
7236 protected PropertyOrIndexerExpr (Location l)
7243 protected abstract Arguments Arguments { get; set; }
7245 public MethodSpec Getter {
7254 public MethodSpec Setter {
7265 protected override Expression DoResolve (ResolveContext ec)
7267 if (eclass == ExprClass.Unresolved) {
7268 ResolveConditionalAccessReceiver (ec);
7270 var expr = OverloadResolve (ec, null);
7275 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7276 return expr.Resolve (ec);
7279 if (conditional_access_receiver) {
7280 type = LiftMemberType (ec, type);
7284 if (!ResolveGetter (ec))
7290 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7292 if (HasConditionalAccess ())
7293 Error_NullPropagatingLValue (rc);
7295 if (right_side == EmptyExpression.OutAccess) {
7296 // TODO: best_candidate can be null at this point
7297 INamedBlockVariable variable = null;
7298 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7299 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7300 best_candidate.Name);
7302 right_side.DoResolveLValue (rc, this);
7307 if (eclass == ExprClass.Unresolved) {
7308 var expr = OverloadResolve (rc, right_side);
7313 return expr.ResolveLValue (rc, right_side);
7315 ResolveInstanceExpression (rc, right_side);
7318 if (!best_candidate.HasSet) {
7319 if (ResolveAutopropertyAssignment (rc, right_side))
7322 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7323 GetSignatureForError ());
7327 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7328 if (best_candidate.HasDifferentAccessibility) {
7329 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7330 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7331 GetSignatureForError ());
7333 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7334 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7338 if (best_candidate.HasDifferentAccessibility)
7339 CheckProtectedMemberAccess (rc, best_candidate.Set);
7341 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7345 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7347 var ca = ec.ConditionalAccess;
7348 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7350 call.Emit (ec, method, arguments, loc);
7352 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7353 ec.ConditionalAccess = ca;
7357 // Implements the IAssignMethod interface for assignments
7359 public virtual void Emit (EmitContext ec, bool leave_copy)
7361 var call = new CallEmitter ();
7362 call.ConditionalAccess = ConditionalAccess;
7363 call.InstanceExpression = InstanceExpression;
7364 if (has_await_arguments)
7365 call.HasAwaitArguments = true;
7367 call.DuplicateArguments = emitting_compound_assignment;
7369 if (conditional_access_receiver)
7370 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7372 call.Emit (ec, Getter, Arguments, loc);
7374 if (call.HasAwaitArguments) {
7375 InstanceExpression = call.InstanceExpression;
7376 Arguments = call.EmittedArguments;
7377 has_await_arguments = true;
7381 ec.Emit (OpCodes.Dup);
7382 temp = new LocalTemporary (Type);
7387 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7389 public override void Emit (EmitContext ec)
7394 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7396 has_await_arguments = true;
7401 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7403 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7405 bool ResolveGetter (ResolveContext rc)
7407 if (!best_candidate.HasGet) {
7408 if (InstanceExpression != EmptyExpression.Null) {
7409 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7410 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7411 best_candidate.GetSignatureForError ());
7414 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7415 if (best_candidate.HasDifferentAccessibility) {
7416 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7417 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7418 TypeManager.CSharpSignature (best_candidate));
7420 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7421 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7425 if (best_candidate.HasDifferentAccessibility) {
7426 CheckProtectedMemberAccess (rc, best_candidate.Get);
7429 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7433 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7440 /// Fully resolved expression that evaluates to an Event
7442 public class EventExpr : MemberExpr, IAssignMethod
7444 readonly EventSpec spec;
7447 public EventExpr (EventSpec spec, Location loc)
7455 protected override TypeSpec DeclaringType {
7457 return spec.DeclaringType;
7461 public override string Name {
7467 public override bool IsInstance {
7469 return !spec.IsStatic;
7473 public override bool IsStatic {
7475 return spec.IsStatic;
7479 public override string KindName {
7480 get { return "event"; }
7483 public MethodSpec Operator {
7491 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7494 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7496 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7497 if (spec.BackingField != null &&
7498 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7500 spec.MemberDefinition.SetIsUsed ();
7502 spec.CheckObsoleteness (ec, loc);
7504 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7505 Error_AssignmentEventOnly (ec);
7507 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7509 InstanceExpression = null;
7511 return ml.ResolveMemberAccess (ec, left, original);
7515 return base.ResolveMemberAccess (ec, left, original);
7518 public override Expression CreateExpressionTree (ResolveContext ec)
7520 throw new NotSupportedException ("ET");
7523 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7525 if (right_side == EmptyExpression.EventAddition) {
7526 op = spec.AccessorAdd;
7527 } else if (right_side == EmptyExpression.EventSubtraction) {
7528 op = spec.AccessorRemove;
7532 Error_AssignmentEventOnly (ec);
7536 if (HasConditionalAccess ())
7537 Error_NullPropagatingLValue (ec);
7539 op = CandidateToBaseOverride (ec, op);
7543 protected override Expression DoResolve (ResolveContext ec)
7545 eclass = ExprClass.EventAccess;
7546 type = spec.MemberType;
7548 ResolveInstanceExpression (ec, null);
7550 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7551 Error_AssignmentEventOnly (ec);
7554 DoBestMemberChecks (ec, spec);
7558 public override void Emit (EmitContext ec)
7560 throw new NotSupportedException ();
7561 //Error_CannotAssign ();
7564 #region IAssignMethod Members
7566 public void Emit (EmitContext ec, bool leave_copy)
7568 throw new NotImplementedException ();
7571 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7573 if (leave_copy || !isCompound)
7574 throw new NotImplementedException ("EventExpr::EmitAssign");
7576 Arguments args = new Arguments (1);
7577 args.Add (new Argument (source));
7579 // TODO: Wrong, needs receiver
7580 // if (NullShortCircuit) {
7581 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7584 var call = new CallEmitter ();
7585 call.InstanceExpression = InstanceExpression;
7586 call.ConditionalAccess = ConditionalAccess;
7587 call.EmitStatement (ec, op, args, loc);
7589 // if (NullShortCircuit)
7590 // ec.CloseConditionalAccess (null);
7595 void Error_AssignmentEventOnly (ResolveContext ec)
7597 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7598 ec.Report.Error (79, loc,
7599 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7600 GetSignatureForError ());
7602 ec.Report.Error (70, loc,
7603 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7604 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7608 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7610 name = name.Substring (0, name.LastIndexOf ('.'));
7611 base.Error_CannotCallAbstractBase (rc, name);
7614 public override string GetSignatureForError ()
7616 return TypeManager.CSharpSignature (spec);
7619 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7621 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7625 public class TemporaryVariableReference : VariableReference
7627 public class Declarator : Statement
7629 TemporaryVariableReference variable;
7631 public Declarator (TemporaryVariableReference variable)
7633 this.variable = variable;
7637 protected override void DoEmit (EmitContext ec)
7639 variable.li.CreateBuilder (ec);
7642 public override void Emit (EmitContext ec)
7644 // Don't create sequence point
7648 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7653 protected override void CloneTo (CloneContext clonectx, Statement target)
7661 public TemporaryVariableReference (LocalVariable li, Location loc)
7664 this.type = li.Type;
7668 public override bool IsLockedByStatement {
7676 public LocalVariable LocalInfo {
7682 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7684 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7685 return new TemporaryVariableReference (li, loc);
7688 protected override Expression DoResolve (ResolveContext ec)
7690 eclass = ExprClass.Variable;
7693 // Don't capture temporary variables except when using
7694 // state machine redirection and block yields
7696 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7697 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7698 ec.IsVariableCapturingRequired) {
7699 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7700 storey.CaptureLocalVariable (ec, li);
7706 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7708 return Resolve (ec);
7711 public override void Emit (EmitContext ec)
7713 li.CreateBuilder (ec);
7718 public void EmitAssign (EmitContext ec, Expression source)
7720 li.CreateBuilder (ec);
7722 EmitAssign (ec, source, false, false);
7725 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7727 return li.HoistedVariant;
7730 public override bool IsFixed {
7731 get { return true; }
7734 public override bool IsRef {
7735 get { return false; }
7738 public override string Name {
7739 get { throw new NotImplementedException (); }
7742 public override void SetHasAddressTaken ()
7744 throw new NotImplementedException ();
7747 protected override ILocalVariable Variable {
7751 public override VariableInfo VariableInfo {
7752 get { return null; }
7757 /// Handles `var' contextual keyword; var becomes a keyword only
7758 /// if no type called var exists in a variable scope
7760 class VarExpr : SimpleName
7762 public VarExpr (Location loc)
7767 public bool InferType (ResolveContext ec, Expression right_side)
7770 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7772 type = right_side.Type;
7773 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7774 ec.Report.Error (815, loc,
7775 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7776 type.GetSignatureForError ());
7777 type = InternalType.ErrorType;
7781 eclass = ExprClass.Variable;
7785 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7787 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7788 base.Error_TypeOrNamespaceNotFound (ec);
7790 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");