2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
233 var rc = mc as ResolveContext ?? new ResolveContext (mc);
234 Expression e = Resolve (rc);
236 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 public static bool IsNeverNull (Expression expr)
435 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
438 var c = expr as Constant;
442 var tc = expr as TypeCast;
444 return IsNeverNull (tc.Child);
449 protected static bool IsNullPropagatingValid (TypeSpec type)
452 case MemberKind.Struct:
453 return type.IsNullableType;
454 case MemberKind.Enum:
455 case MemberKind.Void:
456 case MemberKind.PointerType:
458 case MemberKind.InternalCompilerType:
459 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
460 case MemberKind.TypeParameter:
461 return !((TypeParameterSpec) type).IsValueType;
467 public virtual bool HasConditionalAccess ()
472 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
474 var tps = type as TypeParameterSpec;
475 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
476 Error_OperatorCannotBeApplied (rc, loc, "?", type);
479 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
480 Nullable.NullableInfo.MakeType (rc.Module, type) :
485 /// Resolves an expression and performs semantic analysis on it.
489 /// Currently Resolve wraps DoResolve to perform sanity
490 /// checking and assertion checking on what we expect from Resolve.
492 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
494 if (eclass != ExprClass.Unresolved) {
495 if ((flags & ExprClassToResolveFlags) == 0) {
496 Error_UnexpectedKind (ec, flags, loc);
510 if ((flags & e.ExprClassToResolveFlags) == 0) {
511 e.Error_UnexpectedKind (ec, flags, loc);
516 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
519 } catch (Exception ex) {
520 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
521 ec.Report.Printer is NullReportPrinter)
524 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
525 return ErrorExpression.Instance; // TODO: Add location
530 /// Resolves an expression and performs semantic analysis on it.
532 public Expression Resolve (ResolveContext rc)
534 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
538 /// Resolves an expression for LValue assignment
542 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
543 /// checking and assertion checking on what we expect from Resolve
545 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
547 int errors = ec.Report.Errors;
548 bool out_access = right_side == EmptyExpression.OutAccess;
550 Expression e = DoResolveLValue (ec, right_side);
552 if (e != null && out_access && !(e is IMemoryLocation)) {
553 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
554 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
556 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
557 // e.GetType () + " " + e.GetSignatureForError ());
562 if (errors == ec.Report.Errors) {
563 Error_ValueAssignment (ec, right_side);
568 if (e.eclass == ExprClass.Unresolved)
569 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
571 if ((e.type == null) && !(e is GenericTypeExpr))
572 throw new Exception ("Expression " + e + " did not set its type after Resolve");
577 public Constant ResolveLabelConstant (ResolveContext rc)
579 var expr = Resolve (rc);
583 Constant c = expr as Constant;
585 if (expr.type != InternalType.ErrorType)
586 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
594 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
596 if (Attribute.IsValidArgumentType (parameterType)) {
597 rc.Module.Compiler.Report.Error (182, loc,
598 "An attribute argument must be a constant expression, typeof expression or array creation expression");
600 rc.Module.Compiler.Report.Error (181, loc,
601 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
602 targetType.GetSignatureForError ());
607 /// Emits the code for the expression
611 /// The Emit method is invoked to generate the code
612 /// for the expression.
614 public abstract void Emit (EmitContext ec);
617 // Emit code to branch to @target if this expression is equivalent to @on_true.
618 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
619 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
620 // including the use of conditional branches. Note also that a branch MUST be emitted
621 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
624 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
627 // Emit this expression for its side effects, not for its value.
628 // The default implementation is to emit the value, and then throw it away.
629 // Subclasses can provide more efficient implementations, but those MUST be equivalent
630 public virtual void EmitSideEffect (EmitContext ec)
633 ec.Emit (OpCodes.Pop);
637 // Emits the expression into temporary field variable. The method
638 // should be used for await expressions only
640 public virtual Expression EmitToField (EmitContext ec)
643 // This is the await prepare Emit method. When emitting code like
644 // a + b we emit code like
650 // For await a + await b we have to interfere the flow to keep the
651 // stack clean because await yields from the expression. The emit
654 // a = a.EmitToField () // a is changed to temporary field access
655 // b = b.EmitToField ()
661 // The idea is to emit expression and leave the stack empty with
662 // result value still available.
664 // Expressions should override this default implementation when
665 // optimized version can be provided (e.g. FieldExpr)
668 // We can optimize for side-effect free expressions, they can be
669 // emitted out of order
671 if (IsSideEffectFree)
674 bool needs_temporary = ContainsEmitWithAwait ();
675 if (!needs_temporary)
678 // Emit original code
679 var field = EmitToFieldSource (ec);
682 // Store the result to temporary field when we
683 // cannot load `this' directly
685 field = ec.GetTemporaryField (type);
686 if (needs_temporary) {
688 // Create temporary local (we cannot load `this' before Emit)
690 var temp = ec.GetTemporaryLocal (type);
691 ec.Emit (OpCodes.Stloc, temp);
694 ec.Emit (OpCodes.Ldloc, temp);
695 field.EmitAssignFromStack (ec);
697 ec.FreeTemporaryLocal (temp, type);
699 field.EmitAssignFromStack (ec);
706 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
709 // Default implementation calls Emit method
715 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
717 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
718 bool contains_await = false;
720 for (int i = 1; i < expressions.Count; ++i) {
721 if (expressions[i].ContainsEmitWithAwait ()) {
722 contains_await = true;
727 if (contains_await) {
728 for (int i = 0; i < expressions.Count; ++i) {
729 expressions[i] = expressions[i].EmitToField (ec);
734 for (int i = 0; i < expressions.Count; ++i) {
735 expressions[i].Emit (ec);
740 /// Protected constructor. Only derivate types should
741 /// be able to be created
744 protected Expression ()
749 /// Returns a fully formed expression after a MemberLookup
752 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
754 if (spec is EventSpec)
755 return new EventExpr ((EventSpec) spec, loc);
756 if (spec is ConstSpec)
757 return new ConstantExpr ((ConstSpec) spec, loc);
758 if (spec is FieldSpec)
759 return new FieldExpr ((FieldSpec) spec, loc);
760 if (spec is PropertySpec)
761 return new PropertyExpr ((PropertySpec) spec, loc);
762 if (spec is TypeSpec)
763 return new TypeExpression (((TypeSpec) spec), loc);
768 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
770 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
773 case MemberKind.Struct:
774 // Every struct has implicit default constructor if not provided by user
778 rc.Report.SymbolRelatedToPreviousError (type);
779 // Report meaningful error for struct as they always have default ctor in C# context
780 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
782 case MemberKind.MissingType:
783 case MemberKind.InternalCompilerType:
784 // LAMESPEC: dynamic is not really object
785 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
789 rc.Report.SymbolRelatedToPreviousError (type);
790 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
791 type.GetSignatureForError ());
798 if (args == null && type.IsStruct) {
799 bool includes_empty = false;
800 foreach (MethodSpec ctor in ctors) {
801 if (ctor.Parameters.IsEmpty) {
802 includes_empty = true;
810 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
811 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
812 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
815 return r.ResolveMember<MethodSpec> (rc, ref args);
819 public enum MemberLookupRestrictions
825 EmptyArguments = 1 << 4,
826 IgnoreArity = 1 << 5,
827 IgnoreAmbiguity = 1 << 6,
828 NameOfExcluded = 1 << 7,
829 DontSetConditionalAccess = 1 << 8
833 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
834 // `qualifier_type' or null to lookup members in the current class.
836 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
838 var members = MemberCache.FindMembers (queried_type, name, false);
844 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
848 if (members [0].DeclaringType.BaseType == null)
851 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
852 } while (members != null);
857 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
859 MemberSpec non_method = null;
860 MemberSpec ambig_non_method = null;
862 for (int i = 0; i < members.Count; ++i) {
863 var member = members [i];
865 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
866 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
869 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
872 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
876 if (!member.IsAccessible (rc))
880 // With runtime binder we can have a situation where queried type is inaccessible
881 // because it came via dynamic object, the check about inconsisted accessibility
882 // had no effect as the type was unknown during compilation
885 // private class N { }
887 // public dynamic Foo ()
893 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
897 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
898 if (member is MethodSpec) {
900 // Interface members that are hidden by class members are removed from the set. This
901 // step only has an effect if T is a type parameter and T has both an effective base
902 // class other than object and a non-empty effective interface set
904 var tps = queried_type as TypeParameterSpec;
905 if (tps != null && tps.HasTypeConstraint)
906 members = RemoveHiddenTypeParameterMethods (members);
908 return new MethodGroupExpr (members, queried_type, loc);
911 if (!Invocation.IsMemberInvocable (member))
915 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
917 } else if (!errorMode && !member.IsNotCSharpCompatible) {
919 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
920 // T has both an effective base class other than object and a non-empty effective interface set.
922 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
924 var tps = queried_type as TypeParameterSpec;
925 if (tps != null && tps.HasTypeConstraint) {
926 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
929 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
935 ambig_non_method = member;
939 if (non_method != null) {
940 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
941 var report = rc.Module.Compiler.Report;
942 report.SymbolRelatedToPreviousError (non_method);
943 report.SymbolRelatedToPreviousError (ambig_non_method);
944 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
945 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
948 if (non_method is MethodSpec)
949 return new MethodGroupExpr (members, queried_type, loc);
951 return ExprClassFromMemberInfo (non_method, loc);
957 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
959 if (members.Count < 2)
963 // If M is a method, then all non-method members declared in an interface declaration
964 // are removed from the set, and all methods with the same signature as M declared in
965 // an interface declaration are removed from the set
969 for (int i = 0; i < members.Count; ++i) {
970 var method = members[i] as MethodSpec;
971 if (method == null) {
974 members = new List<MemberSpec> (members);
977 members.RemoveAt (i--);
981 if (!method.DeclaringType.IsInterface)
984 for (int ii = 0; ii < members.Count; ++ii) {
985 var candidate = members[ii] as MethodSpec;
986 if (candidate == null || !candidate.DeclaringType.IsClass)
989 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
992 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
997 members = new List<MemberSpec> (members);
1000 members.RemoveAt (i--);
1008 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1010 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1013 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1015 throw new NotImplementedException ();
1018 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1020 if (t == InternalType.ErrorType)
1023 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1024 oper, t.GetSignatureForError ());
1027 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1029 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1032 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1034 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1037 protected void Error_NullPropagatingLValue (ResolveContext rc)
1039 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1042 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1047 // Special version of flow analysis for expressions which can return different
1048 // on-true and on-false result. Used by &&, ||, ?: expressions
1050 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1053 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1057 /// Returns an expression that can be used to invoke operator true
1058 /// on the expression if it exists.
1060 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1062 return GetOperatorTrueOrFalse (ec, e, true, loc);
1066 /// Returns an expression that can be used to invoke operator false
1067 /// on the expression if it exists.
1069 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1071 return GetOperatorTrueOrFalse (ec, e, false, loc);
1074 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1076 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1078 if (type.IsNullableType)
1079 type = Nullable.NullableInfo.GetUnderlyingType (type);
1081 var methods = MemberCache.GetUserOperator (type, op, false);
1082 if (methods == null)
1085 Arguments arguments = new Arguments (1);
1086 arguments.Add (new Argument (e));
1088 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1089 var oper = res.ResolveOperator (ec, ref arguments);
1094 return new UserOperatorCall (oper, arguments, null, loc);
1097 public virtual string ExprClassName
1101 case ExprClass.Unresolved:
1102 return "Unresolved";
1103 case ExprClass.Value:
1105 case ExprClass.Variable:
1107 case ExprClass.Namespace:
1109 case ExprClass.Type:
1111 case ExprClass.MethodGroup:
1112 return "method group";
1113 case ExprClass.PropertyAccess:
1114 return "property access";
1115 case ExprClass.EventAccess:
1116 return "event access";
1117 case ExprClass.IndexerAccess:
1118 return "indexer access";
1119 case ExprClass.Nothing:
1121 case ExprClass.TypeParameter:
1122 return "type parameter";
1124 throw new Exception ("Should not happen");
1129 /// Reports that we were expecting `expr' to be of class `expected'
1131 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1133 var name = memberExpr.GetSignatureForError ();
1135 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1138 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1140 string [] valid = new string [4];
1143 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1144 valid [count++] = "variable";
1145 valid [count++] = "value";
1148 if ((flags & ResolveFlags.Type) != 0)
1149 valid [count++] = "type";
1151 if ((flags & ResolveFlags.MethodGroup) != 0)
1152 valid [count++] = "method group";
1155 valid [count++] = "unknown";
1157 StringBuilder sb = new StringBuilder (valid [0]);
1158 for (int i = 1; i < count - 1; i++) {
1160 sb.Append (valid [i]);
1163 sb.Append ("' or `");
1164 sb.Append (valid [count - 1]);
1167 ec.Report.Error (119, loc,
1168 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1171 public static void UnsafeError (ResolveContext ec, Location loc)
1173 UnsafeError (ec.Report, loc);
1176 public static void UnsafeError (Report Report, Location loc)
1178 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1182 // Converts `source' to an int, uint, long or ulong.
1184 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1186 var btypes = ec.BuiltinTypes;
1188 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1189 Arguments args = new Arguments (1);
1190 args.Add (new Argument (source));
1191 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1194 Expression converted;
1196 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1197 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1198 if (converted == null)
1199 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1200 if (converted == null)
1201 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1202 if (converted == null)
1203 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1205 if (converted == null) {
1206 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1215 // Only positive constants are allowed at compile time
1217 Constant c = converted as Constant;
1218 if (c != null && c.IsNegative)
1219 Error_NegativeArrayIndex (ec, source.loc);
1221 // No conversion needed to array index
1222 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1225 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1228 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1230 if (args.Count != 1){
1231 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1236 if (arg is NamedArgument)
1237 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1239 var index = arg.Expr.Resolve (rc);
1243 index = ConvertExpressionToArrayIndex (rc, index, true);
1245 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1246 return new Indirection (p, loc);
1250 // Derived classes implement this method by cloning the fields that
1251 // could become altered during the Resolve stage
1253 // Only expressions that are created for the parser need to implement
1256 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1258 throw new NotImplementedException (
1260 "CloneTo not implemented for expression {0}", this.GetType ()));
1264 // Clones an expression created by the parser.
1266 // We only support expressions created by the parser so far, not
1267 // expressions that have been resolved (many more classes would need
1268 // to implement CloneTo).
1270 // This infrastructure is here merely for Lambda expressions which
1271 // compile the same code using different type values for the same
1272 // arguments to find the correct overload
1274 public virtual Expression Clone (CloneContext clonectx)
1276 Expression cloned = (Expression) MemberwiseClone ();
1277 CloneTo (clonectx, cloned);
1283 // Implementation of expression to expression tree conversion
1285 public abstract Expression CreateExpressionTree (ResolveContext ec);
1287 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1289 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1292 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1294 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1297 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1299 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1302 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1304 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1308 return new TypeExpression (t, loc);
1312 // Implemented by all expressions which support conversion from
1313 // compiler expression to invokable runtime expression. Used by
1314 // dynamic C# binder.
1316 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1318 throw new NotImplementedException ("MakeExpression for " + GetType ());
1321 public virtual object Accept (StructuralVisitor visitor)
1323 return visitor.Visit (this);
1328 /// This is just a base class for expressions that can
1329 /// appear on statements (invocations, object creation,
1330 /// assignments, post/pre increment and decrement). The idea
1331 /// being that they would support an extra Emition interface that
1332 /// does not leave a result on the stack.
1334 public abstract class ExpressionStatement : Expression
1336 public virtual void MarkReachable (Reachability rc)
1340 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1342 Expression e = Resolve (ec);
1346 ExpressionStatement es = e as ExpressionStatement;
1347 if (es == null || e is AnonymousMethodBody) {
1348 var reduced = e as IReducedExpressionStatement;
1349 if (reduced != null) {
1350 return EmptyExpressionStatement.Instance;
1353 Error_InvalidExpressionStatement (ec);
1357 // This is quite expensive warning, try to limit the damage
1359 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1360 WarningAsyncWithoutWait (ec, e);
1366 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1368 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1369 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1374 // Need to do full resolve because GetAwaiter can be extension method
1375 // available only in this context
1377 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1381 var arguments = new Arguments (0);
1382 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1387 // Use same check rules as for real await
1389 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1390 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1393 bc.Report.Warning (4014, 1, e.Location,
1394 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1398 var inv = e as Invocation;
1399 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1400 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1401 bc.Report.Warning (4014, 1, e.Location,
1402 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1408 /// Requests the expression to be emitted in a `statement'
1409 /// context. This means that no new value is left on the
1410 /// stack after invoking this method (constrasted with
1411 /// Emit that will always leave a value on the stack).
1413 public abstract void EmitStatement (EmitContext ec);
1415 public override void EmitSideEffect (EmitContext ec)
1421 interface IReducedExpressionStatement
1426 /// This kind of cast is used to encapsulate the child
1427 /// whose type is child.Type into an expression that is
1428 /// reported to return "return_type". This is used to encapsulate
1429 /// expressions which have compatible types, but need to be dealt
1430 /// at higher levels with.
1432 /// For example, a "byte" expression could be encapsulated in one
1433 /// of these as an "unsigned int". The type for the expression
1434 /// would be "unsigned int".
1437 public abstract class TypeCast : Expression
1439 protected readonly Expression child;
1441 protected TypeCast (Expression child, TypeSpec return_type)
1443 eclass = child.eclass;
1444 loc = child.Location;
1449 public Expression Child {
1455 public override bool ContainsEmitWithAwait ()
1457 return child.ContainsEmitWithAwait ();
1460 public override Expression CreateExpressionTree (ResolveContext ec)
1462 Arguments args = new Arguments (2);
1463 args.Add (new Argument (child.CreateExpressionTree (ec)));
1464 args.Add (new Argument (new TypeOf (type, loc)));
1466 if (type.IsPointer || child.Type.IsPointer)
1467 Error_PointerInsideExpressionTree (ec);
1469 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1472 protected override Expression DoResolve (ResolveContext ec)
1474 // This should never be invoked, we are born in fully
1475 // initialized state.
1480 public override void Emit (EmitContext ec)
1485 public override void FlowAnalysis (FlowAnalysisContext fc)
1487 child.FlowAnalysis (fc);
1490 public override SLE.Expression MakeExpression (BuilderContext ctx)
1493 return base.MakeExpression (ctx);
1495 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1496 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1497 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1501 protected override void CloneTo (CloneContext clonectx, Expression t)
1506 public override bool IsNull {
1507 get { return child.IsNull; }
1511 public class EmptyCast : TypeCast {
1512 EmptyCast (Expression child, TypeSpec target_type)
1513 : base (child, target_type)
1517 public static Expression Create (Expression child, TypeSpec type)
1519 Constant c = child as Constant;
1521 var enum_constant = c as EnumConstant;
1522 if (enum_constant != null)
1523 c = enum_constant.Child;
1525 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1529 var res = c.ConvertImplicitly (type);
1535 EmptyCast e = child as EmptyCast;
1537 return new EmptyCast (e.child, type);
1539 return new EmptyCast (child, type);
1542 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1544 child.EmitBranchable (ec, label, on_true);
1547 public override void EmitSideEffect (EmitContext ec)
1549 child.EmitSideEffect (ec);
1554 // Used for predefined type user operator (no obsolete check, etc.)
1556 public class OperatorCast : TypeCast
1558 readonly MethodSpec conversion_operator;
1560 public OperatorCast (Expression expr, TypeSpec target_type)
1561 : this (expr, target_type, target_type, false)
1565 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1566 : this (expr, target_type, target_type, find_explicit)
1570 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1571 : base (expr, returnType)
1573 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1574 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1577 foreach (MethodSpec oper in mi) {
1578 if (oper.ReturnType != returnType)
1581 if (oper.Parameters.Types[0] == expr.Type) {
1582 conversion_operator = oper;
1588 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1589 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1592 public override void Emit (EmitContext ec)
1595 ec.Emit (OpCodes.Call, conversion_operator);
1600 // Constant specialization of EmptyCast.
1601 // We need to special case this since an empty cast of
1602 // a constant is still a constant.
1604 public class EmptyConstantCast : Constant
1606 public readonly Constant child;
1608 public EmptyConstantCast (Constant child, TypeSpec type)
1609 : base (child.Location)
1612 throw new ArgumentNullException ("child");
1615 this.eclass = child.eclass;
1619 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1621 if (child.Type == target_type)
1624 // FIXME: check that 'type' can be converted to 'target_type' first
1625 return child.ConvertExplicitly (in_checked_context, target_type);
1628 public override Expression CreateExpressionTree (ResolveContext ec)
1630 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1631 child.CreateExpressionTree (ec),
1632 new TypeOf (type, loc));
1635 Error_PointerInsideExpressionTree (ec);
1637 return CreateExpressionFactoryCall (ec, "Convert", args);
1640 public override bool IsDefaultValue {
1641 get { return child.IsDefaultValue; }
1644 public override bool IsNegative {
1645 get { return child.IsNegative; }
1648 public override bool IsNull {
1649 get { return child.IsNull; }
1652 public override bool IsOneInteger {
1653 get { return child.IsOneInteger; }
1656 public override bool IsSideEffectFree {
1658 return child.IsSideEffectFree;
1662 public override bool IsZeroInteger {
1663 get { return child.IsZeroInteger; }
1666 public override void Emit (EmitContext ec)
1671 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1673 child.EmitBranchable (ec, label, on_true);
1675 // Only to make verifier happy
1676 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1677 ec.Emit (OpCodes.Unbox_Any, type);
1680 public override void EmitSideEffect (EmitContext ec)
1682 child.EmitSideEffect (ec);
1685 public override object GetValue ()
1687 return child.GetValue ();
1690 public override string GetValueAsLiteral ()
1692 return child.GetValueAsLiteral ();
1695 public override long GetValueAsLong ()
1697 return child.GetValueAsLong ();
1700 public override Constant ConvertImplicitly (TypeSpec target_type)
1702 if (type == target_type)
1705 // FIXME: Do we need to check user conversions?
1706 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1709 return child.ConvertImplicitly (target_type);
1714 /// This class is used to wrap literals which belong inside Enums
1716 public class EnumConstant : Constant
1718 public Constant Child;
1720 public EnumConstant (Constant child, TypeSpec enum_type)
1721 : base (child.Location)
1725 this.eclass = ExprClass.Value;
1726 this.type = enum_type;
1729 protected EnumConstant (Location loc)
1734 public override void Emit (EmitContext ec)
1739 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1741 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1744 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1746 Child.EmitBranchable (ec, label, on_true);
1749 public override void EmitSideEffect (EmitContext ec)
1751 Child.EmitSideEffect (ec);
1754 public override string GetSignatureForError()
1756 return Type.GetSignatureForError ();
1759 public override object GetValue ()
1761 return Child.GetValue ();
1765 public override object GetTypedValue ()
1768 // The method can be used in dynamic context only (on closed types)
1770 // System.Enum.ToObject cannot be called on dynamic types
1771 // EnumBuilder has to be used, but we cannot use EnumBuilder
1772 // because it does not properly support generics
1774 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1778 public override string GetValueAsLiteral ()
1780 return Child.GetValueAsLiteral ();
1783 public override long GetValueAsLong ()
1785 return Child.GetValueAsLong ();
1788 public EnumConstant Increment()
1790 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1793 public override bool IsDefaultValue {
1795 return Child.IsDefaultValue;
1799 public override bool IsSideEffectFree {
1801 return Child.IsSideEffectFree;
1805 public override bool IsZeroInteger {
1806 get { return Child.IsZeroInteger; }
1809 public override bool IsNegative {
1811 return Child.IsNegative;
1815 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1817 if (Child.Type == target_type)
1820 return Child.ConvertExplicitly (in_checked_context, target_type);
1823 public override Constant ConvertImplicitly (TypeSpec type)
1825 if (this.type == type) {
1829 if (!Convert.ImplicitStandardConversionExists (this, type)){
1833 return Child.ConvertImplicitly (type);
1838 /// This kind of cast is used to encapsulate Value Types in objects.
1840 /// The effect of it is to box the value type emitted by the previous
1843 public class BoxedCast : TypeCast {
1845 public BoxedCast (Expression expr, TypeSpec target_type)
1846 : base (expr, target_type)
1848 eclass = ExprClass.Value;
1851 protected override Expression DoResolve (ResolveContext ec)
1853 // This should never be invoked, we are born in fully
1854 // initialized state.
1859 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1861 // Only boxing to object type is supported
1862 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1863 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1867 enc.Encode (child.Type);
1868 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1871 public override void Emit (EmitContext ec)
1875 ec.Emit (OpCodes.Box, child.Type);
1878 public override void EmitSideEffect (EmitContext ec)
1880 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1881 // so, we need to emit the box+pop instructions in most cases
1882 if (child.Type.IsStruct &&
1883 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1884 child.EmitSideEffect (ec);
1886 base.EmitSideEffect (ec);
1890 public class UnboxCast : TypeCast {
1891 public UnboxCast (Expression expr, TypeSpec return_type)
1892 : base (expr, return_type)
1896 protected override Expression DoResolve (ResolveContext ec)
1898 // This should never be invoked, we are born in fully
1899 // initialized state.
1904 public override void Emit (EmitContext ec)
1908 ec.Emit (OpCodes.Unbox_Any, type);
1913 /// This is used to perform explicit numeric conversions.
1915 /// Explicit numeric conversions might trigger exceptions in a checked
1916 /// context, so they should generate the conv.ovf opcodes instead of
1919 public class ConvCast : TypeCast {
1920 public enum Mode : byte {
1921 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1923 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1924 U2_I1, U2_U1, U2_I2, U2_CH,
1925 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1926 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1927 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1928 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1929 CH_I1, CH_U1, CH_I2,
1930 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1931 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1937 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1938 : base (child, return_type)
1943 protected override Expression DoResolve (ResolveContext ec)
1945 // This should never be invoked, we are born in fully
1946 // initialized state.
1951 public override string ToString ()
1953 return String.Format ("ConvCast ({0}, {1})", mode, child);
1956 public override void Emit (EmitContext ec)
1962 public static void Emit (EmitContext ec, Mode mode)
1964 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1966 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1967 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1968 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1969 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1970 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.U1_CH: /* nothing */ break;
1975 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1976 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1977 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1978 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1979 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1980 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1982 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1983 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1984 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1985 case Mode.U2_CH: /* nothing */ break;
1987 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1988 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1989 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1990 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1991 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1996 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1997 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1998 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1999 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2000 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2002 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2003 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2004 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2005 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2006 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2007 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2008 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2009 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2010 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2012 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2013 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2014 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2015 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2016 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2017 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2018 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2019 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2020 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2022 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2023 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2024 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2026 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2027 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2028 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2029 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2030 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2031 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2032 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2033 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2034 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2036 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2037 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2038 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2039 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2040 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2041 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2042 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2043 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2044 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2045 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2047 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2051 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2052 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2053 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2054 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2055 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2058 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2060 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2061 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2062 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2063 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2064 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2065 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2067 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2068 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2069 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2070 case Mode.U2_CH: /* nothing */ break;
2072 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2073 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2074 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2075 case Mode.I4_U4: /* nothing */ break;
2076 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2077 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2078 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2080 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2081 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2082 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2083 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2084 case Mode.U4_I4: /* nothing */ break;
2085 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2087 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2088 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2089 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2090 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2091 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2092 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2093 case Mode.I8_U8: /* nothing */ break;
2094 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2095 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2097 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2098 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2099 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2100 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2101 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2102 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2103 case Mode.U8_I8: /* nothing */ break;
2104 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2105 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2107 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2108 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2109 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2111 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2112 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2113 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2114 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2115 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2116 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2117 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2118 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2119 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2121 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2122 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2123 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2124 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2125 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2126 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2127 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2128 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2129 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2130 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2132 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2138 class OpcodeCast : TypeCast
2142 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2143 : base (child, return_type)
2148 protected override Expression DoResolve (ResolveContext ec)
2150 // This should never be invoked, we are born in fully
2151 // initialized state.
2156 public override void Emit (EmitContext ec)
2162 public TypeSpec UnderlyingType {
2163 get { return child.Type; }
2168 // Opcode casts expression with 2 opcodes but only
2169 // single expression tree node
2171 class OpcodeCastDuplex : OpcodeCast
2173 readonly OpCode second;
2175 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2176 : base (child, returnType, first)
2178 this.second = second;
2181 public override void Emit (EmitContext ec)
2189 /// This kind of cast is used to encapsulate a child and cast it
2190 /// to the class requested
2192 public sealed class ClassCast : TypeCast {
2193 readonly bool forced;
2195 public ClassCast (Expression child, TypeSpec return_type)
2196 : base (child, return_type)
2200 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2201 : base (child, return_type)
2203 this.forced = forced;
2206 public override void Emit (EmitContext ec)
2210 bool gen = TypeManager.IsGenericParameter (child.Type);
2212 ec.Emit (OpCodes.Box, child.Type);
2214 if (type.IsGenericParameter) {
2215 ec.Emit (OpCodes.Unbox_Any, type);
2222 ec.Emit (OpCodes.Castclass, type);
2227 // Created during resolving pahse when an expression is wrapped or constantified
2228 // and original expression can be used later (e.g. for expression trees)
2230 public class ReducedExpression : Expression
2232 public class ReducedConstantExpression : EmptyConstantCast
2234 readonly Expression orig_expr;
2236 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2237 : base (expr, expr.Type)
2239 this.orig_expr = orig_expr;
2242 public Expression OriginalExpression {
2248 public override Constant ConvertImplicitly (TypeSpec target_type)
2250 Constant c = base.ConvertImplicitly (target_type);
2252 c = new ReducedConstantExpression (c, orig_expr);
2257 public override Expression CreateExpressionTree (ResolveContext ec)
2259 return orig_expr.CreateExpressionTree (ec);
2262 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2264 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2266 c = new ReducedConstantExpression (c, orig_expr);
2270 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2273 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2275 if (orig_expr is Conditional)
2276 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2278 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2282 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2284 public ReducedConstantStatement (Constant expr, Expression origExpr)
2285 : base (expr, origExpr)
2290 sealed class ReducedExpressionStatement : ExpressionStatement
2292 readonly Expression orig_expr;
2293 readonly ExpressionStatement stm;
2295 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2297 this.orig_expr = orig;
2299 this.eclass = stm.eclass;
2300 this.type = stm.Type;
2302 this.loc = orig.Location;
2305 public override bool ContainsEmitWithAwait ()
2307 return stm.ContainsEmitWithAwait ();
2310 public override Expression CreateExpressionTree (ResolveContext ec)
2312 return orig_expr.CreateExpressionTree (ec);
2315 protected override Expression DoResolve (ResolveContext ec)
2320 public override void Emit (EmitContext ec)
2325 public override void EmitStatement (EmitContext ec)
2327 stm.EmitStatement (ec);
2330 public override void FlowAnalysis (FlowAnalysisContext fc)
2332 stm.FlowAnalysis (fc);
2336 readonly Expression expr, orig_expr;
2338 private ReducedExpression (Expression expr, Expression orig_expr)
2341 this.eclass = expr.eclass;
2342 this.type = expr.Type;
2343 this.orig_expr = orig_expr;
2344 this.loc = orig_expr.Location;
2349 public override bool IsSideEffectFree {
2351 return expr.IsSideEffectFree;
2355 public Expression OriginalExpression {
2363 public override bool ContainsEmitWithAwait ()
2365 return expr.ContainsEmitWithAwait ();
2369 // Creates fully resolved expression switcher
2371 public static Constant Create (Constant expr, Expression originalExpr)
2373 if (expr.eclass == ExprClass.Unresolved)
2374 throw new ArgumentException ("Unresolved expression");
2376 if (originalExpr is ExpressionStatement)
2377 return new ReducedConstantStatement (expr, originalExpr);
2379 return new ReducedConstantExpression (expr, originalExpr);
2382 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2384 return new ReducedExpressionStatement (s, orig);
2387 public static Expression Create (Expression expr, Expression original_expr)
2389 return Create (expr, original_expr, true);
2393 // Creates unresolved reduce expression. The original expression has to be
2394 // already resolved. Created expression is constant based based on `expr'
2395 // value unless canBeConstant is used
2397 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2399 if (canBeConstant) {
2400 Constant c = expr as Constant;
2402 return Create (c, original_expr);
2405 ExpressionStatement s = expr as ExpressionStatement;
2407 return Create (s, original_expr);
2409 if (expr.eclass == ExprClass.Unresolved)
2410 throw new ArgumentException ("Unresolved expression");
2412 return new ReducedExpression (expr, original_expr);
2415 public override Expression CreateExpressionTree (ResolveContext ec)
2417 return orig_expr.CreateExpressionTree (ec);
2420 protected override Expression DoResolve (ResolveContext ec)
2425 public override void Emit (EmitContext ec)
2430 public override Expression EmitToField (EmitContext ec)
2432 return expr.EmitToField(ec);
2435 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2437 expr.EmitBranchable (ec, target, on_true);
2440 public override void FlowAnalysis (FlowAnalysisContext fc)
2442 expr.FlowAnalysis (fc);
2445 public override SLE.Expression MakeExpression (BuilderContext ctx)
2447 return orig_expr.MakeExpression (ctx);
2452 // Standard composite pattern
2454 public abstract class CompositeExpression : Expression
2456 protected Expression expr;
2458 protected CompositeExpression (Expression expr)
2461 this.loc = expr.Location;
2464 public override bool ContainsEmitWithAwait ()
2466 return expr.ContainsEmitWithAwait ();
2469 public override Expression CreateExpressionTree (ResolveContext rc)
2471 return expr.CreateExpressionTree (rc);
2474 public Expression Child {
2475 get { return expr; }
2478 protected override Expression DoResolve (ResolveContext rc)
2480 expr = expr.Resolve (rc);
2485 eclass = expr.eclass;
2489 public override void Emit (EmitContext ec)
2494 public override bool IsNull {
2495 get { return expr.IsNull; }
2500 // Base of expressions used only to narrow resolve flow
2502 public abstract class ShimExpression : Expression
2504 protected Expression expr;
2506 protected ShimExpression (Expression expr)
2511 public Expression Expr {
2517 protected override void CloneTo (CloneContext clonectx, Expression t)
2522 ShimExpression target = (ShimExpression) t;
2523 target.expr = expr.Clone (clonectx);
2526 public override bool ContainsEmitWithAwait ()
2528 return expr.ContainsEmitWithAwait ();
2531 public override Expression CreateExpressionTree (ResolveContext ec)
2533 throw new NotSupportedException ("ET");
2536 public override void Emit (EmitContext ec)
2538 throw new InternalErrorException ("Missing Resolve call");
2542 public class UnreachableExpression : Expression
2544 public UnreachableExpression (Expression expr)
2546 this.loc = expr.Location;
2549 public override Expression CreateExpressionTree (ResolveContext ec)
2552 throw new NotImplementedException ();
2555 protected override Expression DoResolve (ResolveContext rc)
2557 throw new NotSupportedException ();
2560 public override void FlowAnalysis (FlowAnalysisContext fc)
2562 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2565 public override void Emit (EmitContext ec)
2569 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2575 // Unresolved type name expressions
2577 public abstract class ATypeNameExpression : FullNamedExpression
2580 protected TypeArguments targs;
2582 protected ATypeNameExpression (string name, Location l)
2588 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2595 protected ATypeNameExpression (string name, int arity, Location l)
2596 : this (name, new UnboundTypeArguments (arity, l), l)
2604 return targs == null ? 0 : targs.Count;
2608 public bool HasTypeArguments {
2610 return targs != null && !targs.IsEmpty;
2614 public string Name {
2623 public TypeArguments TypeArguments {
2631 public override bool Equals (object obj)
2633 ATypeNameExpression atne = obj as ATypeNameExpression;
2634 return atne != null && atne.Name == Name &&
2635 (targs == null || targs.Equals (atne.targs));
2638 public override int GetHashCode ()
2640 return Name.GetHashCode ();
2643 // TODO: Move it to MemberCore
2644 public static string GetMemberType (MemberCore mc)
2650 if (mc is FieldBase)
2652 if (mc is MethodCore)
2654 if (mc is EnumMember)
2662 public override string GetSignatureForError ()
2664 if (targs != null) {
2665 return Name + "<" + targs.GetSignatureForError () + ">";
2671 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2675 /// SimpleName expressions are formed of a single word and only happen at the beginning
2676 /// of a dotted-name.
2678 public class SimpleName : ATypeNameExpression
2680 public SimpleName (string name, Location l)
2685 public SimpleName (string name, TypeArguments args, Location l)
2686 : base (name, args, l)
2690 public SimpleName (string name, int arity, Location l)
2691 : base (name, arity, l)
2695 public SimpleName GetMethodGroup ()
2697 return new SimpleName (Name, targs, loc);
2700 protected override Expression DoResolve (ResolveContext rc)
2702 return SimpleNameResolve (rc, null);
2705 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2707 return SimpleNameResolve (ec, right_side);
2710 public void Error_NameDoesNotExist (ResolveContext rc)
2712 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2715 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2717 if (ctx.CurrentType != null) {
2718 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2719 if (member != null) {
2720 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2725 var report = ctx.Module.Compiler.Report;
2727 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2728 if (retval != null) {
2729 report.SymbolRelatedToPreviousError (retval.Type);
2730 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2734 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2735 if (retval != null) {
2736 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2740 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2741 if (ns_candidates != null) {
2742 if (ctx is UsingAliasNamespace.AliasContext) {
2743 report.Error (246, loc,
2744 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2745 ns_candidates[0], Name);
2747 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2748 report.Error (246, loc,
2749 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2753 report.Error (246, loc,
2754 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2759 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2761 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2764 if (fne.Type != null && Arity > 0) {
2765 if (HasTypeArguments) {
2766 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2767 if (ct.ResolveAsType (mc) == null)
2773 targs.Resolve (mc, allowUnboundTypeArguments);
2775 return new GenericOpenTypeExpr (fne.Type, loc);
2779 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2781 if (!(fne is NamespaceExpression))
2785 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2786 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2787 mc.Module.Compiler.Report.Error (1980, Location,
2788 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2789 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2792 fne = new DynamicTypeExpr (loc);
2793 fne.ResolveAsType (mc);
2799 Error_TypeOrNamespaceNotFound (mc);
2803 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2805 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2808 public bool IsPossibleType (IMemberContext mc)
2810 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2813 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2815 int lookup_arity = Arity;
2816 bool errorMode = false;
2818 Block current_block = rc.CurrentBlock;
2819 INamedBlockVariable variable = null;
2820 bool variable_found = false;
2824 // Stage 1: binding to local variables or parameters
2826 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2828 if (current_block != null && lookup_arity == 0) {
2829 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2830 if (!variable.IsDeclared) {
2831 // We found local name in accessible block but it's not
2832 // initialized yet, maybe the user wanted to bind to something else
2834 variable_found = true;
2836 e = variable.CreateReferenceExpression (rc, loc);
2839 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2848 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2850 TypeSpec member_type = rc.CurrentType;
2851 for (; member_type != null; member_type = member_type.DeclaringType) {
2852 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2856 var me = e as MemberExpr;
2858 // The name matches a type, defer to ResolveAsTypeStep
2866 if (variable != null) {
2867 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2868 rc.Report.Error (844, loc,
2869 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2870 Name, me.GetSignatureForError ());
2874 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2875 // Leave it to overload resolution to report correct error
2877 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2878 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2882 // MemberLookup does not check accessors availability, this is actually needed for properties only
2884 var pe = me as PropertyExpr;
2887 // Break as there is no other overload available anyway
2888 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2889 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2892 pe.Getter = pe.PropertyInfo.Get;
2894 if (!pe.PropertyInfo.HasSet) {
2895 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2896 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2897 var p = (Property) pe.PropertyInfo.MemberDefinition;
2898 return new FieldExpr (p.BackingField, loc);
2901 variable_found = true;
2905 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2906 variable_found = true;
2910 pe.Setter = pe.PropertyInfo.Set;
2915 // TODO: It's used by EventExpr -> FieldExpr transformation only
2916 // TODO: Should go to MemberAccess
2917 me = me.ResolveMemberAccess (rc, null, null);
2920 targs.Resolve (rc, false);
2921 me.SetTypeArguments (rc, targs);
2928 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2930 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2931 if (IsPossibleTypeOrNamespace (rc)) {
2932 return ResolveAsTypeOrNamespace (rc, false);
2936 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2939 targs.Resolve (rc, false);
2941 var me = expr as MemberExpr;
2943 me.SetTypeArguments (rc, targs);
2948 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2949 return new NameOf (this);
2952 if (variable_found) {
2953 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2956 var tparams = rc.CurrentTypeParameters;
2957 if (tparams != null) {
2958 if (tparams.Find (Name) != null) {
2959 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2964 var ct = rc.CurrentType;
2966 if (ct.MemberDefinition.TypeParametersCount > 0) {
2967 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2968 if (ctp.Name == Name) {
2969 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2975 ct = ct.DeclaringType;
2976 } while (ct != null);
2979 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2980 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2982 rc.Report.SymbolRelatedToPreviousError (e.Type);
2983 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2987 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2989 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2990 return ErrorExpression.Instance;
2994 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2996 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2997 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
3001 if (e is TypeExpr) {
3002 // TypeExpression does not have correct location
3003 if (e is TypeExpression)
3004 e = new TypeExpression (e.Type, loc);
3010 Error_NameDoesNotExist (rc);
3013 return ErrorExpression.Instance;
3016 if (rc.Module.Evaluator != null) {
3017 var fi = rc.Module.Evaluator.LookupField (Name);
3019 return new FieldExpr (fi.Item1, loc);
3027 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3029 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3034 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3035 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3039 if (right_side != null) {
3040 e = e.ResolveLValue (ec, right_side);
3048 public override object Accept (StructuralVisitor visitor)
3050 return visitor.Visit (this);
3055 /// Represents a namespace or a type. The name of the class was inspired by
3056 /// section 10.8.1 (Fully Qualified Names).
3058 public abstract class FullNamedExpression : Expression
3060 protected override void CloneTo (CloneContext clonectx, Expression target)
3062 // Do nothing, most unresolved type expressions cannot be
3063 // resolved to different type
3066 public override bool ContainsEmitWithAwait ()
3071 public override Expression CreateExpressionTree (ResolveContext ec)
3073 throw new NotSupportedException ("ET");
3076 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3079 // This is used to resolve the expression as a type, a null
3080 // value will be returned if the expression is not a type
3083 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3085 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3090 TypeExpr te = fne as TypeExpr;
3092 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3100 var dep = type.GetMissingDependencies ();
3102 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3105 if (type.Kind == MemberKind.Void) {
3106 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3110 // Obsolete checks cannot be done when resolving base context as they
3111 // require type dependencies to be set but we are in process of resolving them
3113 if (mc is ResolveContext) {
3114 var oa = type.GetAttributeObsolete ();
3115 if (oa != null && !mc.IsObsolete)
3116 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3123 public override void Emit (EmitContext ec)
3125 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3126 GetSignatureForError ());
3131 /// Expression that evaluates to a type
3133 public abstract class TypeExpr : FullNamedExpression
3135 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3141 protected sealed override Expression DoResolve (ResolveContext ec)
3147 public override bool Equals (object obj)
3149 TypeExpr tobj = obj as TypeExpr;
3153 return Type == tobj.Type;
3156 public override int GetHashCode ()
3158 return Type.GetHashCode ();
3163 /// Fully resolved Expression that already evaluated to a type
3165 public class TypeExpression : TypeExpr
3167 public TypeExpression (TypeSpec t, Location l)
3170 eclass = ExprClass.Type;
3174 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3180 public class NamespaceExpression : FullNamedExpression
3182 readonly Namespace ns;
3184 public NamespaceExpression (Namespace ns, Location loc)
3187 this.Type = InternalType.Namespace;
3188 this.eclass = ExprClass.Namespace;
3192 public Namespace Namespace {
3198 protected override Expression DoResolve (ResolveContext rc)
3200 throw new NotImplementedException ();
3203 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3208 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3210 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3211 if (retval != null) {
3212 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3213 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3217 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3218 if (retval != null) {
3219 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3224 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3225 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3229 string assembly = null;
3230 string possible_name = Namespace.GetSignatureForError () + "." + name;
3232 // Only assembly unique name should be added
3233 switch (possible_name) {
3234 case "System.Drawing":
3235 case "System.Web.Services":
3238 case "System.Configuration":
3239 case "System.Data.Services":
3240 case "System.DirectoryServices":
3242 case "System.Net.Http":
3243 case "System.Numerics":
3244 case "System.Runtime.Caching":
3245 case "System.ServiceModel":
3246 case "System.Transactions":
3247 case "System.Web.Routing":
3248 case "System.Xml.Linq":
3250 assembly = possible_name;
3254 case "System.Linq.Expressions":
3255 assembly = "System.Core";
3258 case "System.Windows.Forms":
3259 case "System.Windows.Forms.Layout":
3260 assembly = "System.Windows.Forms";
3264 assembly = assembly == null ? "an" : "`" + assembly + "'";
3266 if (Namespace is GlobalRootNamespace) {
3267 ctx.Module.Compiler.Report.Error (400, loc,
3268 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3271 ctx.Module.Compiler.Report.Error (234, loc,
3272 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3273 name, GetSignatureForError (), assembly);
3277 public override string GetSignatureForError ()
3279 return ns.GetSignatureForError ();
3282 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3284 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3287 public override string ToString ()
3289 return Namespace.Name;
3294 /// This class denotes an expression which evaluates to a member
3295 /// of a struct or a class.
3297 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3299 protected bool conditional_access_receiver;
3302 // An instance expression associated with this member, if it's a
3303 // non-static member
3305 public Expression InstanceExpression;
3308 /// The name of this member.
3310 public abstract string Name {
3315 // When base.member is used
3317 public bool IsBase {
3318 get { return InstanceExpression is BaseThis; }
3322 /// Whether this is an instance member.
3324 public abstract bool IsInstance {
3329 /// Whether this is a static member.
3331 public abstract bool IsStatic {
3335 public abstract string KindName {
3339 public bool ConditionalAccess { get; set; }
3341 protected abstract TypeSpec DeclaringType {
3345 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3347 return InstanceExpression.Type;
3352 // Converts best base candidate for virtual method starting from QueriedBaseType
3354 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3357 // Only when base.member is used and method is virtual
3363 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3364 // means for base.member access we have to find the closest match after we found best candidate
3366 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3368 // The method could already be what we are looking for
3370 TypeSpec[] targs = null;
3371 if (method.DeclaringType != InstanceExpression.Type) {
3373 // Candidate can have inflated MVAR parameters and we need to find
3374 // base match for original definition not inflated parameter types
3376 var parameters = method.Parameters;
3377 if (method.Arity > 0) {
3378 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3379 var inflated = method.DeclaringType as InflatedTypeSpec;
3380 if (inflated != null) {
3381 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3385 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3386 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3387 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3388 if (base_override.IsGeneric)
3389 targs = method.TypeArguments;
3391 method = base_override;
3396 // When base access is used inside anonymous method/iterator/etc we need to
3397 // get back to the context of original type. We do it by emiting proxy
3398 // method in original class and rewriting base call to this compiler
3399 // generated method call which does the actual base invocation. This may
3400 // introduce redundant storey but with `this' only but it's tricky to avoid
3401 // at this stage as we don't know what expressions follow base
3403 if (rc.CurrentAnonymousMethod != null) {
3404 if (targs == null && method.IsGeneric) {
3405 targs = method.TypeArguments;
3406 method = method.GetGenericMethodDefinition ();
3409 if (method.Parameters.HasArglist)
3410 throw new NotImplementedException ("__arglist base call proxy");
3412 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3414 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3415 // get/set member expressions second call would fail to proxy because left expression
3416 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3417 // FIXME: The async check is another hack but will probably fail with mutators
3418 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3419 InstanceExpression = new This (loc).Resolve (rc);
3423 method = method.MakeGenericMethod (rc, targs);
3427 // Only base will allow this invocation to happen.
3429 if (method.IsAbstract) {
3430 rc.Report.SymbolRelatedToPreviousError (method);
3431 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3437 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3439 if (InstanceExpression == null)
3442 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3443 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3444 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3449 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3451 if (InstanceExpression == null)
3454 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3457 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3459 var ct = rc.CurrentType;
3460 if (ct == qualifier)
3463 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3466 qualifier = qualifier.GetDefinition ();
3467 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3474 public override bool ContainsEmitWithAwait ()
3476 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3479 public override bool HasConditionalAccess ()
3481 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3484 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3487 type = type.GetDefinition ();
3489 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3492 type = type.DeclaringType;
3493 } while (type != null);
3498 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3500 if (InstanceExpression != null) {
3501 InstanceExpression = InstanceExpression.Resolve (rc);
3502 CheckProtectedMemberAccess (rc, member);
3505 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3506 UnsafeError (rc, loc);
3509 var dep = member.GetMissingDependencies ();
3511 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3514 member.CheckObsoleteness (rc, loc);
3516 if (!(member is FieldSpec))
3517 member.MemberDefinition.SetIsUsed ();
3520 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3522 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3525 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3527 rc.Report.SymbolRelatedToPreviousError (member);
3528 rc.Report.Error (1540, loc,
3529 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3530 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3533 public override void FlowAnalysis (FlowAnalysisContext fc)
3535 if (InstanceExpression != null) {
3536 InstanceExpression.FlowAnalysis (fc);
3540 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3542 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3543 conditional_access_receiver = true;
3547 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3549 if (!ResolveInstanceExpressionCore (rc, rhs))
3553 // Check intermediate value modification which won't have any effect
3555 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3556 var fexpr = InstanceExpression as FieldExpr;
3557 if (fexpr != null) {
3558 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3561 if (fexpr.IsStatic) {
3562 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3563 fexpr.GetSignatureForError ());
3565 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3566 fexpr.GetSignatureForError ());
3572 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3573 if (rc.CurrentInitializerVariable != null) {
3574 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3575 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3577 rc.Report.Error (1612, loc,
3578 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3579 InstanceExpression.GetSignatureForError ());
3585 var lvr = InstanceExpression as LocalVariableReference;
3588 if (!lvr.local_info.IsReadonly)
3591 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3592 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3599 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3602 if (InstanceExpression != null) {
3603 if (InstanceExpression is TypeExpr) {
3604 var t = InstanceExpression.Type;
3606 t.CheckObsoleteness (rc, loc);
3608 t = t.DeclaringType;
3609 } while (t != null);
3611 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3612 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3613 rc.Report.Error (176, loc,
3614 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3615 GetSignatureForError ());
3619 InstanceExpression = null;
3625 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3626 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3627 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3628 rc.Report.Error (236, loc,
3629 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3630 GetSignatureForError ());
3632 var fe = this as FieldExpr;
3633 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3634 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3635 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3637 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3641 rc.Report.Error (120, loc,
3642 "An object reference is required to access non-static member `{0}'",
3643 GetSignatureForError ());
3647 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3651 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3652 rc.Report.Error (38, loc,
3653 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3654 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3657 InstanceExpression = new This (loc).Resolve (rc);
3661 var me = InstanceExpression as MemberExpr;
3663 me.ResolveInstanceExpressionCore (rc, rhs);
3665 var fe = me as FieldExpr;
3666 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3667 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3668 rc.Report.Warning (1690, 1, loc,
3669 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3670 me.GetSignatureForError ());
3677 // Additional checks for l-value member access
3680 if (InstanceExpression is UnboxCast) {
3681 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3688 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3690 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3691 ec.Report.Warning (1720, 1, left.Location,
3692 "Expression will always cause a `{0}'", "System.NullReferenceException");
3695 InstanceExpression = left;
3699 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3701 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3702 inst.Emit (ec, ConditionalAccess);
3704 if (prepare_for_load)
3705 ec.Emit (OpCodes.Dup);
3708 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3711 public class ExtensionMethodCandidates
3713 readonly NamespaceContainer container;
3714 readonly IList<MethodSpec> methods;
3716 readonly IMemberContext context;
3718 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3720 this.context = context;
3721 this.methods = methods;
3722 this.container = nsContainer;
3723 this.index = lookupIndex;
3726 public NamespaceContainer Container {
3732 public IMemberContext Context {
3738 public int LookupIndex {
3744 public IList<MethodSpec> Methods {
3752 // Represents a group of extension method candidates for whole namespace
3754 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3756 ExtensionMethodCandidates candidates;
3757 public Expression ExtensionExpression;
3759 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3760 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3762 this.candidates = candidates;
3763 this.ExtensionExpression = extensionExpr;
3766 public override bool IsStatic {
3767 get { return true; }
3771 // For extension methodgroup we are not looking for base members but parent
3772 // namespace extension methods
3774 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3776 // TODO: candidates are null only when doing error reporting, that's
3777 // incorrect. We have to discover same extension methods in error mode
3778 if (candidates == null)
3781 int arity = type_arguments == null ? 0 : type_arguments.Count;
3783 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3784 if (candidates == null)
3787 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3790 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3793 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3795 // LAMESPEC: or implicit type parameter conversion
3797 return argType == extensionType ||
3798 TypeSpecComparer.IsEqual (argType, extensionType) ||
3799 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3800 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3803 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3805 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3807 // Not included in C#6
3809 ExtensionExpression = ExtensionExpression.Resolve (rc);
3810 if (ExtensionExpression == null)
3813 var argType = ExtensionExpression.Type;
3814 foreach (MethodSpec candidate in Candidates) {
3815 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3819 // TODO: Scan full hierarchy
3821 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3826 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3828 // We are already here
3832 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3834 if (arguments == null)
3835 arguments = new Arguments (1);
3837 ExtensionExpression = ExtensionExpression.Resolve (ec);
3838 if (ExtensionExpression == null)
3841 var cand = candidates;
3842 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3843 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3844 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3846 // Restore candidates in case we are running in probing mode
3849 // Store resolved argument and restore original arguments
3851 // Clean-up modified arguments for error reporting
3852 arguments.RemoveAt (0);
3856 var me = ExtensionExpression as MemberExpr;
3858 me.ResolveInstanceExpression (ec, null);
3859 var fe = me as FieldExpr;
3861 fe.Spec.MemberDefinition.SetIsUsed ();
3864 InstanceExpression = null;
3868 #region IErrorHandler Members
3870 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3875 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3877 rc.Report.SymbolRelatedToPreviousError (best);
3880 rc.Report.Error (1929, loc,
3881 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3882 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3884 rc.Report.Error (1928, loc,
3885 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3886 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3892 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3897 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3906 /// MethodGroupExpr represents a group of method candidates which
3907 /// can be resolved to the best method overload
3909 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3911 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3913 protected IList<MemberSpec> Methods;
3914 MethodSpec best_candidate;
3915 TypeSpec best_candidate_return;
3916 protected TypeArguments type_arguments;
3918 SimpleName simple_name;
3919 protected TypeSpec queried_type;
3921 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3925 this.type = InternalType.MethodGroup;
3927 eclass = ExprClass.MethodGroup;
3928 queried_type = type;
3931 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3932 : this (new MemberSpec[] { m }, type, loc)
3938 public MethodSpec BestCandidate {
3940 return best_candidate;
3944 public TypeSpec BestCandidateReturnType {
3946 return best_candidate_return;
3950 public IList<MemberSpec> Candidates {
3956 protected override TypeSpec DeclaringType {
3958 return queried_type;
3962 public bool IsConditionallyExcluded {
3964 return Methods == Excluded;
3968 public override bool IsInstance {
3970 if (best_candidate != null)
3971 return !best_candidate.IsStatic;
3977 public override bool IsSideEffectFree {
3979 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3983 public override bool IsStatic {
3985 if (best_candidate != null)
3986 return best_candidate.IsStatic;
3992 public override string KindName {
3993 get { return "method"; }
3996 public override string Name {
3998 if (best_candidate != null)
3999 return best_candidate.Name;
4002 return Methods.First ().Name;
4009 // When best candidate is already know this factory can be used
4010 // to avoid expensive overload resolution to be called
4012 // NOTE: InstanceExpression has to be set manually
4014 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4016 return new MethodGroupExpr (best, queriedType, loc) {
4017 best_candidate = best,
4018 best_candidate_return = best.ReturnType
4022 public override string GetSignatureForError ()
4024 if (best_candidate != null)
4025 return best_candidate.GetSignatureForError ();
4027 return Methods.First ().GetSignatureForError ();
4030 public override Expression CreateExpressionTree (ResolveContext ec)
4032 if (best_candidate == null) {
4033 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4037 if (IsConditionallyExcluded)
4038 ec.Report.Error (765, loc,
4039 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4041 if (ConditionalAccess)
4042 Error_NullShortCircuitInsideExpressionTree (ec);
4044 return new TypeOfMethod (best_candidate, loc);
4047 protected override Expression DoResolve (ResolveContext ec)
4049 this.eclass = ExprClass.MethodGroup;
4051 if (InstanceExpression != null) {
4052 InstanceExpression = InstanceExpression.Resolve (ec);
4053 if (InstanceExpression == null)
4060 public override void Emit (EmitContext ec)
4062 throw new NotSupportedException ();
4065 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4067 var call = new CallEmitter ();
4068 call.InstanceExpression = InstanceExpression;
4069 call.ConditionalAccess = ConditionalAccess;
4072 call.EmitStatement (ec, best_candidate, arguments, loc);
4074 call.Emit (ec, best_candidate, arguments, loc);
4077 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4079 var ca = ec.ConditionalAccess;
4080 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4081 Statement = statement
4084 EmitCall (ec, arguments, statement);
4086 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4087 ec.ConditionalAccess = ca;
4090 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4092 if (target != InternalType.ErrorType) {
4093 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4094 Name, target.GetSignatureForError ());
4098 public bool HasAccessibleCandidate (ResolveContext rc)
4100 foreach (var candidate in Candidates) {
4101 if (candidate.IsAccessible (rc))
4108 public static bool IsExtensionMethodArgument (Expression expr)
4111 // LAMESPEC: No details about which expressions are not allowed
4113 return !(expr is TypeExpr) && !(expr is BaseThis);
4117 /// Find the Applicable Function Members (7.4.2.1)
4119 /// me: Method Group expression with the members to select.
4120 /// it might contain constructors or methods (or anything
4121 /// that maps to a method).
4123 /// Arguments: ArrayList containing resolved Argument objects.
4125 /// loc: The location if we want an error to be reported, or a Null
4126 /// location for "probing" purposes.
4128 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4129 /// that is the best match of me on Arguments.
4132 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4134 // TODO: causes issues with probing mode, remove explicit Kind check
4135 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4138 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4139 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4140 r.BaseMembersProvider = this;
4141 r.InstanceQualifier = this;
4144 if (cerrors != null)
4145 r.CustomErrors = cerrors;
4147 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4148 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4149 if (best_candidate == null) {
4150 if (!r.BestCandidateIsDynamic)
4153 if (simple_name != null && ec.IsStatic)
4154 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4159 // Overload resolver had to create a new method group, all checks bellow have already been executed
4160 if (r.BestCandidateNewMethodGroup != null)
4161 return r.BestCandidateNewMethodGroup;
4163 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4164 if (InstanceExpression != null) {
4165 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4166 InstanceExpression = null;
4168 if (simple_name != null && best_candidate.IsStatic) {
4169 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4172 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4176 ResolveInstanceExpression (ec, null);
4179 var base_override = CandidateToBaseOverride (ec, best_candidate);
4180 if (base_override == best_candidate) {
4181 best_candidate_return = r.BestCandidateReturnType;
4183 best_candidate = base_override;
4184 best_candidate_return = best_candidate.ReturnType;
4187 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4188 ConstraintChecker cc = new ConstraintChecker (ec);
4189 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4193 // Additional check for possible imported base override method which
4194 // could not be done during IsOverrideMethodBaseTypeAccessible
4196 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4197 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4198 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4199 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4202 // Speed up the check by not doing it on disallowed targets
4203 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4209 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4211 var fe = left as FieldExpr;
4214 // Using method-group on struct fields makes the struct assigned. I am not sure
4215 // why but that's what .net does
4217 fe.Spec.MemberDefinition.SetIsAssigned ();
4220 simple_name = original;
4221 return base.ResolveMemberAccess (ec, left, original);
4224 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4226 type_arguments = ta;
4229 #region IBaseMembersProvider Members
4231 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4233 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4236 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4238 if (queried_type == member.DeclaringType)
4241 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4242 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4246 // Extension methods lookup after ordinary methods candidates failed to apply
4248 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4250 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4253 if (!IsExtensionMethodArgument (InstanceExpression))
4256 int arity = type_arguments == null ? 0 : type_arguments.Count;
4257 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4258 if (methods == null)
4261 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4262 emg.SetTypeArguments (rc, type_arguments);
4263 emg.ConditionalAccess = ConditionalAccess;
4270 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4272 public ConstructorInstanceQualifier (TypeSpec type)
4275 InstanceType = type;
4278 public TypeSpec InstanceType { get; private set; }
4280 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4282 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4286 public struct OverloadResolver
4289 public enum Restrictions
4293 ProbingOnly = 1 << 1,
4294 CovariantDelegate = 1 << 2,
4295 NoBaseMembers = 1 << 3,
4296 BaseMembersIncluded = 1 << 4,
4297 GetEnumeratorLookup = 1 << 5
4300 public interface IBaseMembersProvider
4302 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4303 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4304 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4307 public interface IErrorHandler
4309 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4310 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4311 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4312 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4315 public interface IInstanceQualifier
4317 TypeSpec InstanceType { get; }
4318 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4321 sealed class NoBaseMembers : IBaseMembersProvider
4323 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4325 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4330 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4335 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4341 struct AmbiguousCandidate
4343 public readonly MemberSpec Member;
4344 public readonly bool Expanded;
4345 public readonly AParametersCollection Parameters;
4347 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4350 Parameters = parameters;
4351 Expanded = expanded;
4356 IList<MemberSpec> members;
4357 TypeArguments type_arguments;
4358 IBaseMembersProvider base_provider;
4359 IErrorHandler custom_errors;
4360 IInstanceQualifier instance_qualifier;
4361 Restrictions restrictions;
4362 MethodGroupExpr best_candidate_extension_group;
4363 TypeSpec best_candidate_return_type;
4365 SessionReportPrinter lambda_conv_msgs;
4367 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4368 : this (members, null, restrictions, loc)
4372 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4375 if (members == null || members.Count == 0)
4376 throw new ArgumentException ("empty members set");
4378 this.members = members;
4380 type_arguments = targs;
4381 this.restrictions = restrictions;
4382 if (IsDelegateInvoke)
4383 this.restrictions |= Restrictions.NoBaseMembers;
4385 base_provider = NoBaseMembers.Instance;
4390 public IBaseMembersProvider BaseMembersProvider {
4392 return base_provider;
4395 base_provider = value;
4399 public bool BestCandidateIsDynamic { get; set; }
4402 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4404 public MethodGroupExpr BestCandidateNewMethodGroup {
4406 return best_candidate_extension_group;
4411 // Return type can be different between best candidate and closest override
4413 public TypeSpec BestCandidateReturnType {
4415 return best_candidate_return_type;
4419 public IErrorHandler CustomErrors {
4421 return custom_errors;
4424 custom_errors = value;
4428 TypeSpec DelegateType {
4430 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4431 throw new InternalErrorException ("Not running in delegate mode", loc);
4433 return members [0].DeclaringType;
4437 public IInstanceQualifier InstanceQualifier {
4439 return instance_qualifier;
4442 instance_qualifier = value;
4446 bool IsProbingOnly {
4448 return (restrictions & Restrictions.ProbingOnly) != 0;
4452 bool IsDelegateInvoke {
4454 return (restrictions & Restrictions.DelegateInvoke) != 0;
4461 // 7.4.3.3 Better conversion from expression
4462 // Returns : 1 if a->p is better,
4463 // 2 if a->q is better,
4464 // 0 if neither is better
4466 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4468 TypeSpec argument_type = a.Type;
4471 // Exactly matching Expression phase
4475 // If argument is an anonymous function
4477 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4479 // p and q are delegate types or expression tree types
4481 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4482 if (q.MemberDefinition != p.MemberDefinition) {
4487 // Uwrap delegate from Expression<T>
4489 q = TypeManager.GetTypeArguments (q) [0];
4490 p = TypeManager.GetTypeArguments (p) [0];
4493 var p_m = Delegate.GetInvokeMethod (p);
4494 var q_m = Delegate.GetInvokeMethod (q);
4497 // With identical parameter lists
4499 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4507 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4509 if (p.Kind == MemberKind.Void) {
4510 return q.Kind != MemberKind.Void ? 2 : 0;
4514 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4516 if (q.Kind == MemberKind.Void) {
4517 return p.Kind != MemberKind.Void ? 1 : 0;
4520 var am = (AnonymousMethodExpression)a.Expr;
4523 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4524 // better conversion is performed between underlying types Y1 and Y2
4526 if (p.IsGenericTask || q.IsGenericTask) {
4527 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4528 q = q.TypeArguments [0];
4529 p = p.TypeArguments [0];
4535 // An inferred return type X exists for E in the context of the parameter list, and
4536 // an identity conversion exists from X to the return type of D
4538 var inferred_type = am.InferReturnType (ec, null, orig_q);
4539 if (inferred_type != null) {
4540 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4541 inferred_type = ec.BuiltinTypes.Object;
4543 if (inferred_type == p)
4546 if (inferred_type == q)
4552 if (argument_type == p)
4555 if (argument_type == q)
4558 return IsBetterConversionTarget (ec, p, q);
4561 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4563 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4565 if (p.Kind != MemberKind.Delegate) {
4566 p = TypeManager.GetTypeArguments (p) [0];
4569 if (q.Kind != MemberKind.Delegate) {
4570 q = TypeManager.GetTypeArguments (q) [0];
4573 var p_m = Delegate.GetInvokeMethod (p);
4574 var q_m = Delegate.GetInvokeMethod (q);
4580 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4582 if (p.Kind == MemberKind.Void) {
4583 return q.Kind != MemberKind.Void ? 2 : 0;
4587 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4589 if (q.Kind == MemberKind.Void) {
4590 return p.Kind != MemberKind.Void ? 1 : 0;
4593 return IsBetterConversionTarget (rc, p, q);
4596 if (p.IsGenericTask && q.IsGenericTask) {
4597 q = q.TypeArguments [0];
4598 p = p.TypeArguments [0];
4599 return IsBetterConversionTarget (rc, p, q);
4603 if (p.IsNullableType) {
4604 p = Nullable.NullableInfo.GetUnderlyingType (p);
4605 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4606 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4609 // Spec expects implicit conversion check between p and q, q and p
4610 // to be done before nullable unwrapping but that's expensive operation.
4612 // Extra manual tweak is needed because BetterTypeConversion works on
4620 if (q.IsNullableType) {
4621 q = Nullable.NullableInfo.GetUnderlyingType (q);
4622 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4623 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4629 return BetterTypeConversion (rc, p, q);
4633 // 7.4.3.4 Better conversion from type
4635 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4637 if (p == null || q == null)
4638 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4640 switch (p.BuiltinType) {
4641 case BuiltinTypeSpec.Type.Int:
4642 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4645 case BuiltinTypeSpec.Type.Long:
4646 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4649 case BuiltinTypeSpec.Type.SByte:
4650 switch (q.BuiltinType) {
4651 case BuiltinTypeSpec.Type.Byte:
4652 case BuiltinTypeSpec.Type.UShort:
4653 case BuiltinTypeSpec.Type.UInt:
4654 case BuiltinTypeSpec.Type.ULong:
4658 case BuiltinTypeSpec.Type.Short:
4659 switch (q.BuiltinType) {
4660 case BuiltinTypeSpec.Type.UShort:
4661 case BuiltinTypeSpec.Type.UInt:
4662 case BuiltinTypeSpec.Type.ULong:
4666 case BuiltinTypeSpec.Type.Dynamic:
4667 // LAMESPEC: Dynamic conversions is not considered
4668 p = ec.Module.Compiler.BuiltinTypes.Object;
4672 switch (q.BuiltinType) {
4673 case BuiltinTypeSpec.Type.Int:
4674 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4677 case BuiltinTypeSpec.Type.Long:
4678 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4681 case BuiltinTypeSpec.Type.SByte:
4682 switch (p.BuiltinType) {
4683 case BuiltinTypeSpec.Type.Byte:
4684 case BuiltinTypeSpec.Type.UShort:
4685 case BuiltinTypeSpec.Type.UInt:
4686 case BuiltinTypeSpec.Type.ULong:
4690 case BuiltinTypeSpec.Type.Short:
4691 switch (p.BuiltinType) {
4692 case BuiltinTypeSpec.Type.UShort:
4693 case BuiltinTypeSpec.Type.UInt:
4694 case BuiltinTypeSpec.Type.ULong:
4698 case BuiltinTypeSpec.Type.Dynamic:
4699 // LAMESPEC: Dynamic conversions is not considered
4700 q = ec.Module.Compiler.BuiltinTypes.Object;
4704 return BetterTypeConversionImplicitConversion (ec, p, q);
4707 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4709 // TODO: this is expensive
4710 Expression p_tmp = new EmptyExpression (p);
4711 Expression q_tmp = new EmptyExpression (q);
4713 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4714 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4716 if (p_to_q && !q_to_p)
4719 if (q_to_p && !p_to_q)
4726 /// Determines "Better function" between candidate
4727 /// and the current best match
4730 /// Returns a boolean indicating :
4731 /// false if candidate ain't better
4732 /// true if candidate is better than the current best match
4734 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4735 MemberSpec best, AParametersCollection bparam, bool best_params)
4737 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4738 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4740 int candidate_better_count = 0;
4741 int best_better_count = 0;
4743 bool are_equivalent = true;
4744 int args_count = args == null ? 0 : args.Count;
4748 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4751 // Default arguments are ignored for better decision
4752 if (a.IsDefaultArgument)
4756 // When comparing named argument the parameter type index has to be looked up
4757 // in original parameter set (override version for virtual members)
4759 NamedArgument na = a as NamedArgument;
4761 int idx = cparam.GetParameterIndexByName (na.Name);
4762 ct = candidate_pd.Types[idx];
4763 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4764 ct = TypeManager.GetElementType (ct);
4766 idx = bparam.GetParameterIndexByName (na.Name);
4767 bt = best_pd.Types[idx];
4768 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4769 bt = TypeManager.GetElementType (bt);
4771 ct = candidate_pd.Types[c_idx];
4772 bt = best_pd.Types[b_idx];
4774 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4775 ct = TypeManager.GetElementType (ct);
4779 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4780 bt = TypeManager.GetElementType (bt);
4785 if (TypeSpecComparer.IsEqual (ct, bt))
4788 are_equivalent = false;
4789 int result = BetterExpressionConversion (ec, a, ct, bt);
4791 // for each argument, the conversion to 'ct' should be no worse than
4792 // the conversion to 'bt'.
4795 // No optional parameters tie breaking rules for delegates overload resolution
4797 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4800 ++best_better_count;
4804 // for at least one argument, the conversion to 'ct' should be better than
4805 // the conversion to 'bt'.
4807 ++candidate_better_count;
4810 if (candidate_better_count != 0 && best_better_count == 0)
4813 if (best_better_count > 0 && candidate_better_count == 0)
4817 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4819 if (!are_equivalent) {
4820 while (j < args_count && !args [j++].IsDefaultArgument) ;
4823 // A candidate with no default parameters is still better when there
4824 // is no better expression conversion
4826 if (candidate_pd.Count < best_pd.Count) {
4827 if (!candidate_params && !candidate_pd.FixedParameters [j - j].HasDefaultValue) {
4830 } else if (candidate_pd.Count == best_pd.Count) {
4831 if (candidate_params)
4834 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4837 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4845 // If candidate is applicable in its normal form and best has a params array and is applicable
4846 // only in its expanded form, then candidate is better
4848 if (candidate_params != best_params)
4849 return !candidate_params;
4852 // We have not reached end of parameters list due to params or used default parameters
4854 bool defaults_ambiguity = false;
4855 while (j < candidate_pd.Count && j < best_pd.Count) {
4856 var cand_param = candidate_pd.FixedParameters [j];
4857 var best_param = best_pd.FixedParameters [j];
4859 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4860 return cand_param.HasDefaultValue;
4862 defaults_ambiguity = true;
4863 if (candidate_pd.Count == best_pd.Count) {
4867 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4868 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4870 if (cand_param.HasDefaultValue) {
4879 // Neither is better when not all arguments are provided
4881 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4882 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4883 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4888 if (candidate_pd.Count != best_pd.Count) {
4889 if (defaults_ambiguity && best_pd.Count - 1 == j)
4890 return best_pd.HasParams;
4892 return candidate_pd.Count < best_pd.Count;
4896 // One is a non-generic method and second is a generic method, then non-generic is better
4898 if (best.IsGeneric != candidate.IsGeneric)
4899 return best.IsGeneric;
4902 // Both methods have the same number of parameters, and the parameters have equal types
4903 // Pick the "more specific" signature using rules over original (non-inflated) types
4905 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4906 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4908 bool specific_at_least_once = false;
4909 for (j = 0; j < args_count; ++j) {
4910 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4912 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4913 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4915 ct = candidate_def_pd.Types[j];
4916 bt = best_def_pd.Types[j];
4921 TypeSpec specific = MoreSpecific (ct, bt);
4925 specific_at_least_once = true;
4928 if (specific_at_least_once)
4934 static bool CheckInflatedArguments (MethodSpec ms)
4936 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4939 // Setup constraint checker for probing only
4940 ConstraintChecker cc = new ConstraintChecker (null);
4942 var mp = ms.Parameters.Types;
4943 for (int i = 0; i < mp.Length; ++i) {
4944 var type = mp[i] as InflatedTypeSpec;
4948 var targs = type.TypeArguments;
4949 if (targs.Length == 0)
4952 // TODO: Checking inflated MVAR arguments should be enough
4953 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4960 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4962 rc.Report.Error (1729, loc,
4963 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4964 type.GetSignatureForError (), argCount.ToString ());
4968 // Determines if the candidate method is applicable to the given set of arguments
4969 // There could be two different set of parameters for same candidate where one
4970 // is the closest override for default values and named arguments checks and second
4971 // one being the virtual base for the parameter types and modifiers.
4973 // A return value rates candidate method compatibility,
4975 // 0 = the best, int.MaxValue = the worst
4977 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)
4980 // Each step has allocated 10 values, it can overflow for
4981 // more than 10 arguments but that's ok as it's used for
4982 // better error reporting only
4984 const int ArgumentCountMismatch = 1000000000;
4985 const int NamedArgumentsMismatch = 100000000;
4986 const int DefaultArgumentMismatch = 10000000;
4987 const int UnexpectedTypeArguments = 1000000;
4988 const int TypeArgumentsMismatch = 100000;
4989 const int InflatedTypesMismatch = 10000;
4991 // Parameters of most-derived type used mainly for named and optional parameters
4992 var pd = pm.Parameters;
4994 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4995 // params modifier instead of most-derived type
4996 var cpd = ((IParametersMember) candidate).Parameters;
4997 int param_count = pd.Count;
4998 int optional_count = 0;
5000 Arguments orig_args = arguments;
5002 if (arg_count != param_count) {
5004 // No arguments expansion when doing exact match for delegates
5006 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5007 for (int i = 0; i < pd.Count; ++i) {
5008 if (pd.FixedParameters[i].HasDefaultValue) {
5009 optional_count = pd.Count - i;
5015 if (optional_count != 0) {
5016 // Readjust expected number when params used
5017 if (cpd.HasParams) {
5019 if (arg_count < param_count)
5021 } else if (arg_count > param_count) {
5022 int args_gap = System.Math.Abs (arg_count - param_count);
5023 return ArgumentCountMismatch + args_gap;
5024 } else if (arg_count < param_count - optional_count) {
5025 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5026 return ArgumentCountMismatch + args_gap;
5028 } else if (arg_count != param_count) {
5029 int args_gap = System.Math.Abs (arg_count - param_count);
5031 return ArgumentCountMismatch + args_gap;
5032 if (arg_count < param_count - 1)
5033 return ArgumentCountMismatch + args_gap;
5036 // Resize to fit optional arguments
5037 if (optional_count != 0) {
5038 if (arguments == null) {
5039 arguments = new Arguments (optional_count);
5041 // Have to create a new container, so the next run can do same
5042 var resized = new Arguments (param_count);
5043 resized.AddRange (arguments);
5044 arguments = resized;
5047 for (int i = arg_count; i < param_count; ++i)
5048 arguments.Add (null);
5052 if (arg_count > 0) {
5054 // Shuffle named arguments to the right positions if there are any
5056 if (arguments[arg_count - 1] is NamedArgument) {
5057 arg_count = arguments.Count;
5059 for (int i = 0; i < arg_count; ++i) {
5060 bool arg_moved = false;
5062 NamedArgument na = arguments[i] as NamedArgument;
5066 int index = pd.GetParameterIndexByName (na.Name);
5068 // Named parameter not found
5070 return NamedArgumentsMismatch - i;
5072 // already reordered
5077 if (index >= param_count) {
5078 // When using parameters which should not be available to the user
5079 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5082 arguments.Add (null);
5086 if (index == arg_count)
5087 return NamedArgumentsMismatch - i - 1;
5089 temp = arguments [index];
5091 // The slot has been taken by positional argument
5092 if (temp != null && !(temp is NamedArgument))
5097 arguments = arguments.MarkOrderedArgument (na);
5101 if (arguments == orig_args) {
5102 arguments = new Arguments (orig_args.Count);
5103 arguments.AddRange (orig_args);
5106 arguments[index] = arguments[i];
5107 arguments[i] = temp;
5114 arg_count = arguments.Count;
5116 } else if (arguments != null) {
5117 arg_count = arguments.Count;
5121 // Don't do any expensive checks when the candidate cannot succeed
5123 if (arg_count != param_count && !cpd.HasParams)
5124 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5126 var dep = candidate.GetMissingDependencies ();
5128 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5133 // 1. Handle generic method using type arguments when specified or type inference
5136 var ms = candidate as MethodSpec;
5137 if (ms != null && ms.IsGeneric) {
5138 if (type_arguments != null) {
5139 var g_args_count = ms.Arity;
5140 if (g_args_count != type_arguments.Count)
5141 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5143 if (type_arguments.Arguments != null)
5144 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5147 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5148 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5149 // candidate was found use the set to report more details about what was wrong with lambda body.
5150 // The general idea is to distinguish between code errors and errors caused by
5151 // trial-and-error type inference
5153 if (lambda_conv_msgs == null) {
5154 for (int i = 0; i < arg_count; i++) {
5155 Argument a = arguments[i];
5159 var am = a.Expr as AnonymousMethodExpression;
5161 if (lambda_conv_msgs == null)
5162 lambda_conv_msgs = new SessionReportPrinter ();
5164 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5169 var ti = new TypeInference (arguments);
5170 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5173 return TypeArgumentsMismatch - ti.InferenceScore;
5176 // Clear any error messages when the result was success
5178 if (lambda_conv_msgs != null)
5179 lambda_conv_msgs.ClearSession ();
5181 if (i_args.Length != 0) {
5183 for (int i = 0; i < i_args.Length; ++i) {
5184 var ta = i_args [i];
5185 if (!ta.IsAccessible (ec))
5186 return TypeArgumentsMismatch - i;
5190 ms = ms.MakeGenericMethod (ec, i_args);
5195 // Type arguments constraints have to match for the method to be applicable
5197 if (!CheckInflatedArguments (ms)) {
5199 return InflatedTypesMismatch;
5203 // We have a generic return type and at same time the method is override which
5204 // means we have to also inflate override return type in case the candidate is
5205 // best candidate and override return type is different to base return type.
5207 // virtual Foo<T, object> with override Foo<T, dynamic>
5209 if (candidate != pm) {
5210 MethodSpec override_ms = (MethodSpec) pm;
5211 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5212 returnType = inflator.Inflate (returnType);
5214 returnType = ms.ReturnType;
5221 if (type_arguments != null)
5222 return UnexpectedTypeArguments;
5228 // 2. Each argument has to be implicitly convertible to method parameter
5230 Parameter.Modifier p_mod = 0;
5233 for (int i = 0; i < arg_count; i++) {
5234 Argument a = arguments[i];
5236 var fp = pd.FixedParameters[i];
5237 if (!fp.HasDefaultValue) {
5238 arguments = orig_args;
5239 return arg_count * 2 + 2;
5243 // Get the default value expression, we can use the same expression
5244 // if the type matches
5246 Expression e = fp.DefaultValue;
5248 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5250 // Restore for possible error reporting
5251 for (int ii = i; ii < arg_count; ++ii)
5252 arguments.RemoveAt (i);
5254 return (arg_count - i) * 2 + 1;
5258 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5260 // LAMESPEC: Attributes can be mixed together with build-in priority
5262 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5263 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5264 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5265 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5266 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5267 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5271 arguments[i] = new Argument (e, Argument.AType.Default);
5275 if (p_mod != Parameter.Modifier.PARAMS) {
5276 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5278 } else if (!params_expanded_form) {
5279 params_expanded_form = true;
5280 pt = ((ElementTypeSpec) pt).Element;
5286 if (!params_expanded_form) {
5287 if (a.IsExtensionType) {
5288 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5293 score = IsArgumentCompatible (ec, a, p_mod, pt);
5296 dynamicArgument = true;
5301 // It can be applicable in expanded form (when not doing exact match like for delegates)
5303 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5304 if (!params_expanded_form) {
5305 pt = ((ElementTypeSpec) pt).Element;
5309 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5312 params_expanded_form = true;
5313 dynamicArgument = true;
5314 } else if (score == 0 || arg_count > pd.Count) {
5315 params_expanded_form = true;
5320 if (params_expanded_form)
5322 return (arg_count - i) * 2 + score;
5327 // Restore original arguments for dynamic binder to keep the intention of original source code
5329 if (dynamicArgument)
5330 arguments = orig_args;
5335 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5337 if (e is Constant && e.Type == ptype)
5341 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5343 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5344 e = new MemberAccess (new MemberAccess (new MemberAccess (
5345 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5346 } else if (e is Constant) {
5348 // Handles int to int? conversions, DefaultParameterValue check
5350 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5354 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5357 return e.Resolve (ec);
5361 // Tests argument compatibility with the parameter
5362 // The possible return values are
5364 // 1 - modifier mismatch
5365 // 2 - type mismatch
5366 // -1 - dynamic binding required
5368 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5371 // Types have to be identical when ref or out modifer
5372 // is used and argument is not of dynamic type
5374 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5375 var arg_type = argument.Type;
5377 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5379 // Using dynamic for ref/out parameter can still succeed at runtime
5381 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5387 if (arg_type != parameter) {
5388 if (arg_type == InternalType.VarOutType)
5392 // Do full equality check after quick path
5394 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5396 // Using dynamic for ref/out parameter can still succeed at runtime
5398 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5406 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5410 // Use implicit conversion in all modes to return same candidates when the expression
5411 // is used as argument or delegate conversion
5413 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5414 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5421 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5423 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5425 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5428 var ac_p = p as ArrayContainer;
5430 var ac_q = q as ArrayContainer;
5434 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5435 if (specific == ac_p.Element)
5437 if (specific == ac_q.Element)
5439 } else if (p.IsGeneric && q.IsGeneric) {
5440 var pargs = TypeManager.GetTypeArguments (p);
5441 var qargs = TypeManager.GetTypeArguments (q);
5443 bool p_specific_at_least_once = false;
5444 bool q_specific_at_least_once = false;
5446 for (int i = 0; i < pargs.Length; i++) {
5447 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5448 if (specific == pargs[i])
5449 p_specific_at_least_once = true;
5450 if (specific == qargs[i])
5451 q_specific_at_least_once = true;
5454 if (p_specific_at_least_once && !q_specific_at_least_once)
5456 if (!p_specific_at_least_once && q_specific_at_least_once)
5464 // Find the best method from candidate list
5466 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5468 List<AmbiguousCandidate> ambiguous_candidates = null;
5470 MemberSpec best_candidate;
5471 Arguments best_candidate_args = null;
5472 bool best_candidate_params = false;
5473 bool best_candidate_dynamic = false;
5474 int best_candidate_rate;
5475 IParametersMember best_parameter_member = null;
5477 int args_count = args != null ? args.Count : 0;
5479 Arguments candidate_args = args;
5480 bool error_mode = false;
5481 MemberSpec invocable_member = null;
5482 int applicable_candidates = 0;
5485 best_candidate = null;
5486 best_candidate_rate = int.MaxValue;
5488 var type_members = members;
5490 for (int i = 0; i < type_members.Count; ++i) {
5491 var member = type_members[i];
5494 // Methods in a base class are not candidates if any method in a derived
5495 // class is applicable
5497 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5501 if (!member.IsAccessible (rc))
5504 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5507 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5508 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5513 IParametersMember pm = member as IParametersMember;
5516 // Will use it later to report ambiguity between best method and invocable member
5518 if (Invocation.IsMemberInvocable (member))
5519 invocable_member = member;
5525 // Overload resolution is looking for base member but using parameter names
5526 // and default values from the closest member. That means to do expensive lookup
5527 // for the closest override for virtual or abstract members
5529 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5530 var override_params = base_provider.GetOverrideMemberParameters (member);
5531 if (override_params != null)
5532 pm = override_params;
5536 // Check if the member candidate is applicable
5538 bool params_expanded_form = false;
5539 bool dynamic_argument = false;
5540 TypeSpec rt = pm.MemberType;
5541 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5543 if (lambda_conv_msgs != null)
5544 lambda_conv_msgs.EndSession ();
5547 // How does it score compare to others
5549 if (candidate_rate < best_candidate_rate) {
5551 // Fatal error (missing dependency), cannot continue
5552 if (candidate_rate < 0)
5555 applicable_candidates = 1;
5556 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5557 // Only parameterless methods are considered
5559 best_candidate_rate = candidate_rate;
5560 best_candidate = member;
5561 best_candidate_args = candidate_args;
5562 best_candidate_params = params_expanded_form;
5563 best_candidate_dynamic = dynamic_argument;
5564 best_parameter_member = pm;
5565 best_candidate_return_type = rt;
5567 } else if (candidate_rate == 0) {
5569 // The member look is done per type for most operations but sometimes
5570 // it's not possible like for binary operators overload because they
5571 // are unioned between 2 sides
5573 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5574 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5578 ++applicable_candidates;
5580 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5582 // We pack all interface members into top level type which makes the overload resolution
5583 // more complicated for interfaces. We compensate it by removing methods with same
5584 // signature when building the cache hence this path should not really be hit often
5587 // interface IA { void Foo (int arg); }
5588 // interface IB : IA { void Foo (params int[] args); }
5590 // IB::Foo is the best overload when calling IB.Foo (1)
5593 if (ambiguous_candidates != null) {
5594 foreach (var amb_cand in ambiguous_candidates) {
5595 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5604 ambiguous_candidates = null;
5607 // Is the new candidate better
5608 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5612 best_candidate = member;
5613 best_candidate_args = candidate_args;
5614 best_candidate_params = params_expanded_form;
5615 best_candidate_dynamic = dynamic_argument;
5616 best_parameter_member = pm;
5617 best_candidate_return_type = rt;
5619 // It's not better but any other found later could be but we are not sure yet
5620 if (ambiguous_candidates == null)
5621 ambiguous_candidates = new List<AmbiguousCandidate> ();
5623 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5627 // Restore expanded arguments
5628 candidate_args = args;
5630 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5633 // We've found exact match
5635 if (best_candidate_rate == 0)
5639 // Try extension methods lookup when no ordinary method match was found and provider enables it
5642 var emg = base_provider.LookupExtensionMethod (rc);
5644 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5646 best_candidate_extension_group = emg;
5647 return (T) (MemberSpec) emg.BestCandidate;
5652 // Don't run expensive error reporting mode for probing
5659 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5662 lambda_conv_msgs = null;
5667 // No best member match found, report an error
5669 if (best_candidate_rate != 0 || error_mode) {
5670 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5674 if (best_candidate_dynamic) {
5675 if (args[0].IsExtensionType) {
5676 rc.Report.Error (1973, loc,
5677 "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",
5678 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5682 // Check type constraints only when explicit type arguments are used
5684 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5685 MethodSpec bc = best_candidate as MethodSpec;
5686 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5687 ConstraintChecker cc = new ConstraintChecker (rc);
5688 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5692 BestCandidateIsDynamic = true;
5697 // These flags indicates we are running delegate probing conversion. No need to
5698 // do more expensive checks
5700 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5701 return (T) best_candidate;
5703 if (ambiguous_candidates != null) {
5705 // Now check that there are no ambiguities i.e the selected method
5706 // should be better than all the others
5708 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5709 var candidate = ambiguous_candidates [ix];
5711 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5712 var ambiguous = candidate.Member;
5713 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5714 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5715 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5716 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5717 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5720 return (T) best_candidate;
5725 if (invocable_member != null && !IsProbingOnly) {
5726 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5727 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5728 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5729 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5733 // And now check if the arguments are all
5734 // compatible, perform conversions if
5735 // necessary etc. and return if everything is
5738 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5741 if (best_candidate == null)
5745 // Don't run possibly expensive checks in probing mode
5747 if (!IsProbingOnly && !rc.IsInProbingMode) {
5749 // Check ObsoleteAttribute on the best method
5751 best_candidate.CheckObsoleteness (rc, loc);
5753 best_candidate.MemberDefinition.SetIsUsed ();
5756 args = best_candidate_args;
5757 return (T) best_candidate;
5760 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5762 return ResolveMember<MethodSpec> (rc, ref args);
5765 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5766 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5768 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5771 if (a.Type == InternalType.ErrorType)
5774 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5775 ec.Report.SymbolRelatedToPreviousError (method);
5776 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5777 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5778 TypeManager.CSharpSignature (method));
5781 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5782 TypeManager.CSharpSignature (method));
5783 } else if (IsDelegateInvoke) {
5784 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5785 DelegateType.GetSignatureForError ());
5787 ec.Report.SymbolRelatedToPreviousError (method);
5788 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5789 method.GetSignatureForError ());
5792 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5794 string index = (idx + 1).ToString ();
5795 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5796 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5797 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5798 index, Parameter.GetModifierSignature (a.Modifier));
5800 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5801 index, Parameter.GetModifierSignature (mod));
5803 string p1 = a.GetSignatureForError ();
5804 string p2 = paramType.GetSignatureForError ();
5807 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5808 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5811 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5812 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5813 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5816 ec.Report.Error (1503, a.Expr.Location,
5817 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5822 // We have failed to find exact match so we return error info about the closest match
5824 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5826 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5827 int arg_count = args == null ? 0 : args.Count;
5829 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5830 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5831 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5835 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5840 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5841 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5842 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5846 // For candidates which match on parameters count report more details about incorrect arguments
5849 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5850 // Reject any inaccessible member
5851 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5852 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5853 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5857 var ms = best_candidate as MethodSpec;
5858 if (ms != null && ms.IsGeneric) {
5859 bool constr_ok = true;
5860 if (ms.TypeArguments != null)
5861 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5863 if (ta_count == 0 && ms.TypeArguments == null) {
5864 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5868 rc.Report.Error (411, loc,
5869 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5870 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5877 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5883 // We failed to find any method with correct argument count, report best candidate
5885 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5888 if (best_candidate.Kind == MemberKind.Constructor) {
5889 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5890 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5891 } else if (IsDelegateInvoke) {
5892 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5893 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5894 DelegateType.GetSignatureForError (), arg_count.ToString ());
5896 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5897 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5898 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5899 name, arg_count.ToString ());
5903 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5905 var p = ((IParametersMember)best_candidate).Parameters;
5910 for (int i = p.Count - 1; i != 0; --i) {
5911 var fp = p.FixedParameters [i];
5912 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5922 foreach (var arg in args) {
5923 var na = arg as NamedArgument;
5927 if (na.Name == name) {
5936 return args.Count + 1 == pm.Parameters.Count;
5939 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5941 var pd = pm.Parameters;
5942 var cpd = ((IParametersMember) member).Parameters;
5943 var ptypes = cpd.Types;
5945 Parameter.Modifier p_mod = 0;
5947 int a_idx = 0, a_pos = 0;
5949 ArrayInitializer params_initializers = null;
5950 bool has_unsafe_arg = pm.MemberType.IsPointer;
5951 int arg_count = args == null ? 0 : args.Count;
5953 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5958 if (p_mod != Parameter.Modifier.PARAMS) {
5959 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5961 has_unsafe_arg |= pt.IsPointer;
5963 if (p_mod == Parameter.Modifier.PARAMS) {
5964 if (chose_params_expanded) {
5965 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5966 pt = TypeManager.GetElementType (pt);
5972 // Types have to be identical when ref or out modifer is used
5974 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5975 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5978 var arg_type = a.Type;
5982 if (arg_type == InternalType.VarOutType) {
5984 // Set underlying variable type based on parameter type
5986 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5990 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5994 NamedArgument na = a as NamedArgument;
5996 int name_index = pd.GetParameterIndexByName (na.Name);
5997 if (name_index < 0 || name_index >= pd.Count) {
5998 if (IsDelegateInvoke) {
5999 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6000 ec.Report.Error (1746, na.Location,
6001 "The delegate `{0}' does not contain a parameter named `{1}'",
6002 DelegateType.GetSignatureForError (), na.Name);
6004 ec.Report.SymbolRelatedToPreviousError (member);
6005 ec.Report.Error (1739, na.Location,
6006 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6007 TypeManager.CSharpSignature (member), na.Name);
6009 } else if (args[name_index] != a && args[name_index] != null) {
6010 if (IsDelegateInvoke)
6011 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6013 ec.Report.SymbolRelatedToPreviousError (member);
6015 ec.Report.Error (1744, na.Location,
6016 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6021 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6024 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6025 if (a.IsExtensionType) {
6026 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6027 // CS1061 but that still better than confusing CS0123
6028 var ma = new MemberAccess (a.Expr, member.Name, loc);
6029 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6031 custom_errors.NoArgumentMatch (ec, member);
6037 if (a.IsExtensionType) {
6038 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6041 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6043 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6046 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6053 // Convert params arguments to an array initializer
6055 if (params_initializers != null) {
6056 // we choose to use 'a.Expr' rather than 'conv' so that
6057 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6058 params_initializers.Add (a.Expr);
6059 args.RemoveAt (a_idx--);
6065 // Update the argument with the implicit conversion
6069 if (a_idx != arg_count) {
6071 // Convert all var out argument to error type for less confusing error reporting
6072 // when no matching overload is found
6074 for (; a_idx < arg_count; a_idx++) {
6075 var arg = args [a_idx];
6079 if (arg.Type == InternalType.VarOutType) {
6080 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6084 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6089 // Fill not provided arguments required by params modifier
6091 if (params_initializers == null && arg_count + 1 == pd.Count) {
6093 args = new Arguments (1);
6095 pt = ptypes[pd.Count - 1];
6096 pt = TypeManager.GetElementType (pt);
6097 has_unsafe_arg |= pt.IsPointer;
6098 params_initializers = new ArrayInitializer (0, loc);
6102 // Append an array argument with all params arguments
6104 if (params_initializers != null) {
6105 args.Add (new Argument (
6106 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6110 if (has_unsafe_arg && !ec.IsUnsafe) {
6111 Expression.UnsafeError (ec, loc);
6115 // We could infer inaccesible type arguments
6117 if (type_arguments == null && member.IsGeneric) {
6118 var ms = (MethodSpec) member;
6119 foreach (var ta in ms.TypeArguments) {
6120 if (!ta.IsAccessible (ec)) {
6121 ec.Report.SymbolRelatedToPreviousError (ta);
6122 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6132 public class ConstantExpr : MemberExpr
6134 readonly ConstSpec constant;
6136 public ConstantExpr (ConstSpec constant, Location loc)
6138 this.constant = constant;
6142 public override string Name {
6143 get { throw new NotImplementedException (); }
6146 public override string KindName {
6147 get { return "constant"; }
6150 public override bool IsInstance {
6151 get { return !IsStatic; }
6154 public override bool IsStatic {
6155 get { return true; }
6158 protected override TypeSpec DeclaringType {
6159 get { return constant.DeclaringType; }
6162 public override Expression CreateExpressionTree (ResolveContext ec)
6164 throw new NotSupportedException ("ET");
6167 protected override Expression DoResolve (ResolveContext rc)
6169 ResolveInstanceExpression (rc, null);
6170 DoBestMemberChecks (rc, constant);
6172 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6173 eclass = ExprClass.Value;
6174 type = constant.MemberType;
6178 var c = constant.GetConstant (rc);
6180 // Creates reference expression to the constant value
6181 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6184 public override void Emit (EmitContext ec)
6186 throw new NotSupportedException ();
6189 public override string GetSignatureForError ()
6191 return constant.GetSignatureForError ();
6194 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6196 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6201 // Fully resolved expression that references a Field
6203 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6205 protected FieldSpec spec;
6206 VariableInfo variable_info;
6208 LocalTemporary temp;
6211 protected FieldExpr (Location l)
6216 public FieldExpr (FieldSpec spec, Location loc)
6221 type = spec.MemberType;
6224 public FieldExpr (FieldBase fi, Location l)
6231 public override string Name {
6237 public bool IsHoisted {
6239 IVariableReference hv = InstanceExpression as IVariableReference;
6240 return hv != null && hv.IsHoisted;
6244 public override bool IsInstance {
6246 return !spec.IsStatic;
6250 public override bool IsStatic {
6252 return spec.IsStatic;
6256 public override string KindName {
6257 get { return "field"; }
6260 public FieldSpec Spec {
6266 protected override TypeSpec DeclaringType {
6268 return spec.DeclaringType;
6272 public VariableInfo VariableInfo {
6274 return variable_info;
6280 public override string GetSignatureForError ()
6282 return spec.GetSignatureForError ();
6285 public bool IsMarshalByRefAccess (ResolveContext rc)
6287 // Checks possible ldflda of field access expression
6288 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6289 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6290 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6293 public void SetHasAddressTaken ()
6295 IVariableReference vr = InstanceExpression as IVariableReference;
6297 vr.SetHasAddressTaken ();
6301 protected override void CloneTo (CloneContext clonectx, Expression target)
6303 var t = (FieldExpr) target;
6305 if (InstanceExpression != null)
6306 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6309 public override Expression CreateExpressionTree (ResolveContext ec)
6311 if (ConditionalAccess) {
6312 Error_NullShortCircuitInsideExpressionTree (ec);
6315 return CreateExpressionTree (ec, true);
6318 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6321 Expression instance;
6323 if (InstanceExpression == null) {
6324 instance = new NullLiteral (loc);
6325 } else if (convertInstance) {
6326 instance = InstanceExpression.CreateExpressionTree (ec);
6328 args = new Arguments (1);
6329 args.Add (new Argument (InstanceExpression));
6330 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6333 args = Arguments.CreateForExpressionTree (ec, null,
6335 CreateTypeOfExpression ());
6337 return CreateExpressionFactoryCall (ec, "Field", args);
6340 public Expression CreateTypeOfExpression ()
6342 return new TypeOfField (spec, loc);
6345 protected override Expression DoResolve (ResolveContext ec)
6347 spec.MemberDefinition.SetIsUsed ();
6349 return DoResolve (ec, null);
6352 Expression DoResolve (ResolveContext ec, Expression rhs)
6354 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6357 ResolveConditionalAccessReceiver (ec);
6359 if (ResolveInstanceExpression (ec, rhs)) {
6360 // Resolve the field's instance expression while flow analysis is turned
6361 // off: when accessing a field "a.b", we must check whether the field
6362 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6364 if (lvalue_instance) {
6365 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6367 Expression right_side =
6368 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6370 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6372 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6375 if (InstanceExpression == null)
6379 DoBestMemberChecks (ec, spec);
6381 if (conditional_access_receiver)
6382 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6385 var fb = spec as FixedFieldSpec;
6386 IVariableReference var = InstanceExpression as IVariableReference;
6389 IFixedExpression fe = InstanceExpression as IFixedExpression;
6390 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6391 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6394 if (InstanceExpression.eclass != ExprClass.Variable) {
6395 ec.Report.SymbolRelatedToPreviousError (spec);
6396 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6397 TypeManager.GetFullNameSignature (spec));
6398 } else if (var != null && var.IsHoisted) {
6399 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6402 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6406 // Set flow-analysis variable info for struct member access. It will be check later
6407 // for precise error reporting
6409 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6410 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6413 if (conditional_access_receiver)
6414 type = LiftMemberType (ec, type);
6416 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6417 return Constant.CreateConstantFromValue (type, null, loc);
6419 eclass = ExprClass.Variable;
6423 public void SetFieldAssigned (FlowAnalysisContext fc)
6428 bool lvalue_instance = spec.DeclaringType.IsStruct;
6429 if (lvalue_instance) {
6430 var var = InstanceExpression as IVariableReference;
6431 if (var != null && var.VariableInfo != null) {
6432 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6436 var fe = InstanceExpression as FieldExpr;
6438 Expression instance;
6441 instance = fe.InstanceExpression;
6442 var fe_instance = instance as FieldExpr;
6443 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6444 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6445 var var = InstanceExpression as IVariableReference;
6446 if (var != null && var.VariableInfo == null) {
6447 var var_inst = instance as IVariableReference;
6448 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6449 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6453 if (fe_instance != null) {
6462 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6463 instance.FlowAnalysis (fc);
6465 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6466 InstanceExpression.FlowAnalysis (fc);
6470 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6472 // The return value is always null. Returning a value simplifies calling code.
6474 if (right_side == EmptyExpression.OutAccess) {
6476 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6477 GetSignatureForError ());
6479 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6480 GetSignatureForError ());
6486 if (right_side == EmptyExpression.LValueMemberAccess) {
6487 // Already reported as CS1648/CS1650
6491 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6493 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6494 GetSignatureForError ());
6496 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6497 GetSignatureForError ());
6503 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6504 GetSignatureForError ());
6506 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6507 GetSignatureForError ());
6513 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6515 if (HasConditionalAccess ())
6516 Error_NullPropagatingLValue (ec);
6518 if (spec is FixedFieldSpec) {
6519 // It could be much better error message but we want to be error compatible
6520 Error_ValueAssignment (ec, right_side);
6523 Expression e = DoResolve (ec, right_side);
6528 spec.MemberDefinition.SetIsAssigned ();
6530 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6531 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6532 ec.Report.Warning (420, 1, loc,
6533 "`{0}': A volatile field references will not be treated as volatile",
6534 spec.GetSignatureForError ());
6537 if (spec.IsReadOnly) {
6538 // InitOnly fields can only be assigned in constructors or initializers
6539 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6540 return Error_AssignToReadonly (ec, right_side);
6542 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6544 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6545 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6546 return Error_AssignToReadonly (ec, right_side);
6547 // static InitOnly fields cannot be assigned-to in an instance constructor
6548 if (IsStatic && !ec.IsStatic)
6549 return Error_AssignToReadonly (ec, right_side);
6550 // instance constructors can't modify InitOnly fields of other instances of the same type
6551 if (!IsStatic && !(InstanceExpression is This))
6552 return Error_AssignToReadonly (ec, right_side);
6556 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6557 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6558 ec.Report.Warning (197, 1, loc,
6559 "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",
6560 GetSignatureForError ());
6563 eclass = ExprClass.Variable;
6567 public override void FlowAnalysis (FlowAnalysisContext fc)
6569 var var = InstanceExpression as IVariableReference;
6571 var vi = var.VariableInfo;
6572 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6573 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6577 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6578 var le = SkipLeftValueTypeAccess (InstanceExpression);
6580 le.FlowAnalysis (fc);
6586 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6588 base.FlowAnalysis (fc);
6590 if (conditional_access_receiver)
6591 fc.DefiniteAssignment = da;
6594 static Expression SkipLeftValueTypeAccess (Expression expr)
6596 if (!TypeSpec.IsValueType (expr.Type))
6599 if (expr is VariableReference)
6602 var fe = expr as FieldExpr;
6606 if (fe.InstanceExpression == null)
6609 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6612 public override int GetHashCode ()
6614 return spec.GetHashCode ();
6617 public bool IsFixed {
6620 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6622 IVariableReference variable = InstanceExpression as IVariableReference;
6623 if (variable != null)
6624 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6626 IFixedExpression fe = InstanceExpression as IFixedExpression;
6627 return fe != null && fe.IsFixed;
6631 public override bool Equals (object obj)
6633 FieldExpr fe = obj as FieldExpr;
6637 if (spec != fe.spec)
6640 if (InstanceExpression == null || fe.InstanceExpression == null)
6643 return InstanceExpression.Equals (fe.InstanceExpression);
6646 public void Emit (EmitContext ec, bool leave_copy)
6648 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6652 ec.Emit (OpCodes.Volatile);
6654 ec.Emit (OpCodes.Ldsfld, spec);
6656 var ca = ec.ConditionalAccess;
6659 if (conditional_access_receiver)
6660 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6662 EmitInstance (ec, false);
6665 // Optimization for build-in types
6666 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6667 ec.EmitLoadFromPtr (type);
6669 var ff = spec as FixedFieldSpec;
6671 ec.Emit (OpCodes.Ldflda, spec);
6672 ec.Emit (OpCodes.Ldflda, ff.Element);
6675 ec.Emit (OpCodes.Volatile);
6677 ec.Emit (OpCodes.Ldfld, spec);
6681 if (conditional_access_receiver) {
6682 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6683 ec.ConditionalAccess = ca;
6688 ec.Emit (OpCodes.Dup);
6690 temp = new LocalTemporary (this.Type);
6696 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6698 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6699 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6704 if (ConditionalAccess)
6705 throw new NotImplementedException ("null operator assignment");
6707 if (has_await_source)
6708 source = source.EmitToField (ec);
6710 EmitInstance (ec, prepared);
6715 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6716 ec.Emit (OpCodes.Dup);
6718 temp = new LocalTemporary (this.Type);
6723 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6724 ec.Emit (OpCodes.Volatile);
6726 spec.MemberDefinition.SetIsAssigned ();
6729 ec.Emit (OpCodes.Stsfld, spec);
6731 ec.Emit (OpCodes.Stfld, spec);
6733 if (ec.NotifyEvaluatorOnStore) {
6735 throw new NotImplementedException ("instance field write");
6738 ec.Emit (OpCodes.Dup);
6740 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6751 // Emits store to field with prepared values on stack
6753 public void EmitAssignFromStack (EmitContext ec)
6756 ec.Emit (OpCodes.Stsfld, spec);
6758 ec.Emit (OpCodes.Stfld, spec);
6762 public override void Emit (EmitContext ec)
6767 public override void EmitSideEffect (EmitContext ec)
6769 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6771 if (is_volatile) // || is_marshal_by_ref ())
6772 base.EmitSideEffect (ec);
6775 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6777 if ((mode & AddressOp.Store) != 0)
6778 spec.MemberDefinition.SetIsAssigned ();
6779 if ((mode & AddressOp.Load) != 0)
6780 spec.MemberDefinition.SetIsUsed ();
6783 // Handle initonly fields specially: make a copy and then
6784 // get the address of the copy.
6787 if (spec.IsReadOnly){
6789 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6801 var temp = ec.GetTemporaryLocal (type);
6802 ec.Emit (OpCodes.Stloc, temp);
6803 ec.Emit (OpCodes.Ldloca, temp);
6809 ec.Emit (OpCodes.Ldsflda, spec);
6812 EmitInstance (ec, false);
6813 ec.Emit (OpCodes.Ldflda, spec);
6817 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6819 return MakeExpression (ctx);
6822 public override SLE.Expression MakeExpression (BuilderContext ctx)
6825 return base.MakeExpression (ctx);
6827 return SLE.Expression.Field (
6828 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6829 spec.GetMetaInfo ());
6833 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6835 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6841 // Expression that evaluates to a Property.
6843 // This is not an LValue because we need to re-write the expression. We
6844 // can not take data from the stack and store it.
6846 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6848 Arguments arguments;
6849 FieldExpr backing_field;
6851 public PropertyExpr (PropertySpec spec, Location l)
6854 best_candidate = spec;
6855 type = spec.MemberType;
6860 protected override Arguments Arguments {
6869 protected override TypeSpec DeclaringType {
6871 return best_candidate.DeclaringType;
6875 public override string Name {
6877 return best_candidate.Name;
6881 public bool IsAutoPropertyAccess {
6883 var prop = best_candidate.MemberDefinition as Property;
6884 return prop != null && prop.BackingField != null;
6888 public override bool IsInstance {
6894 public override bool IsStatic {
6896 return best_candidate.IsStatic;
6900 public override string KindName {
6901 get { return "property"; }
6904 public PropertySpec PropertyInfo {
6906 return best_candidate;
6912 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6914 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6917 var args_count = arguments == null ? 0 : arguments.Count;
6918 if (args_count != body.Parameters.Count && args_count == 0)
6921 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6922 mg.InstanceExpression = InstanceExpression;
6927 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6929 return new PropertyExpr (spec, loc) {
6935 public override Expression CreateExpressionTree (ResolveContext ec)
6937 if (ConditionalAccess) {
6938 Error_NullShortCircuitInsideExpressionTree (ec);
6942 if (IsSingleDimensionalArrayLength ()) {
6943 args = new Arguments (1);
6944 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6945 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6948 args = new Arguments (2);
6949 if (InstanceExpression == null)
6950 args.Add (new Argument (new NullLiteral (loc)));
6952 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6953 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6954 return CreateExpressionFactoryCall (ec, "Property", args);
6957 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6959 DoResolveLValue (rc, null);
6960 return new TypeOfMethod (Setter, loc);
6963 public override string GetSignatureForError ()
6965 return best_candidate.GetSignatureForError ();
6968 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6971 return base.MakeExpression (ctx);
6973 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6977 public override SLE.Expression MakeExpression (BuilderContext ctx)
6980 return base.MakeExpression (ctx);
6982 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6986 void Error_PropertyNotValid (ResolveContext ec)
6988 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6989 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6990 GetSignatureForError ());
6993 bool IsSingleDimensionalArrayLength ()
6995 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6998 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6999 return ac != null && ac.Rank == 1;
7002 public override void Emit (EmitContext ec, bool leave_copy)
7005 // Special case: length of single dimension array property is turned into ldlen
7007 if (IsSingleDimensionalArrayLength ()) {
7008 if (conditional_access_receiver) {
7009 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7012 EmitInstance (ec, false);
7014 ec.Emit (OpCodes.Ldlen);
7015 ec.Emit (OpCodes.Conv_I4);
7017 if (conditional_access_receiver) {
7018 ec.CloseConditionalAccess (type);
7024 base.Emit (ec, leave_copy);
7027 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7029 if (backing_field != null) {
7030 backing_field.EmitAssign (ec, source, false, false);
7035 LocalTemporary await_source_arg = null;
7037 if (isCompound && !(source is DynamicExpressionStatement)) {
7038 emitting_compound_assignment = true;
7041 if (has_await_arguments) {
7042 await_source_arg = new LocalTemporary (Type);
7043 await_source_arg.Store (ec);
7045 args = new Arguments (1);
7046 args.Add (new Argument (await_source_arg));
7049 temp = await_source_arg;
7052 has_await_arguments = false;
7057 ec.Emit (OpCodes.Dup);
7058 temp = new LocalTemporary (this.Type);
7063 args = arguments ?? new Arguments (1);
7067 temp = new LocalTemporary (this.Type);
7069 args.Add (new Argument (temp));
7071 args.Add (new Argument (source));
7075 emitting_compound_assignment = false;
7077 var call = new CallEmitter ();
7078 call.InstanceExpression = InstanceExpression;
7080 call.InstanceExpressionOnStack = true;
7082 if (ConditionalAccess) {
7083 call.ConditionalAccess = true;
7087 call.Emit (ec, Setter, args, loc);
7089 call.EmitStatement (ec, Setter, args, loc);
7096 if (await_source_arg != null) {
7097 await_source_arg.Release (ec);
7101 public override void FlowAnalysis (FlowAnalysisContext fc)
7103 var prop = best_candidate.MemberDefinition as Property;
7104 if (prop != null && prop.BackingField != null) {
7105 var var = InstanceExpression as IVariableReference;
7107 var vi = var.VariableInfo;
7108 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7109 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7113 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7118 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7120 base.FlowAnalysis (fc);
7122 if (conditional_access_receiver)
7123 fc.DefiniteAssignment = da;
7126 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7128 eclass = ExprClass.PropertyAccess;
7130 if (best_candidate.IsNotCSharpCompatible) {
7131 Error_PropertyNotValid (rc);
7134 ResolveInstanceExpression (rc, right_side);
7136 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7137 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7138 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7140 type = p.MemberType;
7144 DoBestMemberChecks (rc, best_candidate);
7146 // Handling of com-imported properties with any number of default property parameters
7147 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7148 var p = best_candidate.Get.Parameters;
7149 arguments = new Arguments (p.Count);
7150 for (int i = 0; i < p.Count; ++i) {
7151 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7153 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7154 var p = best_candidate.Set.Parameters;
7155 arguments = new Arguments (p.Count - 1);
7156 for (int i = 0; i < p.Count - 1; ++i) {
7157 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7164 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7166 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7169 var prop = best_candidate.MemberDefinition as Property;
7170 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7171 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7175 prop = (Property)ps.MemberDefinition;
7178 var spec = prop.BackingField;
7182 if (rc.IsStatic != spec.IsStatic)
7185 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7188 backing_field = new FieldExpr (prop.BackingField, loc);
7189 backing_field.ResolveLValue (rc, rhs);
7193 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7195 if (backing_field != null) {
7196 backing_field.SetFieldAssigned (fc);
7200 if (!IsAutoPropertyAccess)
7203 var prop = best_candidate.MemberDefinition as Property;
7204 if (prop != null && prop.BackingField != null) {
7205 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7206 if (lvalue_instance) {
7207 var var = InstanceExpression as IVariableReference;
7208 if (var != null && var.VariableInfo != null) {
7209 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7215 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7217 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7221 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7223 // getter and setter can be different for base calls
7224 MethodSpec getter, setter;
7225 protected T best_candidate;
7227 protected LocalTemporary temp;
7228 protected bool emitting_compound_assignment;
7229 protected bool has_await_arguments;
7231 protected PropertyOrIndexerExpr (Location l)
7238 protected abstract Arguments Arguments { get; set; }
7240 public MethodSpec Getter {
7249 public MethodSpec Setter {
7260 protected override Expression DoResolve (ResolveContext ec)
7262 if (eclass == ExprClass.Unresolved) {
7263 ResolveConditionalAccessReceiver (ec);
7265 var expr = OverloadResolve (ec, null);
7270 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7271 return expr.Resolve (ec);
7274 if (conditional_access_receiver) {
7275 type = LiftMemberType (ec, type);
7279 if (!ResolveGetter (ec))
7285 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7287 if (HasConditionalAccess ())
7288 Error_NullPropagatingLValue (rc);
7290 if (right_side == EmptyExpression.OutAccess) {
7291 // TODO: best_candidate can be null at this point
7292 INamedBlockVariable variable = null;
7293 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7294 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7295 best_candidate.Name);
7297 right_side.DoResolveLValue (rc, this);
7302 if (eclass == ExprClass.Unresolved) {
7303 var expr = OverloadResolve (rc, right_side);
7308 return expr.ResolveLValue (rc, right_side);
7310 ResolveInstanceExpression (rc, right_side);
7313 if (!best_candidate.HasSet) {
7314 if (ResolveAutopropertyAssignment (rc, right_side))
7317 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7318 GetSignatureForError ());
7322 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7323 if (best_candidate.HasDifferentAccessibility) {
7324 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7325 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7326 GetSignatureForError ());
7328 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7329 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7333 if (best_candidate.HasDifferentAccessibility)
7334 CheckProtectedMemberAccess (rc, best_candidate.Set);
7336 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7340 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7342 var ca = ec.ConditionalAccess;
7343 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7345 call.Emit (ec, method, arguments, loc);
7347 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7348 ec.ConditionalAccess = ca;
7352 // Implements the IAssignMethod interface for assignments
7354 public virtual void Emit (EmitContext ec, bool leave_copy)
7356 var call = new CallEmitter ();
7357 call.ConditionalAccess = ConditionalAccess;
7358 call.InstanceExpression = InstanceExpression;
7359 if (has_await_arguments)
7360 call.HasAwaitArguments = true;
7362 call.DuplicateArguments = emitting_compound_assignment;
7364 if (conditional_access_receiver)
7365 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7367 call.Emit (ec, Getter, Arguments, loc);
7369 if (call.HasAwaitArguments) {
7370 InstanceExpression = call.InstanceExpression;
7371 Arguments = call.EmittedArguments;
7372 has_await_arguments = true;
7376 ec.Emit (OpCodes.Dup);
7377 temp = new LocalTemporary (Type);
7382 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7384 public override void Emit (EmitContext ec)
7389 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7391 has_await_arguments = true;
7396 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7398 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7400 bool ResolveGetter (ResolveContext rc)
7402 if (!best_candidate.HasGet) {
7403 if (InstanceExpression != EmptyExpression.Null) {
7404 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7405 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7406 best_candidate.GetSignatureForError ());
7409 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7410 if (best_candidate.HasDifferentAccessibility) {
7411 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7412 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7413 TypeManager.CSharpSignature (best_candidate));
7415 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7416 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7420 if (best_candidate.HasDifferentAccessibility) {
7421 CheckProtectedMemberAccess (rc, best_candidate.Get);
7424 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7428 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7435 /// Fully resolved expression that evaluates to an Event
7437 public class EventExpr : MemberExpr, IAssignMethod
7439 readonly EventSpec spec;
7442 public EventExpr (EventSpec spec, Location loc)
7450 protected override TypeSpec DeclaringType {
7452 return spec.DeclaringType;
7456 public override string Name {
7462 public override bool IsInstance {
7464 return !spec.IsStatic;
7468 public override bool IsStatic {
7470 return spec.IsStatic;
7474 public override string KindName {
7475 get { return "event"; }
7478 public MethodSpec Operator {
7486 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7489 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7491 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7492 if (spec.BackingField != null &&
7493 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7495 spec.MemberDefinition.SetIsUsed ();
7497 spec.CheckObsoleteness (ec, loc);
7499 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7500 Error_AssignmentEventOnly (ec);
7502 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7504 InstanceExpression = null;
7506 return ml.ResolveMemberAccess (ec, left, original);
7510 return base.ResolveMemberAccess (ec, left, original);
7513 public override Expression CreateExpressionTree (ResolveContext ec)
7515 throw new NotSupportedException ("ET");
7518 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7520 if (right_side == EmptyExpression.EventAddition) {
7521 op = spec.AccessorAdd;
7522 } else if (right_side == EmptyExpression.EventSubtraction) {
7523 op = spec.AccessorRemove;
7527 Error_AssignmentEventOnly (ec);
7531 if (HasConditionalAccess ())
7532 Error_NullPropagatingLValue (ec);
7534 op = CandidateToBaseOverride (ec, op);
7538 protected override Expression DoResolve (ResolveContext ec)
7540 eclass = ExprClass.EventAccess;
7541 type = spec.MemberType;
7543 ResolveInstanceExpression (ec, null);
7545 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7546 Error_AssignmentEventOnly (ec);
7549 DoBestMemberChecks (ec, spec);
7553 public override void Emit (EmitContext ec)
7555 throw new NotSupportedException ();
7556 //Error_CannotAssign ();
7559 #region IAssignMethod Members
7561 public void Emit (EmitContext ec, bool leave_copy)
7563 throw new NotImplementedException ();
7566 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7568 if (leave_copy || !isCompound)
7569 throw new NotImplementedException ("EventExpr::EmitAssign");
7571 Arguments args = new Arguments (1);
7572 args.Add (new Argument (source));
7574 // TODO: Wrong, needs receiver
7575 // if (NullShortCircuit) {
7576 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7579 var call = new CallEmitter ();
7580 call.InstanceExpression = InstanceExpression;
7581 call.ConditionalAccess = ConditionalAccess;
7582 call.EmitStatement (ec, op, args, loc);
7584 // if (NullShortCircuit)
7585 // ec.CloseConditionalAccess (null);
7590 void Error_AssignmentEventOnly (ResolveContext ec)
7592 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7593 ec.Report.Error (79, loc,
7594 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7595 GetSignatureForError ());
7597 ec.Report.Error (70, loc,
7598 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7599 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7603 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7605 name = name.Substring (0, name.LastIndexOf ('.'));
7606 base.Error_CannotCallAbstractBase (rc, name);
7609 public override string GetSignatureForError ()
7611 return TypeManager.CSharpSignature (spec);
7614 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7616 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7620 public class TemporaryVariableReference : VariableReference
7622 public class Declarator : Statement
7624 TemporaryVariableReference variable;
7626 public Declarator (TemporaryVariableReference variable)
7628 this.variable = variable;
7632 protected override void DoEmit (EmitContext ec)
7634 variable.li.CreateBuilder (ec);
7637 public override void Emit (EmitContext ec)
7639 // Don't create sequence point
7643 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7648 protected override void CloneTo (CloneContext clonectx, Statement target)
7656 public TemporaryVariableReference (LocalVariable li, Location loc)
7659 this.type = li.Type;
7663 public override bool IsLockedByStatement {
7671 public LocalVariable LocalInfo {
7677 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7679 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7680 return new TemporaryVariableReference (li, loc);
7683 protected override Expression DoResolve (ResolveContext ec)
7685 eclass = ExprClass.Variable;
7688 // Don't capture temporary variables except when using
7689 // state machine redirection and block yields
7691 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7692 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7693 ec.IsVariableCapturingRequired) {
7694 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7695 storey.CaptureLocalVariable (ec, li);
7701 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7703 return Resolve (ec);
7706 public override void Emit (EmitContext ec)
7708 li.CreateBuilder (ec);
7713 public void EmitAssign (EmitContext ec, Expression source)
7715 li.CreateBuilder (ec);
7717 EmitAssign (ec, source, false, false);
7720 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7722 return li.HoistedVariant;
7725 public override bool IsFixed {
7726 get { return true; }
7729 public override bool IsRef {
7730 get { return false; }
7733 public override string Name {
7734 get { throw new NotImplementedException (); }
7737 public override void SetHasAddressTaken ()
7739 throw new NotImplementedException ();
7742 protected override ILocalVariable Variable {
7746 public override VariableInfo VariableInfo {
7747 get { return null; }
7752 /// Handles `var' contextual keyword; var becomes a keyword only
7753 /// if no type called var exists in a variable scope
7755 class VarExpr : SimpleName
7757 public VarExpr (Location loc)
7762 public bool InferType (ResolveContext ec, Expression right_side)
7765 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7767 type = right_side.Type;
7768 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7769 ec.Report.Error (815, loc,
7770 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7771 type.GetSignatureForError ());
7772 type = InternalType.ErrorType;
7776 eclass = ExprClass.Variable;
7780 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7782 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7783 base.Error_TypeOrNamespaceNotFound (ec);
7785 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");