2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression
131 public ExprClass eclass;
132 protected TypeSpec type;
133 protected Location loc;
135 public TypeSpec Type {
137 set { type = value; }
140 public virtual bool IsSideEffectFree {
146 public Location Location {
150 public virtual bool IsNull {
157 // Used to workaround parser limitation where we cannot get
158 // start of statement expression location
160 public virtual Location StartLocation {
166 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
169 // Return method-group expression when the expression can be used as
170 // lambda replacement. A good example is array sorting where instead of
173 // Array.Sort (s, (a, b) => String.Compare (a, b));
175 // we can use method group directly
177 // Array.Sort (s, String.Compare);
179 // Correct overload will be used because we do the reduction after
180 // best candidate was found.
186 // Returns true when the expression during Emit phase breaks stack
187 // by using await expression
189 public virtual bool ContainsEmitWithAwait ()
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 protected abstract Expression DoResolve (ResolveContext rc);
223 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
234 var rc = mc as ResolveContext ?? new ResolveContext (mc);
235 Expression e = Resolve (rc);
237 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
242 protected void CheckExpressionVariable (ResolveContext rc)
244 if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) {
245 rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers");
246 } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) {
247 rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause");
251 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
253 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
256 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
258 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
261 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
263 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
264 name, type.GetSignatureForError ());
267 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
269 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
272 public void Error_InvalidExpressionStatement (BlockContext bc)
274 Error_InvalidExpressionStatement (bc.Report, loc);
277 public void Error_InvalidExpressionStatement (Report report)
279 Error_InvalidExpressionStatement (report, loc);
282 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
284 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
287 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
289 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
292 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
294 // The error was already reported as CS1660
295 if (type == InternalType.AnonymousMethod)
298 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
301 if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
302 target.MemberDefinition.DeclaringAssembly.IsMissing)
305 string from_type = type.GetSignatureForError ();
306 string to_type = target.GetSignatureForError ();
307 if (from_type == to_type) {
308 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
309 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
313 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
318 ec.Report.DisableReporting ();
319 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
320 ec.Report.EnableReporting ();
323 ec.Report.Error (266, loc,
324 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
327 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
332 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
334 // Better message for possible generic expressions
335 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
336 var report = context.Module.Compiler.Report;
337 report.SymbolRelatedToPreviousError (member);
338 if (member is TypeSpec)
339 member = ((TypeSpec) member).GetDefinition ();
341 member = ((MethodSpec) member).GetGenericMethodDefinition ();
343 string name = member.Kind == MemberKind.Method ? "method" : "type";
344 if (member.IsGeneric) {
345 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
346 name, member.GetSignatureForError (), member.Arity.ToString ());
348 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
349 name, member.GetSignatureForError ());
352 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
356 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
358 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
362 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
364 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
367 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
369 ec.Report.SymbolRelatedToPreviousError (type);
370 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
371 type.GetSignatureForError (), name);
374 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
376 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
377 // Already reported as CS1612
378 } else if (rhs == EmptyExpression.OutAccess) {
379 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
381 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
385 protected void Error_VoidPointerOperation (ResolveContext rc)
387 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
390 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
392 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
395 public ResolveFlags ExprClassToResolveFlags {
399 case ExprClass.Namespace:
400 return ResolveFlags.Type;
402 case ExprClass.MethodGroup:
403 return ResolveFlags.MethodGroup;
405 case ExprClass.TypeParameter:
406 return ResolveFlags.TypeParameter;
408 case ExprClass.Value:
409 case ExprClass.Variable:
410 case ExprClass.PropertyAccess:
411 case ExprClass.EventAccess:
412 case ExprClass.IndexerAccess:
413 return ResolveFlags.VariableOrValue;
416 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
422 // Implements identical simple name and type-name resolution
424 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
427 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
430 // 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
431 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
433 if (left is MemberExpr || left is VariableReference) {
434 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
435 if (identical_type != null && identical_type.Type == left.Type)
436 return identical_type;
442 public virtual string GetSignatureForError ()
444 return type.GetDefinition ().GetSignatureForError ();
447 public static bool IsNeverNull (Expression expr)
449 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
452 var c = expr as Constant;
456 var tc = expr as TypeCast;
458 return IsNeverNull (tc.Child);
463 protected static bool IsNullPropagatingValid (TypeSpec type)
466 case MemberKind.Struct:
467 return type.IsNullableType;
468 case MemberKind.Enum:
469 case MemberKind.Void:
470 case MemberKind.PointerType:
472 case MemberKind.InternalCompilerType:
473 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
474 case MemberKind.TypeParameter:
475 return !((TypeParameterSpec) type).IsValueType;
481 public virtual bool HasConditionalAccess ()
486 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
488 var tps = type as TypeParameterSpec;
489 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
490 Error_OperatorCannotBeApplied (rc, loc, "?", type);
493 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
494 Nullable.NullableInfo.MakeType (rc.Module, type) :
499 /// Resolves an expression and performs semantic analysis on it.
503 /// Currently Resolve wraps DoResolve to perform sanity
504 /// checking and assertion checking on what we expect from Resolve.
506 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
508 if (eclass != ExprClass.Unresolved) {
509 if ((flags & ExprClassToResolveFlags) == 0) {
510 Error_UnexpectedKind (ec, flags, loc);
524 if ((flags & e.ExprClassToResolveFlags) == 0) {
525 e.Error_UnexpectedKind (ec, flags, loc);
530 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
533 } catch (Exception ex) {
534 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
535 ec.Report.Printer is NullReportPrinter)
538 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
539 return ErrorExpression.Instance; // TODO: Add location
544 /// Resolves an expression and performs semantic analysis on it.
546 public Expression Resolve (ResolveContext rc)
548 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
552 /// Resolves an expression for LValue assignment
556 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
557 /// checking and assertion checking on what we expect from Resolve
559 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
561 int errors = ec.Report.Errors;
562 bool out_access = right_side == EmptyExpression.OutAccess;
564 Expression e = DoResolveLValue (ec, right_side);
566 if (e != null && out_access && !(e is IMemoryLocation)) {
567 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
568 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
570 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
571 // e.GetType () + " " + e.GetSignatureForError ());
576 if (errors == ec.Report.Errors) {
577 Error_ValueAssignment (ec, right_side);
582 if (e.eclass == ExprClass.Unresolved)
583 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
585 if ((e.type == null) && !(e is GenericTypeExpr))
586 throw new Exception ("Expression " + e + " did not set its type after Resolve");
591 public Constant ResolveLabelConstant (ResolveContext rc)
593 var expr = Resolve (rc);
597 Constant c = expr as Constant;
599 if (expr.type != InternalType.ErrorType)
600 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
608 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
610 if (Attribute.IsValidArgumentType (parameterType)) {
611 rc.Module.Compiler.Report.Error (182, loc,
612 "An attribute argument must be a constant expression, typeof expression or array creation expression");
614 rc.Module.Compiler.Report.Error (181, loc,
615 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
616 targetType.GetSignatureForError ());
621 /// Emits the code for the expression
625 /// The Emit method is invoked to generate the code
626 /// for the expression.
628 public abstract void Emit (EmitContext ec);
631 // Emit code to branch to @target if this expression is equivalent to @on_true.
632 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
633 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
634 // including the use of conditional branches. Note also that a branch MUST be emitted
635 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
638 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
641 // Emit this expression for its side effects, not for its value.
642 // The default implementation is to emit the value, and then throw it away.
643 // Subclasses can provide more efficient implementations, but those MUST be equivalent
644 public virtual void EmitSideEffect (EmitContext ec)
647 ec.Emit (OpCodes.Pop);
650 public virtual void EmitPrepare (EmitContext ec)
655 // Emits the expression into temporary field variable. The method
656 // should be used for await expressions only
658 public virtual Expression EmitToField (EmitContext ec)
661 // This is the await prepare Emit method. When emitting code like
662 // a + b we emit code like
668 // For await a + await b we have to interfere the flow to keep the
669 // stack clean because await yields from the expression. The emit
672 // a = a.EmitToField () // a is changed to temporary field access
673 // b = b.EmitToField ()
679 // The idea is to emit expression and leave the stack empty with
680 // result value still available.
682 // Expressions should override this default implementation when
683 // optimized version can be provided (e.g. FieldExpr)
686 // We can optimize for side-effect free expressions, they can be
687 // emitted out of order
689 if (IsSideEffectFree)
692 bool needs_temporary = ContainsEmitWithAwait ();
693 if (!needs_temporary)
696 // Emit original code
697 var field = EmitToFieldSource (ec);
700 // Store the result to temporary field when we
701 // cannot load `this' directly
703 field = ec.GetTemporaryField (type);
704 if (needs_temporary) {
706 // Create temporary local (we cannot load `this' before Emit)
708 var temp = ec.GetTemporaryLocal (type);
709 ec.Emit (OpCodes.Stloc, temp);
712 ec.Emit (OpCodes.Ldloc, temp);
713 field.EmitAssignFromStack (ec);
715 ec.FreeTemporaryLocal (temp, type);
717 field.EmitAssignFromStack (ec);
724 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
727 // Default implementation calls Emit method
733 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
735 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
736 bool contains_await = false;
738 for (int i = 1; i < expressions.Count; ++i) {
739 if (expressions[i].ContainsEmitWithAwait ()) {
740 contains_await = true;
745 if (contains_await) {
746 for (int i = 0; i < expressions.Count; ++i) {
747 expressions[i] = expressions[i].EmitToField (ec);
752 for (int i = 0; i < expressions.Count; ++i) {
753 expressions[i].Emit (ec);
758 /// Protected constructor. Only derivate types should
759 /// be able to be created
762 protected Expression ()
767 /// Returns a fully formed expression after a MemberLookup
770 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
772 if (spec is EventSpec)
773 return new EventExpr ((EventSpec) spec, loc);
774 if (spec is ConstSpec)
775 return new ConstantExpr ((ConstSpec) spec, loc);
776 if (spec is FieldSpec)
777 return new FieldExpr ((FieldSpec) spec, loc);
778 if (spec is PropertySpec)
779 return new PropertyExpr ((PropertySpec) spec, loc);
780 if (spec is TypeSpec)
781 return new TypeExpression (((TypeSpec) spec), loc);
786 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
788 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
791 case MemberKind.Struct:
792 // Every struct has implicit default constructor if not provided by user
796 rc.Report.SymbolRelatedToPreviousError (type);
797 // Report meaningful error for struct as they always have default ctor in C# context
798 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
800 case MemberKind.MissingType:
801 case MemberKind.InternalCompilerType:
802 // LAMESPEC: dynamic is not really object
803 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
807 rc.Report.SymbolRelatedToPreviousError (type);
808 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
809 type.GetSignatureForError ());
816 if (args == null && type.IsStruct) {
817 bool includes_empty = false;
818 foreach (MethodSpec ctor in ctors) {
819 if (ctor.Parameters.IsEmpty) {
820 includes_empty = true;
828 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
829 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
830 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
833 return r.ResolveMember<MethodSpec> (rc, ref args);
837 public enum MemberLookupRestrictions
843 EmptyArguments = 1 << 4,
844 IgnoreArity = 1 << 5,
845 IgnoreAmbiguity = 1 << 6,
846 NameOfExcluded = 1 << 7,
847 DontSetConditionalAccess = 1 << 8
851 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
852 // `qualifier_type' or null to lookup members in the current class.
854 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
856 var members = MemberCache.FindMembers (queried_type, name, false);
858 if (members != null) {
861 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
865 if (members [0].DeclaringType.BaseType == null)
868 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
869 } while (members != null);
872 var tps = queried_type as TypeParameterSpec;
874 members = MemberCache.FindInterfaceMembers (tps, name);
876 return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
882 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
884 MemberSpec non_method = null;
885 MemberSpec ambig_non_method = null;
887 for (int i = 0; i < members.Count; ++i) {
888 var member = members [i];
890 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
891 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
894 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
897 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
901 if (!member.IsAccessible (rc))
905 // With runtime binder we can have a situation where queried type is inaccessible
906 // because it came via dynamic object, the check about inconsisted accessibility
907 // had no effect as the type was unknown during compilation
910 // private class N { }
912 // public dynamic Foo ()
918 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
922 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
923 if (member is MethodSpec) {
924 return new MethodGroupExpr (members, queried_type, loc);
927 if (!Invocation.IsMemberInvocable (member))
931 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
933 } else if (!errorMode && !member.IsNotCSharpCompatible) {
935 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
936 // T has both an effective base class other than object and a non-empty effective interface set.
938 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
940 var tps = queried_type as TypeParameterSpec;
941 if (tps != null && tps.HasTypeConstraint) {
942 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
945 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
951 ambig_non_method = member;
955 if (non_method != null) {
956 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
957 var report = rc.Module.Compiler.Report;
958 report.SymbolRelatedToPreviousError (non_method);
959 report.SymbolRelatedToPreviousError (ambig_non_method);
960 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
961 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
964 if (non_method is MethodSpec)
965 return new MethodGroupExpr (members, queried_type, loc);
967 return ExprClassFromMemberInfo (non_method, loc);
973 protected static void Error_NamedArgument (NamedArgument na, Report Report)
975 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
978 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
980 throw new NotImplementedException ();
983 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
985 if (t == InternalType.ErrorType)
988 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
989 oper, t.GetSignatureForError ());
992 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
994 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
997 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
999 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1002 protected void Error_NullPropagatingLValue (ResolveContext rc)
1004 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1007 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1011 public virtual Reachability MarkReachable (Reachability rc)
1017 // Special version of flow analysis for expressions which can return different
1018 // on-true and on-false result. Used by &&, ||, ?: expressions
1020 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1023 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1027 /// Returns an expression that can be used to invoke operator true
1028 /// on the expression if it exists.
1030 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1032 return GetOperatorTrueOrFalse (ec, e, true, loc);
1036 /// Returns an expression that can be used to invoke operator false
1037 /// on the expression if it exists.
1039 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1041 return GetOperatorTrueOrFalse (ec, e, false, loc);
1044 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1046 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1048 if (type.IsNullableType)
1049 type = Nullable.NullableInfo.GetUnderlyingType (type);
1051 var methods = MemberCache.GetUserOperator (type, op, false);
1052 if (methods == null)
1055 Arguments arguments = new Arguments (1);
1056 arguments.Add (new Argument (e));
1058 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1059 var oper = res.ResolveOperator (ec, ref arguments);
1064 return new UserOperatorCall (oper, arguments, null, loc);
1067 public virtual string ExprClassName
1071 case ExprClass.Unresolved:
1072 return "Unresolved";
1073 case ExprClass.Value:
1075 case ExprClass.Variable:
1077 case ExprClass.Namespace:
1079 case ExprClass.Type:
1081 case ExprClass.MethodGroup:
1082 return "method group";
1083 case ExprClass.PropertyAccess:
1084 return "property access";
1085 case ExprClass.EventAccess:
1086 return "event access";
1087 case ExprClass.IndexerAccess:
1088 return "indexer access";
1089 case ExprClass.Nothing:
1091 case ExprClass.TypeParameter:
1092 return "type parameter";
1094 throw new Exception ("Should not happen");
1099 /// Reports that we were expecting `expr' to be of class `expected'
1101 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1103 var name = memberExpr.GetSignatureForError ();
1105 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1108 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1110 string [] valid = new string [4];
1113 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1114 valid [count++] = "variable";
1115 valid [count++] = "value";
1118 if ((flags & ResolveFlags.Type) != 0)
1119 valid [count++] = "type";
1121 if ((flags & ResolveFlags.MethodGroup) != 0)
1122 valid [count++] = "method group";
1125 valid [count++] = "unknown";
1127 StringBuilder sb = new StringBuilder (valid [0]);
1128 for (int i = 1; i < count - 1; i++) {
1130 sb.Append (valid [i]);
1133 sb.Append ("' or `");
1134 sb.Append (valid [count - 1]);
1137 ec.Report.Error (119, loc,
1138 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1141 public static void UnsafeError (ResolveContext ec, Location loc)
1143 UnsafeError (ec.Report, loc);
1146 public static void UnsafeError (Report Report, Location loc)
1148 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1151 public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
1153 UnsafeInsideIteratorError (rc.Report, loc);
1156 public static void UnsafeInsideIteratorError (Report report, Location loc)
1158 report.Error (1629, loc, "Unsafe code may not appear in iterators");
1162 // Converts `source' to an int, uint, long or ulong.
1164 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1166 var btypes = ec.BuiltinTypes;
1168 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1169 Arguments args = new Arguments (1);
1170 args.Add (new Argument (source));
1171 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1174 Expression converted;
1176 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1177 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1178 if (converted == null)
1179 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1180 if (converted == null)
1181 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1182 if (converted == null)
1183 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1185 if (converted == null) {
1186 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1195 // Only positive constants are allowed at compile time
1197 Constant c = converted as Constant;
1198 if (c != null && c.IsNegative)
1199 Error_NegativeArrayIndex (ec, source.loc);
1201 // No conversion needed to array index
1202 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1205 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1208 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1210 if (args.Count != 1){
1211 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1216 if (arg is NamedArgument)
1217 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1219 var index = arg.Expr.Resolve (rc);
1223 index = ConvertExpressionToArrayIndex (rc, index, true);
1225 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1226 return new Indirection (p, loc);
1230 // Derived classes implement this method by cloning the fields that
1231 // could become altered during the Resolve stage
1233 // Only expressions that are created for the parser need to implement
1236 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1238 throw new NotImplementedException (
1240 "CloneTo not implemented for expression {0}", this.GetType ()));
1244 // Clones an expression created by the parser.
1246 // We only support expressions created by the parser so far, not
1247 // expressions that have been resolved (many more classes would need
1248 // to implement CloneTo).
1250 // This infrastructure is here merely for Lambda expressions which
1251 // compile the same code using different type values for the same
1252 // arguments to find the correct overload
1254 public virtual Expression Clone (CloneContext clonectx)
1256 Expression cloned = (Expression) MemberwiseClone ();
1257 CloneTo (clonectx, cloned);
1263 // Implementation of expression to expression tree conversion
1265 public abstract Expression CreateExpressionTree (ResolveContext ec);
1267 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1269 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1272 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1274 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1277 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1279 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1282 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1284 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1288 return new TypeExpression (t, loc);
1292 // Implemented by all expressions which support conversion from
1293 // compiler expression to invokable runtime expression. Used by
1294 // dynamic C# binder.
1296 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1298 throw new NotImplementedException ("MakeExpression for " + GetType ());
1301 public virtual object Accept (StructuralVisitor visitor)
1303 return visitor.Visit (this);
1308 /// This is just a base class for expressions that can
1309 /// appear on statements (invocations, object creation,
1310 /// assignments, post/pre increment and decrement). The idea
1311 /// being that they would support an extra Emition interface that
1312 /// does not leave a result on the stack.
1314 public abstract class ExpressionStatement : Expression
1316 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1318 Expression e = Resolve (ec);
1322 ExpressionStatement es = e as ExpressionStatement;
1323 if (es == null || e is AnonymousMethodBody) {
1324 var reduced = e as IReducedExpressionStatement;
1325 if (reduced != null) {
1326 return EmptyExpressionStatement.Instance;
1329 Error_InvalidExpressionStatement (ec);
1333 // This is quite expensive warning, try to limit the damage
1335 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1336 WarningAsyncWithoutWait (ec, e);
1342 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1344 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1345 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1350 // Need to do full resolve because GetAwaiter can be extension method
1351 // available only in this context
1353 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1357 var arguments = new Arguments (0);
1358 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1363 // Use same check rules as for real await
1365 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1366 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1369 bc.Report.Warning (4014, 1, e.Location,
1370 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1374 var inv = e as Invocation;
1375 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1376 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1377 bc.Report.Warning (4014, 1, e.Location,
1378 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1384 /// Requests the expression to be emitted in a `statement'
1385 /// context. This means that no new value is left on the
1386 /// stack after invoking this method (constrasted with
1387 /// Emit that will always leave a value on the stack).
1389 public abstract void EmitStatement (EmitContext ec);
1391 public override void EmitSideEffect (EmitContext ec)
1397 interface IReducedExpressionStatement
1402 /// This kind of cast is used to encapsulate the child
1403 /// whose type is child.Type into an expression that is
1404 /// reported to return "return_type". This is used to encapsulate
1405 /// expressions which have compatible types, but need to be dealt
1406 /// at higher levels with.
1408 /// For example, a "byte" expression could be encapsulated in one
1409 /// of these as an "unsigned int". The type for the expression
1410 /// would be "unsigned int".
1413 public abstract class TypeCast : Expression
1415 protected readonly Expression child;
1417 protected TypeCast (Expression child, TypeSpec return_type)
1419 eclass = child.eclass;
1420 loc = child.Location;
1425 public Expression Child {
1431 public override bool ContainsEmitWithAwait ()
1433 return child.ContainsEmitWithAwait ();
1436 public override Expression CreateExpressionTree (ResolveContext ec)
1438 Arguments args = new Arguments (2);
1439 args.Add (new Argument (child.CreateExpressionTree (ec)));
1440 args.Add (new Argument (new TypeOf (type, loc)));
1442 if (type.IsPointer || child.Type.IsPointer)
1443 Error_PointerInsideExpressionTree (ec);
1445 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1448 protected override Expression DoResolve (ResolveContext ec)
1450 // This should never be invoked, we are born in fully
1451 // initialized state.
1456 public override void Emit (EmitContext ec)
1461 public override void FlowAnalysis (FlowAnalysisContext fc)
1463 child.FlowAnalysis (fc);
1466 public override SLE.Expression MakeExpression (BuilderContext ctx)
1469 return base.MakeExpression (ctx);
1471 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1472 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1473 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1477 public override Reachability MarkReachable (Reachability rc)
1479 return child.MarkReachable (rc);
1482 protected override void CloneTo (CloneContext clonectx, Expression t)
1487 public override bool IsNull {
1488 get { return child.IsNull; }
1492 public class EmptyCast : TypeCast {
1493 EmptyCast (Expression child, TypeSpec target_type)
1494 : base (child, target_type)
1498 public static Expression Create (Expression child, TypeSpec type)
1500 Constant c = child as Constant;
1502 var enum_constant = c as EnumConstant;
1503 if (enum_constant != null)
1504 c = enum_constant.Child;
1506 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1510 var res = c.ConvertImplicitly (type);
1516 EmptyCast e = child as EmptyCast;
1518 return new EmptyCast (e.child, type);
1520 return new EmptyCast (child, type);
1523 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1525 child.EmitBranchable (ec, label, on_true);
1528 public override void EmitSideEffect (EmitContext ec)
1530 child.EmitSideEffect (ec);
1535 // Used for predefined type user operator (no obsolete check, etc.)
1537 public class OperatorCast : TypeCast
1539 readonly MethodSpec conversion_operator;
1541 public OperatorCast (Expression expr, TypeSpec target_type)
1542 : this (expr, target_type, target_type, false)
1546 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1547 : this (expr, target_type, target_type, find_explicit)
1551 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1552 : base (expr, returnType)
1554 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1555 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1558 foreach (MethodSpec oper in mi) {
1559 if (oper.ReturnType != returnType)
1562 if (oper.Parameters.Types[0] == expr.Type) {
1563 conversion_operator = oper;
1569 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1570 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1573 public override void Emit (EmitContext ec)
1576 ec.Emit (OpCodes.Call, conversion_operator);
1581 // Constant specialization of EmptyCast.
1582 // We need to special case this since an empty cast of
1583 // a constant is still a constant.
1585 public class EmptyConstantCast : Constant
1587 public readonly Constant child;
1589 public EmptyConstantCast (Constant child, TypeSpec type)
1590 : base (child.Location)
1593 throw new ArgumentNullException ("child");
1596 this.eclass = child.eclass;
1600 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1602 if (child.Type == target_type)
1605 // FIXME: check that 'type' can be converted to 'target_type' first
1606 return child.ConvertExplicitly (in_checked_context, target_type);
1609 public override Expression CreateExpressionTree (ResolveContext ec)
1611 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1612 child.CreateExpressionTree (ec),
1613 new TypeOf (type, loc));
1616 Error_PointerInsideExpressionTree (ec);
1618 return CreateExpressionFactoryCall (ec, "Convert", args);
1621 public override bool IsDefaultValue {
1622 get { return child.IsDefaultValue; }
1625 public override bool IsNegative {
1626 get { return child.IsNegative; }
1629 public override bool IsNull {
1630 get { return child.IsNull; }
1633 public override bool IsOneInteger {
1634 get { return child.IsOneInteger; }
1637 public override bool IsSideEffectFree {
1639 return child.IsSideEffectFree;
1643 public override bool IsZeroInteger {
1644 get { return child.IsZeroInteger; }
1647 public override void Emit (EmitContext ec)
1652 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1654 child.EmitBranchable (ec, label, on_true);
1656 // Only to make verifier happy
1657 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1658 ec.Emit (OpCodes.Unbox_Any, type);
1661 public override void EmitSideEffect (EmitContext ec)
1663 child.EmitSideEffect (ec);
1666 public override object GetValue ()
1668 return child.GetValue ();
1671 public override string GetValueAsLiteral ()
1673 return child.GetValueAsLiteral ();
1676 public override long GetValueAsLong ()
1678 return child.GetValueAsLong ();
1681 public override Constant ConvertImplicitly (TypeSpec target_type)
1683 if (type == target_type)
1686 // FIXME: Do we need to check user conversions?
1687 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1690 return child.ConvertImplicitly (target_type);
1695 /// This class is used to wrap literals which belong inside Enums
1697 public class EnumConstant : Constant
1699 public Constant Child;
1701 public EnumConstant (Constant child, TypeSpec enum_type)
1702 : base (child.Location)
1706 this.eclass = ExprClass.Value;
1707 this.type = enum_type;
1710 protected EnumConstant (Location loc)
1715 public override void Emit (EmitContext ec)
1720 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1722 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1725 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1727 Child.EmitBranchable (ec, label, on_true);
1730 public override void EmitSideEffect (EmitContext ec)
1732 Child.EmitSideEffect (ec);
1735 public override string GetSignatureForError()
1737 return Type.GetSignatureForError ();
1740 public override object GetValue ()
1742 return Child.GetValue ();
1746 public override object GetTypedValue ()
1749 // The method can be used in dynamic context only (on closed types)
1751 // System.Enum.ToObject cannot be called on dynamic types
1752 // EnumBuilder has to be used, but we cannot use EnumBuilder
1753 // because it does not properly support generics
1755 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1759 public override string GetValueAsLiteral ()
1761 return Child.GetValueAsLiteral ();
1764 public override long GetValueAsLong ()
1766 return Child.GetValueAsLong ();
1769 public EnumConstant Increment()
1771 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1774 public override bool IsDefaultValue {
1776 return Child.IsDefaultValue;
1780 public override bool IsSideEffectFree {
1782 return Child.IsSideEffectFree;
1786 public override bool IsZeroInteger {
1787 get { return Child.IsZeroInteger; }
1790 public override bool IsNegative {
1792 return Child.IsNegative;
1796 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1798 if (Child.Type == target_type)
1801 return Child.ConvertExplicitly (in_checked_context, target_type);
1804 public override Constant ConvertImplicitly (TypeSpec type)
1806 if (this.type == type) {
1810 if (!Convert.ImplicitStandardConversionExists (this, type)){
1814 return Child.ConvertImplicitly (type);
1819 /// This kind of cast is used to encapsulate Value Types in objects.
1821 /// The effect of it is to box the value type emitted by the previous
1824 public class BoxedCast : TypeCast {
1826 public BoxedCast (Expression expr, TypeSpec target_type)
1827 : base (expr, target_type)
1829 eclass = ExprClass.Value;
1832 protected override Expression DoResolve (ResolveContext ec)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1840 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1842 // Only boxing to object type is supported
1843 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1844 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1848 enc.Encode (child.Type);
1849 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1852 public override void Emit (EmitContext ec)
1856 ec.Emit (OpCodes.Box, child.Type);
1859 public override void EmitSideEffect (EmitContext ec)
1861 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1862 // so, we need to emit the box+pop instructions in most cases
1863 if (child.Type.IsStruct &&
1864 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1865 child.EmitSideEffect (ec);
1867 base.EmitSideEffect (ec);
1871 public class UnboxCast : TypeCast {
1872 public UnboxCast (Expression expr, TypeSpec return_type)
1873 : base (expr, return_type)
1877 protected override Expression DoResolve (ResolveContext ec)
1879 // This should never be invoked, we are born in fully
1880 // initialized state.
1885 public override void Emit (EmitContext ec)
1889 ec.Emit (OpCodes.Unbox_Any, type);
1894 /// This is used to perform explicit numeric conversions.
1896 /// Explicit numeric conversions might trigger exceptions in a checked
1897 /// context, so they should generate the conv.ovf opcodes instead of
1900 public class ConvCast : TypeCast {
1901 public enum Mode : byte {
1902 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1904 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1905 U2_I1, U2_U1, U2_I2, U2_CH,
1906 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1907 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1908 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1909 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1910 CH_I1, CH_U1, CH_I2,
1911 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1912 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1918 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1919 : base (child, return_type)
1924 protected override Expression DoResolve (ResolveContext ec)
1926 // This should never be invoked, we are born in fully
1927 // initialized state.
1932 public override string ToString ()
1934 return String.Format ("ConvCast ({0}, {1})", mode, child);
1937 public override void Emit (EmitContext ec)
1943 public static void Emit (EmitContext ec, Mode mode)
1945 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1947 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1948 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1950 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1951 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1954 case Mode.U1_CH: /* nothing */ break;
1956 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1957 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1958 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1959 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1960 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1964 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1965 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.U2_CH: /* nothing */ break;
1968 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1969 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1970 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1971 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1972 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1979 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1980 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1981 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1983 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1984 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1985 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1986 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1988 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1989 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1990 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1991 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1993 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1994 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1995 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1996 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1997 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1998 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1999 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2000 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2001 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2003 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2004 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2005 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2007 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2008 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2009 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2010 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2012 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2013 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2014 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2015 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2017 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2018 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2019 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2020 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2021 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2022 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2023 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2024 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2025 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2026 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2028 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2032 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2033 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2035 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2036 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2038 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2039 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2041 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2042 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2043 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2046 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U2_CH: /* nothing */ break;
2053 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2054 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2055 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2056 case Mode.I4_U4: /* nothing */ break;
2057 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2059 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2061 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2062 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2063 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2064 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2065 case Mode.U4_I4: /* nothing */ break;
2066 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2068 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2069 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2070 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2071 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2073 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2074 case Mode.I8_U8: /* nothing */ break;
2075 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2076 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2078 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2079 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2080 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2081 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2083 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2084 case Mode.U8_I8: /* nothing */ break;
2085 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2086 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2088 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2089 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2090 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2092 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2099 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2100 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2102 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2105 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2106 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2107 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2108 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2109 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2110 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2111 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2113 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2119 class OpcodeCast : TypeCast
2123 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2124 : base (child, return_type)
2129 protected override Expression DoResolve (ResolveContext ec)
2131 // This should never be invoked, we are born in fully
2132 // initialized state.
2137 public override void Emit (EmitContext ec)
2143 public TypeSpec UnderlyingType {
2144 get { return child.Type; }
2149 // Opcode casts expression with 2 opcodes but only
2150 // single expression tree node
2152 class OpcodeCastDuplex : OpcodeCast
2154 readonly OpCode second;
2156 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2157 : base (child, returnType, first)
2159 this.second = second;
2162 public override void Emit (EmitContext ec)
2170 /// This kind of cast is used to encapsulate a child and cast it
2171 /// to the class requested
2173 public sealed class ClassCast : TypeCast {
2174 readonly bool forced;
2176 public ClassCast (Expression child, TypeSpec return_type)
2177 : base (child, return_type)
2181 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2182 : base (child, return_type)
2184 this.forced = forced;
2187 public override void Emit (EmitContext ec)
2191 bool gen = TypeManager.IsGenericParameter (child.Type);
2193 ec.Emit (OpCodes.Box, child.Type);
2195 if (type.IsGenericParameter) {
2196 ec.Emit (OpCodes.Unbox_Any, type);
2203 ec.Emit (OpCodes.Castclass, type);
2208 // Created during resolving pahse when an expression is wrapped or constantified
2209 // and original expression can be used later (e.g. for expression trees)
2211 public class ReducedExpression : Expression
2213 public class ReducedConstantExpression : EmptyConstantCast
2215 readonly Expression orig_expr;
2217 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2218 : base (expr, expr.Type)
2220 this.orig_expr = orig_expr;
2223 public Expression OriginalExpression {
2229 public override Constant ConvertImplicitly (TypeSpec target_type)
2231 Constant c = base.ConvertImplicitly (target_type);
2233 c = new ReducedConstantExpression (c, orig_expr);
2238 public override Expression CreateExpressionTree (ResolveContext ec)
2240 return orig_expr.CreateExpressionTree (ec);
2243 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2245 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2247 c = new ReducedConstantExpression (c, orig_expr);
2251 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2254 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2256 if (orig_expr is Conditional)
2257 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2259 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2263 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2265 public ReducedConstantStatement (Constant expr, Expression origExpr)
2266 : base (expr, origExpr)
2271 sealed class ReducedExpressionStatement : ExpressionStatement
2273 readonly Expression orig_expr;
2274 readonly ExpressionStatement stm;
2276 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2278 this.orig_expr = orig;
2280 this.eclass = stm.eclass;
2281 this.type = stm.Type;
2283 this.loc = orig.Location;
2286 public override bool ContainsEmitWithAwait ()
2288 return stm.ContainsEmitWithAwait ();
2291 public override Expression CreateExpressionTree (ResolveContext ec)
2293 return orig_expr.CreateExpressionTree (ec);
2296 protected override Expression DoResolve (ResolveContext ec)
2301 public override void Emit (EmitContext ec)
2306 public override void EmitStatement (EmitContext ec)
2308 stm.EmitStatement (ec);
2311 public override void FlowAnalysis (FlowAnalysisContext fc)
2313 stm.FlowAnalysis (fc);
2317 readonly Expression expr, orig_expr;
2319 private ReducedExpression (Expression expr, Expression orig_expr)
2322 this.eclass = expr.eclass;
2323 this.type = expr.Type;
2324 this.orig_expr = orig_expr;
2325 this.loc = orig_expr.Location;
2330 public override bool IsSideEffectFree {
2332 return expr.IsSideEffectFree;
2336 public Expression OriginalExpression {
2344 public override bool ContainsEmitWithAwait ()
2346 return expr.ContainsEmitWithAwait ();
2350 // Creates fully resolved expression switcher
2352 public static Constant Create (Constant expr, Expression originalExpr)
2354 if (expr.eclass == ExprClass.Unresolved)
2355 throw new ArgumentException ("Unresolved expression");
2357 if (originalExpr is ExpressionStatement)
2358 return new ReducedConstantStatement (expr, originalExpr);
2360 return new ReducedConstantExpression (expr, originalExpr);
2363 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2365 return new ReducedExpressionStatement (s, orig);
2368 public static Expression Create (Expression expr, Expression original_expr)
2370 return Create (expr, original_expr, true);
2374 // Creates unresolved reduce expression. The original expression has to be
2375 // already resolved. Created expression is constant based based on `expr'
2376 // value unless canBeConstant is used
2378 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2380 if (canBeConstant) {
2381 Constant c = expr as Constant;
2383 return Create (c, original_expr);
2386 ExpressionStatement s = expr as ExpressionStatement;
2388 return Create (s, original_expr);
2390 if (expr.eclass == ExprClass.Unresolved)
2391 throw new ArgumentException ("Unresolved expression");
2393 return new ReducedExpression (expr, original_expr);
2396 public override Expression CreateExpressionTree (ResolveContext ec)
2398 return orig_expr.CreateExpressionTree (ec);
2401 protected override Expression DoResolve (ResolveContext ec)
2406 public override void Emit (EmitContext ec)
2411 public override Expression EmitToField (EmitContext ec)
2413 return expr.EmitToField(ec);
2416 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2418 expr.EmitBranchable (ec, target, on_true);
2421 public override void FlowAnalysis (FlowAnalysisContext fc)
2423 expr.FlowAnalysis (fc);
2426 public override SLE.Expression MakeExpression (BuilderContext ctx)
2428 return orig_expr.MakeExpression (ctx);
2431 public override Reachability MarkReachable (Reachability rc)
2433 return expr.MarkReachable (rc);
2438 // Standard composite pattern
2440 public abstract class CompositeExpression : Expression
2442 protected Expression expr;
2444 protected CompositeExpression (Expression expr)
2447 this.loc = expr.Location;
2450 public override bool ContainsEmitWithAwait ()
2452 return expr.ContainsEmitWithAwait ();
2455 public override Expression CreateExpressionTree (ResolveContext rc)
2457 return expr.CreateExpressionTree (rc);
2460 public Expression Child {
2461 get { return expr; }
2464 protected override Expression DoResolve (ResolveContext rc)
2466 expr = expr.Resolve (rc);
2471 eclass = expr.eclass;
2475 public override void Emit (EmitContext ec)
2480 public override bool IsNull {
2481 get { return expr.IsNull; }
2486 // Base of expressions used only to narrow resolve flow
2488 public abstract class ShimExpression : Expression
2490 protected Expression expr;
2492 protected ShimExpression (Expression expr)
2497 public Expression Expr {
2503 protected override void CloneTo (CloneContext clonectx, Expression t)
2508 ShimExpression target = (ShimExpression) t;
2509 target.expr = expr.Clone (clonectx);
2512 public override bool ContainsEmitWithAwait ()
2514 return expr.ContainsEmitWithAwait ();
2517 public override Expression CreateExpressionTree (ResolveContext ec)
2519 throw new NotSupportedException ("ET");
2522 public override void Emit (EmitContext ec)
2524 throw new InternalErrorException ("Missing Resolve call");
2528 public class UnreachableExpression : Expression
2530 public UnreachableExpression (Expression expr)
2532 this.loc = expr.Location;
2535 public override Expression CreateExpressionTree (ResolveContext ec)
2538 throw new NotImplementedException ();
2541 protected override Expression DoResolve (ResolveContext rc)
2543 throw new NotSupportedException ();
2546 public override void FlowAnalysis (FlowAnalysisContext fc)
2548 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2551 public override void Emit (EmitContext ec)
2555 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2561 // Unresolved type name expressions
2563 public abstract class ATypeNameExpression : FullNamedExpression
2566 protected TypeArguments targs;
2568 protected ATypeNameExpression (string name, Location l)
2574 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2581 protected ATypeNameExpression (string name, int arity, Location l)
2582 : this (name, new UnboundTypeArguments (arity, l), l)
2590 return targs == null ? 0 : targs.Count;
2594 public bool HasTypeArguments {
2596 return targs != null && !targs.IsEmpty;
2600 public string Name {
2609 public TypeArguments TypeArguments {
2617 public override bool Equals (object obj)
2619 ATypeNameExpression atne = obj as ATypeNameExpression;
2620 return atne != null && atne.Name == Name &&
2621 (targs == null || targs.Equals (atne.targs));
2624 public override int GetHashCode ()
2626 return Name.GetHashCode ();
2629 // TODO: Move it to MemberCore
2630 public static string GetMemberType (MemberCore mc)
2636 if (mc is FieldBase)
2638 if (mc is MethodCore)
2640 if (mc is EnumMember)
2648 public override string GetSignatureForError ()
2650 if (targs != null) {
2651 return Name + "<" + targs.GetSignatureForError () + ">";
2657 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2661 /// SimpleName expressions are formed of a single word and only happen at the beginning
2662 /// of a dotted-name.
2664 public class SimpleName : ATypeNameExpression
2666 public SimpleName (string name, Location l)
2671 public SimpleName (string name, TypeArguments args, Location l)
2672 : base (name, args, l)
2676 public SimpleName (string name, int arity, Location l)
2677 : base (name, arity, l)
2681 public SimpleName GetMethodGroup ()
2683 return new SimpleName (Name, targs, loc);
2686 protected override Expression DoResolve (ResolveContext rc)
2688 return SimpleNameResolve (rc, null);
2691 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2693 return SimpleNameResolve (ec, right_side);
2696 public void Error_NameDoesNotExist (ResolveContext rc)
2698 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2701 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2703 if (ctx.CurrentType != null) {
2704 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2705 if (member != null) {
2706 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2711 var report = ctx.Module.Compiler.Report;
2713 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2714 if (retval != null) {
2715 report.SymbolRelatedToPreviousError (retval.Type);
2716 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2720 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2721 if (retval != null) {
2722 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2726 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2727 if (ns_candidates != null) {
2728 if (ctx is UsingAliasNamespace.AliasContext) {
2729 report.Error (246, loc,
2730 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2731 ns_candidates[0], Name);
2733 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2734 report.Error (246, loc,
2735 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2739 report.Error (246, loc,
2740 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2745 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2747 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2750 if (fne.Type != null && Arity > 0) {
2751 if (HasTypeArguments) {
2752 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2753 if (ct.ResolveAsType (mc) == null)
2759 targs.Resolve (mc, allowUnboundTypeArguments);
2761 return new GenericOpenTypeExpr (fne.Type, loc);
2765 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2767 if (!(fne is NamespaceExpression))
2771 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2772 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2773 mc.Module.Compiler.Report.Error (1980, Location,
2774 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2775 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2778 fne = new DynamicTypeExpr (loc);
2779 fne.ResolveAsType (mc);
2785 Error_TypeOrNamespaceNotFound (mc);
2789 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2792 // Has to ignore static usings because we are looking for any member not just type
2795 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2798 public bool IsPossibleType (IMemberContext mc)
2800 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2803 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2805 int lookup_arity = Arity;
2806 bool errorMode = false;
2808 Block current_block = rc.CurrentBlock;
2809 INamedBlockVariable variable = null;
2810 bool variable_found = false;
2814 // Stage 1: binding to local variables or parameters
2816 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2818 if (current_block != null && lookup_arity == 0) {
2819 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2820 if (!variable.IsDeclared) {
2821 // We found local name in accessible block but it's not
2822 // initialized yet, maybe the user wanted to bind to something else
2824 variable_found = true;
2826 e = variable.CreateReferenceExpression (rc, loc);
2829 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2838 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2840 TypeSpec member_type = rc.CurrentType;
2841 for (; member_type != null; member_type = member_type.DeclaringType) {
2842 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2846 var me = e as MemberExpr;
2848 // The name matches a type, defer to ResolveAsTypeStep
2856 if (variable != null) {
2857 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2858 rc.Report.Error (844, loc,
2859 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2860 Name, me.GetSignatureForError ());
2864 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2865 // Leave it to overload resolution to report correct error
2867 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2868 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2872 // MemberLookup does not check accessors availability, this is actually needed for properties only
2874 var pe = me as PropertyExpr;
2877 // Break as there is no other overload available anyway
2878 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2879 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2882 pe.Getter = pe.PropertyInfo.Get;
2884 if (!pe.PropertyInfo.HasSet) {
2885 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2886 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2887 var p = (Property) pe.PropertyInfo.MemberDefinition;
2888 return new FieldExpr (p.BackingField, loc);
2891 variable_found = true;
2895 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2896 variable_found = true;
2900 pe.Setter = pe.PropertyInfo.Set;
2905 // TODO: It's used by EventExpr -> FieldExpr transformation only
2906 // TODO: Should go to MemberAccess
2907 me = me.ResolveMemberAccess (rc, null, null);
2910 targs.Resolve (rc, false);
2911 me.SetTypeArguments (rc, targs);
2918 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2920 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2921 if (IsPossibleTypeOrNamespace (rc)) {
2922 return ResolveAsTypeOrNamespace (rc, false);
2926 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2929 targs.Resolve (rc, false);
2931 var me = expr as MemberExpr;
2933 me.SetTypeArguments (rc, targs);
2938 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2939 return new NameOf (this);
2942 if (variable_found) {
2943 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2946 var tparams = rc.CurrentTypeParameters;
2947 if (tparams != null) {
2948 if (tparams.Find (Name) != null) {
2949 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2954 var ct = rc.CurrentType;
2956 if (ct.MemberDefinition.TypeParametersCount > 0) {
2957 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2958 if (ctp.Name == Name) {
2959 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2965 ct = ct.DeclaringType;
2966 } while (ct != null);
2969 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2970 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2972 rc.Report.SymbolRelatedToPreviousError (e.Type);
2973 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2977 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2979 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2980 return ErrorExpression.Instance;
2984 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2986 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2987 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2991 if (e is TypeExpr) {
2992 // TypeExpression does not have correct location
2993 if (e is TypeExpression)
2994 e = new TypeExpression (e.Type, loc);
3000 Error_NameDoesNotExist (rc);
3003 return ErrorExpression.Instance;
3006 if (rc.Module.Evaluator != null) {
3007 var fi = rc.Module.Evaluator.LookupField (Name);
3009 return new FieldExpr (fi.Item1, loc);
3017 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3019 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3024 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3025 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3029 if (right_side != null) {
3030 e = e.ResolveLValue (ec, right_side);
3038 public override object Accept (StructuralVisitor visitor)
3040 return visitor.Visit (this);
3045 /// Represents a namespace or a type. The name of the class was inspired by
3046 /// section 10.8.1 (Fully Qualified Names).
3048 public abstract class FullNamedExpression : Expression
3050 protected override void CloneTo (CloneContext clonectx, Expression target)
3052 // Do nothing, most unresolved type expressions cannot be
3053 // resolved to different type
3056 public override bool ContainsEmitWithAwait ()
3061 public override Expression CreateExpressionTree (ResolveContext ec)
3063 throw new NotSupportedException ("ET");
3066 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3069 // This is used to resolve the expression as a type, a null
3070 // value will be returned if the expression is not a type
3073 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3075 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3080 TypeExpr te = fne as TypeExpr;
3082 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3090 var dep = type.GetMissingDependencies ();
3092 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3095 if (type.Kind == MemberKind.Void) {
3096 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3100 // Obsolete checks cannot be done when resolving base context as they
3101 // require type dependencies to be set but we are in process of resolving them
3103 if (mc is ResolveContext) {
3104 var oa = type.GetAttributeObsolete ();
3105 if (oa != null && !mc.IsObsolete)
3106 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3113 public override void Emit (EmitContext ec)
3115 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3116 GetSignatureForError ());
3121 /// Expression that evaluates to a type
3123 public abstract class TypeExpr : FullNamedExpression
3125 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3131 protected sealed override Expression DoResolve (ResolveContext ec)
3137 public override bool Equals (object obj)
3139 TypeExpr tobj = obj as TypeExpr;
3143 return Type == tobj.Type;
3146 public override int GetHashCode ()
3148 return Type.GetHashCode ();
3153 /// Fully resolved Expression that already evaluated to a type
3155 public class TypeExpression : TypeExpr
3157 public TypeExpression (TypeSpec t, Location l)
3160 eclass = ExprClass.Type;
3164 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3170 public class NamespaceExpression : FullNamedExpression
3172 readonly Namespace ns;
3174 public NamespaceExpression (Namespace ns, Location loc)
3177 this.Type = InternalType.Namespace;
3178 this.eclass = ExprClass.Namespace;
3182 public Namespace Namespace {
3188 protected override Expression DoResolve (ResolveContext rc)
3190 throw new NotImplementedException ();
3193 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3198 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3200 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3201 if (retval != null) {
3202 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3203 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3207 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3208 if (retval != null) {
3209 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3214 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3215 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3219 string assembly = null;
3220 string possible_name = Namespace.GetSignatureForError () + "." + name;
3222 // Only assembly unique name should be added
3223 switch (possible_name) {
3224 case "System.Drawing":
3225 case "System.Web.Services":
3228 case "System.Configuration":
3229 case "System.Data.Services":
3230 case "System.DirectoryServices":
3232 case "System.Net.Http":
3233 case "System.Numerics":
3234 case "System.Runtime.Caching":
3235 case "System.ServiceModel":
3236 case "System.Transactions":
3237 case "System.Web.Routing":
3238 case "System.Xml.Linq":
3240 assembly = possible_name;
3244 case "System.Linq.Expressions":
3245 assembly = "System.Core";
3248 case "System.Windows.Forms":
3249 case "System.Windows.Forms.Layout":
3250 assembly = "System.Windows.Forms";
3254 assembly = assembly == null ? "an" : "`" + assembly + "'";
3256 if (Namespace is GlobalRootNamespace) {
3257 ctx.Module.Compiler.Report.Error (400, loc,
3258 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3261 ctx.Module.Compiler.Report.Error (234, loc,
3262 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3263 name, GetSignatureForError (), assembly);
3267 public override string GetSignatureForError ()
3269 return ns.GetSignatureForError ();
3272 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3274 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3277 public override string ToString ()
3279 return Namespace.Name;
3284 /// This class denotes an expression which evaluates to a member
3285 /// of a struct or a class.
3287 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3289 protected bool conditional_access_receiver;
3292 // An instance expression associated with this member, if it's a
3293 // non-static member
3295 public Expression InstanceExpression;
3298 /// The name of this member.
3300 public abstract string Name {
3305 // When base.member is used
3307 public bool IsBase {
3308 get { return InstanceExpression is BaseThis; }
3312 /// Whether this is an instance member.
3314 public abstract bool IsInstance {
3319 /// Whether this is a static member.
3321 public abstract bool IsStatic {
3325 public abstract string KindName {
3329 public bool ConditionalAccess { get; set; }
3331 protected abstract TypeSpec DeclaringType {
3335 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3337 return InstanceExpression.Type;
3342 // Converts best base candidate for virtual method starting from QueriedBaseType
3344 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3347 // Only when base.member is used and method is virtual
3353 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3354 // means for base.member access we have to find the closest match after we found best candidate
3356 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3358 // The method could already be what we are looking for
3360 TypeSpec[] targs = null;
3361 if (method.DeclaringType != InstanceExpression.Type) {
3363 // Candidate can have inflated MVAR parameters and we need to find
3364 // base match for original definition not inflated parameter types
3366 var parameters = method.Parameters;
3367 if (method.Arity > 0) {
3368 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3369 var inflated = method.DeclaringType as InflatedTypeSpec;
3370 if (inflated != null) {
3371 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3375 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3376 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3377 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3378 if (base_override.IsGeneric)
3379 targs = method.TypeArguments;
3381 method = base_override;
3386 // When base access is used inside anonymous method/iterator/etc we need to
3387 // get back to the context of original type. We do it by emiting proxy
3388 // method in original class and rewriting base call to this compiler
3389 // generated method call which does the actual base invocation. This may
3390 // introduce redundant storey but with `this' only but it's tricky to avoid
3391 // at this stage as we don't know what expressions follow base
3393 // TODO: It's needed only when the method with base call is moved to a storey
3395 if (rc.CurrentAnonymousMethod != null) {
3396 if (targs == null && method.IsGeneric) {
3397 targs = method.TypeArguments;
3398 method = method.GetGenericMethodDefinition ();
3401 if (method.Parameters.HasArglist)
3402 throw new NotImplementedException ("__arglist base call proxy");
3404 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3406 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3407 // get/set member expressions second call would fail to proxy because left expression
3408 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3409 // FIXME: The async check is another hack but will probably fail with mutators
3410 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3411 InstanceExpression = new This (loc).Resolve (rc);
3415 method = method.MakeGenericMethod (rc, targs);
3419 // Only base will allow this invocation to happen.
3421 if (method.IsAbstract) {
3422 rc.Report.SymbolRelatedToPreviousError (method);
3423 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3429 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3431 if (InstanceExpression == null)
3434 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3435 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3436 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3441 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3443 if (InstanceExpression == null)
3446 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3449 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3451 var ct = rc.CurrentType;
3452 if (ct == qualifier)
3455 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3458 qualifier = qualifier.GetDefinition ();
3459 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3466 public override bool ContainsEmitWithAwait ()
3468 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3471 public override bool HasConditionalAccess ()
3473 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3476 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3479 type = type.GetDefinition ();
3481 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3484 type = type.DeclaringType;
3485 } while (type != null);
3490 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3492 if (InstanceExpression != null) {
3493 InstanceExpression = InstanceExpression.Resolve (rc);
3494 CheckProtectedMemberAccess (rc, member);
3497 if (member.MemberType.IsPointer) {
3498 if (rc.CurrentIterator != null) {
3499 UnsafeInsideIteratorError (rc, loc);
3500 } else if (!rc.IsUnsafe) {
3501 UnsafeError (rc, loc);
3505 var dep = member.GetMissingDependencies ();
3507 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3510 member.CheckObsoleteness (rc, loc);
3512 if (!(member is FieldSpec))
3513 member.MemberDefinition.SetIsUsed ();
3516 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3518 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3521 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3523 rc.Report.SymbolRelatedToPreviousError (member);
3524 rc.Report.Error (1540, loc,
3525 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3526 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3529 public override void FlowAnalysis (FlowAnalysisContext fc)
3531 if (InstanceExpression != null) {
3532 InstanceExpression.FlowAnalysis (fc);
3536 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3538 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3539 conditional_access_receiver = true;
3543 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3545 if (!ResolveInstanceExpressionCore (rc, rhs))
3549 // Check intermediate value modification which won't have any effect
3551 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3552 var fexpr = InstanceExpression as FieldExpr;
3553 if (fexpr != null) {
3554 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3557 if (fexpr.IsStatic) {
3558 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3559 fexpr.GetSignatureForError ());
3561 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3562 fexpr.GetSignatureForError ());
3568 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3569 if (rc.CurrentInitializerVariable != null) {
3570 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3571 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3573 rc.Report.Error (1612, loc,
3574 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3575 InstanceExpression.GetSignatureForError ());
3581 var lvr = InstanceExpression as LocalVariableReference;
3584 if (!lvr.local_info.IsReadonly)
3587 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3588 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3595 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3598 if (InstanceExpression != null) {
3599 if (InstanceExpression is TypeExpr) {
3600 var t = InstanceExpression.Type;
3602 t.CheckObsoleteness (rc, loc);
3604 t = t.DeclaringType;
3605 } while (t != null);
3607 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3608 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3609 rc.Report.Error (176, loc,
3610 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3611 GetSignatureForError ());
3615 InstanceExpression = null;
3621 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3622 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3623 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3624 rc.Report.Error (236, loc,
3625 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3626 GetSignatureForError ());
3628 var fe = this as FieldExpr;
3629 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3630 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3631 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3633 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3637 rc.Report.Error (120, loc,
3638 "An object reference is required to access non-static member `{0}'",
3639 GetSignatureForError ());
3643 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3647 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3648 rc.Report.Error (38, loc,
3649 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3650 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3653 InstanceExpression = new This (loc).Resolve (rc);
3657 var me = InstanceExpression as MemberExpr;
3659 me.ResolveInstanceExpressionCore (rc, rhs);
3661 var fe = me as FieldExpr;
3662 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3663 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3664 rc.Report.Warning (1690, 1, loc,
3665 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3666 me.GetSignatureForError ());
3673 // Additional checks for l-value member access
3676 if (InstanceExpression is UnboxCast) {
3677 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3684 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3686 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3687 ec.Report.Warning (1720, 1, left.Location,
3688 "Expression will always cause a `{0}'", "System.NullReferenceException");
3691 InstanceExpression = left;
3695 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3700 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3702 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3703 inst.Emit (ec, ConditionalAccess);
3705 if (prepare_for_load)
3706 ec.Emit (OpCodes.Dup);
3709 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3712 public class ExtensionMethodCandidates
3714 readonly NamespaceContainer container;
3715 readonly IList<MethodSpec> methods;
3717 readonly IMemberContext context;
3719 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3721 this.context = context;
3722 this.methods = methods;
3723 this.container = nsContainer;
3724 this.index = lookupIndex;
3727 public NamespaceContainer Container {
3733 public IMemberContext Context {
3739 public int LookupIndex {
3745 public IList<MethodSpec> Methods {
3753 // Represents a group of extension method candidates for whole namespace
3755 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3757 ExtensionMethodCandidates candidates;
3758 public Expression ExtensionExpression;
3760 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3761 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3763 this.candidates = candidates;
3764 this.ExtensionExpression = extensionExpr;
3767 public override bool IsStatic {
3768 get { return true; }
3772 // For extension methodgroup we are not looking for base members but parent
3773 // namespace extension methods
3775 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3777 // TODO: candidates are null only when doing error reporting, that's
3778 // incorrect. We have to discover same extension methods in error mode
3779 if (candidates == null)
3782 int arity = type_arguments == null ? 0 : type_arguments.Count;
3784 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3785 if (candidates == null)
3788 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3791 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3794 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3796 // LAMESPEC: or implicit type parameter conversion
3798 return argType == extensionType ||
3799 TypeSpecComparer.IsEqual (argType, extensionType) ||
3800 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3801 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3804 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3806 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3809 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3811 // We are already here
3815 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3817 if (arguments == null)
3818 arguments = new Arguments (1);
3820 ExtensionExpression = ExtensionExpression.Resolve (ec);
3821 if (ExtensionExpression == null)
3824 var cand = candidates;
3825 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3826 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3827 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3829 // Restore candidates in case we are running in probing mode
3832 // Store resolved argument and restore original arguments
3834 // Clean-up modified arguments for error reporting
3835 arguments.RemoveAt (0);
3839 var me = ExtensionExpression as MemberExpr;
3841 me.ResolveInstanceExpression (ec, null);
3842 var fe = me as FieldExpr;
3844 fe.Spec.MemberDefinition.SetIsUsed ();
3847 InstanceExpression = null;
3851 #region IErrorHandler Members
3853 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3858 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3860 rc.Report.SymbolRelatedToPreviousError (best);
3863 rc.Report.Error (1929, loc,
3864 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3865 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3867 rc.Report.Error (1928, loc,
3868 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3869 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3875 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3880 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3889 /// MethodGroupExpr represents a group of method candidates which
3890 /// can be resolved to the best method overload
3892 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3894 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3896 protected IList<MemberSpec> Methods;
3897 MethodSpec best_candidate;
3898 TypeSpec best_candidate_return;
3899 protected TypeArguments type_arguments;
3901 SimpleName simple_name;
3902 protected TypeSpec queried_type;
3904 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3908 this.type = InternalType.MethodGroup;
3910 eclass = ExprClass.MethodGroup;
3911 queried_type = type;
3914 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3915 : this (new MemberSpec[] { m }, type, loc)
3921 public MethodSpec BestCandidate {
3923 return best_candidate;
3927 public TypeSpec BestCandidateReturnType {
3929 return best_candidate_return;
3933 public IList<MemberSpec> Candidates {
3939 protected override TypeSpec DeclaringType {
3941 return queried_type;
3945 public bool IsConditionallyExcluded {
3947 return Methods == Excluded;
3951 public override bool IsInstance {
3953 if (best_candidate != null)
3954 return !best_candidate.IsStatic;
3960 public override bool IsSideEffectFree {
3962 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3966 public override bool IsStatic {
3968 if (best_candidate != null)
3969 return best_candidate.IsStatic;
3975 public override string KindName {
3976 get { return "method"; }
3979 public override string Name {
3981 if (best_candidate != null)
3982 return best_candidate.Name;
3985 return Methods.First ().Name;
3992 // When best candidate is already know this factory can be used
3993 // to avoid expensive overload resolution to be called
3995 // NOTE: InstanceExpression has to be set manually
3997 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3999 return new MethodGroupExpr (best, queriedType, loc) {
4000 best_candidate = best,
4001 best_candidate_return = best.ReturnType
4005 public override string GetSignatureForError ()
4007 if (best_candidate != null)
4008 return best_candidate.GetSignatureForError ();
4010 return Methods.First ().GetSignatureForError ();
4013 public override Expression CreateExpressionTree (ResolveContext ec)
4015 if (best_candidate == null) {
4016 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4020 if (IsConditionallyExcluded)
4021 ec.Report.Error (765, loc,
4022 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4024 if (ConditionalAccess)
4025 Error_NullShortCircuitInsideExpressionTree (ec);
4027 return new TypeOfMethod (best_candidate, loc);
4030 protected override Expression DoResolve (ResolveContext ec)
4032 this.eclass = ExprClass.MethodGroup;
4034 if (InstanceExpression != null) {
4035 InstanceExpression = InstanceExpression.Resolve (ec);
4036 if (InstanceExpression == null)
4043 public override void Emit (EmitContext ec)
4045 throw new NotSupportedException ();
4048 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4050 var call = new CallEmitter ();
4051 call.InstanceExpression = InstanceExpression;
4052 call.ConditionalAccess = ConditionalAccess;
4055 call.EmitStatement (ec, best_candidate, arguments, loc);
4057 call.Emit (ec, best_candidate, arguments, loc);
4060 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4062 var ca = ec.ConditionalAccess;
4063 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4064 Statement = statement
4067 EmitCall (ec, arguments, statement);
4069 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4070 ec.ConditionalAccess = ca;
4073 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4075 if (target != InternalType.ErrorType) {
4076 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4077 Name, target.GetSignatureForError ());
4081 public bool HasAccessibleCandidate (ResolveContext rc)
4083 foreach (var candidate in Candidates) {
4084 if (candidate.IsAccessible (rc))
4091 public static bool IsExtensionMethodArgument (Expression expr)
4094 // LAMESPEC: No details about which expressions are not allowed
4096 return !(expr is TypeExpr) && !(expr is BaseThis);
4100 /// Find the Applicable Function Members (7.4.2.1)
4102 /// me: Method Group expression with the members to select.
4103 /// it might contain constructors or methods (or anything
4104 /// that maps to a method).
4106 /// Arguments: ArrayList containing resolved Argument objects.
4108 /// loc: The location if we want an error to be reported, or a Null
4109 /// location for "probing" purposes.
4111 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4112 /// that is the best match of me on Arguments.
4115 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4117 // TODO: causes issues with probing mode, remove explicit Kind check
4118 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4121 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4122 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4123 r.BaseMembersProvider = this;
4124 r.InstanceQualifier = this;
4127 if (cerrors != null)
4128 r.CustomErrors = cerrors;
4130 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4131 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4132 if (best_candidate == null) {
4133 if (!r.BestCandidateIsDynamic)
4136 if (simple_name != null && ec.IsStatic)
4137 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4142 // Overload resolver had to create a new method group, all checks bellow have already been executed
4143 if (r.BestCandidateNewMethodGroup != null)
4144 return r.BestCandidateNewMethodGroup;
4146 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4147 if (InstanceExpression != null) {
4148 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4149 InstanceExpression = null;
4151 if (simple_name != null && best_candidate.IsStatic) {
4152 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4155 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4159 ResolveInstanceExpression (ec, null);
4162 var base_override = CandidateToBaseOverride (ec, best_candidate);
4163 if (base_override == best_candidate) {
4164 best_candidate_return = r.BestCandidateReturnType;
4166 best_candidate = base_override;
4167 best_candidate_return = best_candidate.ReturnType;
4170 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4171 ConstraintChecker cc = new ConstraintChecker (ec);
4172 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4176 // Additional check for possible imported base override method which
4177 // could not be done during IsOverrideMethodBaseTypeAccessible
4179 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4180 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4181 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4182 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4185 // Speed up the check by not doing it on disallowed targets
4186 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4192 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4194 var fe = left as FieldExpr;
4197 // Using method-group on struct fields makes the struct assigned. I am not sure
4198 // why but that's what .net does
4200 fe.Spec.MemberDefinition.SetIsAssigned ();
4203 simple_name = original;
4204 return base.ResolveMemberAccess (ec, left, original);
4207 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4209 if (!HasAccessibleCandidate (rc)) {
4210 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4213 if (expr.HasTypeArguments) {
4214 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4218 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4220 type_arguments = ta;
4223 #region IBaseMembersProvider Members
4225 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4227 var baseType = type.BaseType;
4229 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4231 if (members == null && !type.IsInterface) {
4232 var tps = queried_type as TypeParameterSpec;
4234 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4240 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4242 if (queried_type == member.DeclaringType)
4245 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4246 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4250 // Extension methods lookup after ordinary methods candidates failed to apply
4252 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4254 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4257 if (!IsExtensionMethodArgument (InstanceExpression))
4260 int arity = type_arguments == null ? 0 : type_arguments.Count;
4261 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4262 if (methods == null)
4265 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4266 emg.SetTypeArguments (rc, type_arguments);
4267 emg.ConditionalAccess = ConditionalAccess;
4274 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4276 public ConstructorInstanceQualifier (TypeSpec type)
4279 InstanceType = type;
4282 public TypeSpec InstanceType { get; private set; }
4284 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4286 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4290 public struct OverloadResolver
4293 public enum Restrictions
4297 ProbingOnly = 1 << 1,
4298 CovariantDelegate = 1 << 2,
4299 NoBaseMembers = 1 << 3,
4300 BaseMembersIncluded = 1 << 4,
4301 GetEnumeratorLookup = 1 << 5
4304 public interface IBaseMembersProvider
4306 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4307 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4308 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4311 public interface IErrorHandler
4313 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4314 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4315 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4316 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4319 public interface IInstanceQualifier
4321 TypeSpec InstanceType { get; }
4322 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4325 sealed class NoBaseMembers : IBaseMembersProvider
4327 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4329 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4334 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4339 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4345 struct AmbiguousCandidate
4347 public readonly MemberSpec Member;
4348 public readonly bool Expanded;
4349 public readonly AParametersCollection Parameters;
4351 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4354 Parameters = parameters;
4355 Expanded = expanded;
4360 IList<MemberSpec> members;
4361 TypeArguments type_arguments;
4362 IBaseMembersProvider base_provider;
4363 IErrorHandler custom_errors;
4364 IInstanceQualifier instance_qualifier;
4365 Restrictions restrictions;
4366 MethodGroupExpr best_candidate_extension_group;
4367 TypeSpec best_candidate_return_type;
4369 SessionReportPrinter lambda_conv_msgs;
4371 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4372 : this (members, null, restrictions, loc)
4376 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4379 if (members == null || members.Count == 0)
4380 throw new ArgumentException ("empty members set");
4382 this.members = members;
4384 type_arguments = targs;
4385 this.restrictions = restrictions;
4386 if (IsDelegateInvoke)
4387 this.restrictions |= Restrictions.NoBaseMembers;
4389 base_provider = NoBaseMembers.Instance;
4394 public IBaseMembersProvider BaseMembersProvider {
4396 return base_provider;
4399 base_provider = value;
4403 public bool BestCandidateIsDynamic { get; set; }
4406 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4408 public MethodGroupExpr BestCandidateNewMethodGroup {
4410 return best_candidate_extension_group;
4415 // Return type can be different between best candidate and closest override
4417 public TypeSpec BestCandidateReturnType {
4419 return best_candidate_return_type;
4423 public IErrorHandler CustomErrors {
4425 return custom_errors;
4428 custom_errors = value;
4432 TypeSpec DelegateType {
4434 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4435 throw new InternalErrorException ("Not running in delegate mode", loc);
4437 return members [0].DeclaringType;
4441 public IInstanceQualifier InstanceQualifier {
4443 return instance_qualifier;
4446 instance_qualifier = value;
4450 bool IsProbingOnly {
4452 return (restrictions & Restrictions.ProbingOnly) != 0;
4456 bool IsDelegateInvoke {
4458 return (restrictions & Restrictions.DelegateInvoke) != 0;
4465 // 7.4.3.3 Better conversion from expression
4466 // Returns : 1 if a->p is better,
4467 // 2 if a->q is better,
4468 // 0 if neither is better
4470 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4472 TypeSpec argument_type = a.Type;
4475 // Exactly matching Expression phase
4479 // If argument is an anonymous function
4481 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4483 // p and q are delegate types or expression tree types
4485 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4486 if (q.MemberDefinition != p.MemberDefinition) {
4491 // Uwrap delegate from Expression<T>
4493 q = TypeManager.GetTypeArguments (q) [0];
4494 p = TypeManager.GetTypeArguments (p) [0];
4497 var p_m = Delegate.GetInvokeMethod (p);
4498 var q_m = Delegate.GetInvokeMethod (q);
4501 // With identical parameter lists
4503 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4511 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4513 if (p.Kind == MemberKind.Void) {
4514 return q.Kind != MemberKind.Void ? 2 : 0;
4518 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4520 if (q.Kind == MemberKind.Void) {
4521 return p.Kind != MemberKind.Void ? 1 : 0;
4524 var am = (AnonymousMethodExpression)a.Expr;
4527 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4528 // better conversion is performed between underlying types Y1 and Y2
4530 if (p.IsGenericTask || q.IsGenericTask) {
4531 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4532 q = q.TypeArguments [0];
4533 p = p.TypeArguments [0];
4539 // An inferred return type X exists for E in the context of the parameter list, and
4540 // an identity conversion exists from X to the return type of D
4542 var inferred_type = am.InferReturnType (ec, null, orig_q);
4543 if (inferred_type != null) {
4544 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4545 inferred_type = ec.BuiltinTypes.Object;
4547 if (inferred_type == p)
4550 if (inferred_type == q)
4556 if (argument_type == p)
4559 if (argument_type == q)
4562 return IsBetterConversionTarget (ec, p, q);
4565 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4567 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4569 if (p.Kind != MemberKind.Delegate) {
4570 p = TypeManager.GetTypeArguments (p) [0];
4573 if (q.Kind != MemberKind.Delegate) {
4574 q = TypeManager.GetTypeArguments (q) [0];
4577 var p_m = Delegate.GetInvokeMethod (p);
4578 var q_m = Delegate.GetInvokeMethod (q);
4584 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4586 if (p.Kind == MemberKind.Void) {
4587 return q.Kind != MemberKind.Void ? 2 : 0;
4591 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4593 if (q.Kind == MemberKind.Void) {
4594 return p.Kind != MemberKind.Void ? 1 : 0;
4597 return IsBetterConversionTarget (rc, p, q);
4600 if (p.IsGenericTask && q.IsGenericTask) {
4601 q = q.TypeArguments [0];
4602 p = p.TypeArguments [0];
4603 return IsBetterConversionTarget (rc, p, q);
4607 if (p.IsNullableType) {
4608 p = Nullable.NullableInfo.GetUnderlyingType (p);
4609 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4610 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4613 // Spec expects implicit conversion check between p and q, q and p
4614 // to be done before nullable unwrapping but that's expensive operation.
4616 // Extra manual tweak is needed because BetterTypeConversion works on
4624 if (q.IsNullableType) {
4625 q = Nullable.NullableInfo.GetUnderlyingType (q);
4626 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4627 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4633 return BetterTypeConversion (rc, p, q);
4637 // 7.4.3.4 Better conversion from type
4639 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4641 if (p == null || q == null)
4642 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4644 switch (p.BuiltinType) {
4645 case BuiltinTypeSpec.Type.Int:
4646 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4649 case BuiltinTypeSpec.Type.Long:
4650 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4653 case BuiltinTypeSpec.Type.SByte:
4654 switch (q.BuiltinType) {
4655 case BuiltinTypeSpec.Type.Byte:
4656 case BuiltinTypeSpec.Type.UShort:
4657 case BuiltinTypeSpec.Type.UInt:
4658 case BuiltinTypeSpec.Type.ULong:
4662 case BuiltinTypeSpec.Type.Short:
4663 switch (q.BuiltinType) {
4664 case BuiltinTypeSpec.Type.UShort:
4665 case BuiltinTypeSpec.Type.UInt:
4666 case BuiltinTypeSpec.Type.ULong:
4670 case BuiltinTypeSpec.Type.Dynamic:
4671 // LAMESPEC: Dynamic conversions is not considered
4672 p = ec.Module.Compiler.BuiltinTypes.Object;
4676 switch (q.BuiltinType) {
4677 case BuiltinTypeSpec.Type.Int:
4678 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4681 case BuiltinTypeSpec.Type.Long:
4682 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4685 case BuiltinTypeSpec.Type.SByte:
4686 switch (p.BuiltinType) {
4687 case BuiltinTypeSpec.Type.Byte:
4688 case BuiltinTypeSpec.Type.UShort:
4689 case BuiltinTypeSpec.Type.UInt:
4690 case BuiltinTypeSpec.Type.ULong:
4694 case BuiltinTypeSpec.Type.Short:
4695 switch (p.BuiltinType) {
4696 case BuiltinTypeSpec.Type.UShort:
4697 case BuiltinTypeSpec.Type.UInt:
4698 case BuiltinTypeSpec.Type.ULong:
4702 case BuiltinTypeSpec.Type.Dynamic:
4703 // LAMESPEC: Dynamic conversions is not considered
4704 q = ec.Module.Compiler.BuiltinTypes.Object;
4708 return BetterTypeConversionImplicitConversion (ec, p, q);
4711 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4713 // TODO: this is expensive
4714 Expression p_tmp = new EmptyExpression (p);
4715 Expression q_tmp = new EmptyExpression (q);
4717 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4718 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4720 if (p_to_q && !q_to_p)
4723 if (q_to_p && !p_to_q)
4730 /// Determines "Better function" between candidate
4731 /// and the current best match
4734 /// Returns a boolean indicating :
4735 /// false if candidate ain't better
4736 /// true if candidate is better than the current best match
4738 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4739 MemberSpec best, AParametersCollection bparam, bool best_params)
4741 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4742 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4744 int candidate_better_count = 0;
4745 int best_better_count = 0;
4747 bool are_equivalent = true;
4748 int args_count = args == null ? 0 : args.Count;
4752 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4755 // Default arguments are ignored for better decision
4756 if (a.IsDefaultArgument)
4760 // When comparing named argument the parameter type index has to be looked up
4761 // in original parameter set (override version for virtual members)
4763 NamedArgument na = a as NamedArgument;
4765 int idx = cparam.GetParameterIndexByName (na.Name);
4766 ct = candidate_pd.Types[idx];
4767 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4768 ct = TypeManager.GetElementType (ct);
4770 idx = bparam.GetParameterIndexByName (na.Name);
4771 bt = best_pd.Types[idx];
4772 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4773 bt = TypeManager.GetElementType (bt);
4775 ct = candidate_pd.Types[c_idx];
4776 bt = best_pd.Types[b_idx];
4778 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4779 ct = TypeManager.GetElementType (ct);
4783 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4784 bt = TypeManager.GetElementType (bt);
4789 if (TypeSpecComparer.IsEqual (ct, bt))
4792 are_equivalent = false;
4793 int result = BetterExpressionConversion (ec, a, ct, bt);
4795 // for each argument, the conversion to 'ct' should be no worse than
4796 // the conversion to 'bt'.
4799 // No optional parameters tie breaking rules for delegates overload resolution
4801 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4804 ++best_better_count;
4808 // for at least one argument, the conversion to 'ct' should be better than
4809 // the conversion to 'bt'.
4811 ++candidate_better_count;
4814 if (candidate_better_count != 0 && best_better_count == 0)
4817 if (best_better_count > 0 && candidate_better_count == 0)
4821 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4823 if (!are_equivalent) {
4824 while (j < args_count && !args [j++].IsDefaultArgument) ;
4827 // A candidate with no default parameters is still better when there
4828 // is no better expression conversion and does not have more parameters
4830 if (candidate_pd.Count < best_pd.Count) {
4831 if (candidate_params)
4834 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4837 if (best_pd.FixedParameters [j].HasDefaultValue)
4840 } else if (candidate_pd.Count == best_pd.Count) {
4841 if (candidate_params)
4844 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4847 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4855 // If candidate is applicable in its normal form and best has a params array and is applicable
4856 // only in its expanded form, then candidate is better
4858 if (candidate_params != best_params)
4859 return !candidate_params;
4862 // We have not reached end of parameters list due to params or used default parameters
4864 bool defaults_ambiguity = false;
4865 while (j < candidate_pd.Count && j < best_pd.Count) {
4866 var cand_param = candidate_pd.FixedParameters [j];
4867 var best_param = best_pd.FixedParameters [j];
4869 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4870 return cand_param.HasDefaultValue;
4872 defaults_ambiguity = true;
4873 if (candidate_pd.Count == best_pd.Count) {
4877 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4878 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4880 if (cand_param.HasDefaultValue) {
4889 // Neither is better when not all arguments are provided
4891 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4892 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4893 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4898 if (candidate_pd.Count != best_pd.Count) {
4899 if (defaults_ambiguity && best_pd.Count - 1 == j)
4900 return best_pd.HasParams;
4902 return candidate_pd.Count < best_pd.Count;
4906 // One is a non-generic method and second is a generic method, then non-generic is better
4908 if (best.IsGeneric != candidate.IsGeneric)
4909 return best.IsGeneric;
4912 // Both methods have the same number of parameters, and the parameters have equal types
4913 // Pick the "more specific" signature using rules over original (non-inflated) types
4915 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4916 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4918 bool specific_at_least_once = false;
4919 for (j = 0; j < args_count; ++j) {
4920 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4922 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4923 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4925 ct = candidate_def_pd.Types[j];
4926 bt = best_def_pd.Types[j];
4931 TypeSpec specific = MoreSpecific (ct, bt);
4935 specific_at_least_once = true;
4938 if (specific_at_least_once)
4944 static bool CheckInflatedArguments (MethodSpec ms)
4946 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4949 // Setup constraint checker for probing only
4950 ConstraintChecker cc = new ConstraintChecker (null);
4952 var mp = ms.Parameters.Types;
4953 for (int i = 0; i < mp.Length; ++i) {
4954 var type = mp[i] as InflatedTypeSpec;
4958 var targs = type.TypeArguments;
4959 if (targs.Length == 0)
4962 // TODO: Checking inflated MVAR arguments should be enough
4963 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4970 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4972 rc.Report.Error (1729, loc,
4973 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4974 type.GetSignatureForError (), argCount.ToString ());
4978 // Determines if the candidate method is applicable to the given set of arguments
4979 // There could be two different set of parameters for same candidate where one
4980 // is the closest override for default values and named arguments checks and second
4981 // one being the virtual base for the parameter types and modifiers.
4983 // A return value rates candidate method compatibility,
4985 // 0 = the best, int.MaxValue = the worst
4987 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)
4990 // Each step has allocated 10 values, it can overflow for
4991 // more than 10 arguments but that's ok as it's used for
4992 // better error reporting only
4994 const int ArgumentCountMismatch = 1000000000;
4995 const int NamedArgumentsMismatch = 100000000;
4996 const int DefaultArgumentMismatch = 10000000;
4997 const int UnexpectedTypeArguments = 1000000;
4998 const int TypeArgumentsMismatch = 100000;
4999 const int InflatedTypesMismatch = 10000;
5001 // Parameters of most-derived type used mainly for named and optional parameters
5002 var pd = pm.Parameters;
5004 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
5005 // params modifier instead of most-derived type
5006 var cpd = ((IParametersMember) candidate).Parameters;
5007 int param_count = pd.Count;
5008 int optional_count = 0;
5010 Arguments orig_args = arguments;
5012 if (arg_count != param_count) {
5014 // No arguments expansion when doing exact match for delegates
5016 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5017 for (int i = 0; i < pd.Count; ++i) {
5018 if (pd.FixedParameters[i].HasDefaultValue) {
5019 optional_count = pd.Count - i;
5025 if (optional_count != 0) {
5026 // Readjust expected number when params used
5027 if (cpd.HasParams) {
5029 if (arg_count < param_count)
5031 } else if (arg_count > param_count) {
5032 int args_gap = System.Math.Abs (arg_count - param_count);
5033 return ArgumentCountMismatch + args_gap;
5034 } else if (arg_count < param_count - optional_count) {
5035 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5036 return ArgumentCountMismatch + args_gap;
5038 } else if (arg_count != param_count) {
5039 int args_gap = System.Math.Abs (arg_count - param_count);
5041 return ArgumentCountMismatch + args_gap;
5042 if (arg_count < param_count - 1)
5043 return ArgumentCountMismatch + args_gap;
5046 // Resize to fit optional arguments
5047 if (optional_count != 0) {
5048 if (arguments == null) {
5049 arguments = new Arguments (optional_count);
5051 // Have to create a new container, so the next run can do same
5052 var resized = new Arguments (param_count);
5053 resized.AddRange (arguments);
5054 arguments = resized;
5057 for (int i = arg_count; i < param_count; ++i)
5058 arguments.Add (null);
5062 if (arg_count > 0) {
5064 // Shuffle named arguments to the right positions if there are any
5066 if (arguments[arg_count - 1] is NamedArgument) {
5067 arg_count = arguments.Count;
5069 for (int i = 0; i < arg_count; ++i) {
5070 bool arg_moved = false;
5072 NamedArgument na = arguments[i] as NamedArgument;
5076 int index = pd.GetParameterIndexByName (na.Name);
5078 // Named parameter not found
5080 return NamedArgumentsMismatch - i;
5082 // already reordered
5087 if (index >= param_count) {
5088 // When using parameters which should not be available to the user
5089 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5092 arguments.Add (null);
5096 if (index == arg_count)
5097 return NamedArgumentsMismatch - i - 1;
5099 temp = arguments [index];
5101 // The slot has been taken by positional argument
5102 if (temp != null && !(temp is NamedArgument))
5103 return NamedArgumentsMismatch - i - 1;
5107 arguments = arguments.MarkOrderedArgument (na);
5111 if (arguments == orig_args) {
5112 arguments = new Arguments (orig_args.Count);
5113 arguments.AddRange (orig_args);
5116 arguments[index] = arguments[i];
5117 arguments[i] = temp;
5124 arg_count = arguments.Count;
5126 } else if (arguments != null) {
5127 arg_count = arguments.Count;
5131 // Don't do any expensive checks when the candidate cannot succeed
5133 if (arg_count != param_count && !cpd.HasParams)
5134 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5136 var dep = candidate.GetMissingDependencies ();
5138 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5143 // 1. Handle generic method using type arguments when specified or type inference
5146 var ms = candidate as MethodSpec;
5147 if (ms != null && ms.IsGeneric) {
5148 if (type_arguments != null) {
5149 var g_args_count = ms.Arity;
5150 if (g_args_count != type_arguments.Count)
5151 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5153 if (type_arguments.Arguments != null)
5154 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5157 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5158 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5159 // candidate was found use the set to report more details about what was wrong with lambda body.
5160 // The general idea is to distinguish between code errors and errors caused by
5161 // trial-and-error type inference
5163 if (lambda_conv_msgs == null) {
5164 for (int i = 0; i < arg_count; i++) {
5165 Argument a = arguments[i];
5169 var am = a.Expr as AnonymousMethodExpression;
5171 if (lambda_conv_msgs == null)
5172 lambda_conv_msgs = new SessionReportPrinter ();
5174 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5179 var ti = new TypeInference (arguments);
5180 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5183 return TypeArgumentsMismatch - ti.InferenceScore;
5186 // Clear any error messages when the result was success
5188 if (lambda_conv_msgs != null)
5189 lambda_conv_msgs.ClearSession ();
5191 if (i_args.Length != 0) {
5193 for (int i = 0; i < i_args.Length; ++i) {
5194 var ta = i_args [i];
5195 if (!ta.IsAccessible (ec))
5196 return TypeArgumentsMismatch - i;
5200 ms = ms.MakeGenericMethod (ec, i_args);
5205 // Type arguments constraints have to match for the method to be applicable
5207 if (!CheckInflatedArguments (ms)) {
5209 return InflatedTypesMismatch;
5213 // We have a generic return type and at same time the method is override which
5214 // means we have to also inflate override return type in case the candidate is
5215 // best candidate and override return type is different to base return type.
5217 // virtual Foo<T, object> with override Foo<T, dynamic>
5219 if (candidate != pm) {
5220 MethodSpec override_ms = (MethodSpec) pm;
5221 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5222 returnType = inflator.Inflate (returnType);
5224 returnType = ms.ReturnType;
5231 if (type_arguments != null)
5232 return UnexpectedTypeArguments;
5238 // 2. Each argument has to be implicitly convertible to method parameter
5240 Parameter.Modifier p_mod = 0;
5243 for (int i = 0; i < arg_count; i++) {
5244 Argument a = arguments[i];
5246 var fp = pd.FixedParameters[i];
5247 if (!fp.HasDefaultValue) {
5248 arguments = orig_args;
5249 return arg_count * 2 + 2;
5253 // Get the default value expression, we can use the same expression
5254 // if the type matches
5256 Expression e = fp.DefaultValue;
5258 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5260 // Restore for possible error reporting
5261 for (int ii = i; ii < arg_count; ++ii)
5262 arguments.RemoveAt (i);
5264 return (arg_count - i) * 2 + 1;
5268 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5270 // LAMESPEC: Attributes can be mixed together with build-in priority
5272 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5273 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5274 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5275 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5276 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5277 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5281 arguments[i] = new Argument (e, Argument.AType.Default);
5285 if (p_mod != Parameter.Modifier.PARAMS) {
5286 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5288 } else if (!params_expanded_form) {
5289 params_expanded_form = true;
5290 pt = ((ElementTypeSpec) pt).Element;
5296 if (!params_expanded_form) {
5297 if (a.IsExtensionType) {
5298 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5303 score = IsArgumentCompatible (ec, a, p_mod, pt);
5306 dynamicArgument = true;
5311 // It can be applicable in expanded form (when not doing exact match like for delegates)
5313 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5314 if (!params_expanded_form) {
5315 pt = ((ElementTypeSpec) pt).Element;
5319 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5322 params_expanded_form = true;
5323 dynamicArgument = true;
5324 } else if (score == 0 || arg_count > pd.Count) {
5325 params_expanded_form = true;
5330 if (params_expanded_form)
5332 return (arg_count - i) * 2 + score;
5337 // Restore original arguments for dynamic binder to keep the intention of original source code
5339 if (dynamicArgument)
5340 arguments = orig_args;
5345 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5347 if (e is Constant && e.Type == ptype)
5351 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5353 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5354 e = new MemberAccess (new MemberAccess (new MemberAccess (
5355 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5356 } else if (e is Constant) {
5358 // Handles int to int? conversions, DefaultParameterValue check
5360 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5364 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5367 return e.Resolve (ec);
5371 // Tests argument compatibility with the parameter
5372 // The possible return values are
5374 // 1 - modifier mismatch
5375 // 2 - type mismatch
5376 // -1 - dynamic binding required
5378 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5381 // Types have to be identical when ref or out modifer
5382 // is used and argument is not of dynamic type
5384 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5385 var arg_type = argument.Type;
5387 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5389 // Using dynamic for ref/out parameter can still succeed at runtime
5391 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5397 if (arg_type != parameter) {
5398 if (arg_type == InternalType.VarOutType)
5402 // Do full equality check after quick path
5404 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5406 // Using dynamic for ref/out parameter can still succeed at runtime
5408 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5416 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5420 // Use implicit conversion in all modes to return same candidates when the expression
5421 // is used as argument or delegate conversion
5423 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5424 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5431 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5433 if (p.IsGenericParameter != q.IsGenericParameter)
5434 return p.IsGenericParameter ? q : p;
5436 var ac_p = p as ArrayContainer;
5438 var ac_q = q as ArrayContainer;
5442 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5443 if (specific == ac_p.Element)
5445 if (specific == ac_q.Element)
5451 if (p.IsGeneric && q.IsGeneric) {
5452 var pargs = p.TypeArguments;
5453 var qargs = q.TypeArguments;
5455 bool p_specific_at_least_once = false;
5456 bool q_specific_at_least_once = false;
5458 for (int i = 0; i < pargs.Length; i++) {
5459 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5460 if (specific == pargs [i])
5461 p_specific_at_least_once = true;
5462 if (specific == qargs [i])
5463 q_specific_at_least_once = true;
5466 if (p_specific_at_least_once && !q_specific_at_least_once)
5468 if (!p_specific_at_least_once && q_specific_at_least_once)
5476 // Find the best method from candidate list
5478 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5480 List<AmbiguousCandidate> ambiguous_candidates = null;
5482 MemberSpec best_candidate;
5483 Arguments best_candidate_args = null;
5484 bool best_candidate_params = false;
5485 bool best_candidate_dynamic = false;
5486 int best_candidate_rate;
5487 IParametersMember best_parameter_member = null;
5489 int args_count = args != null ? args.Count : 0;
5491 Arguments candidate_args = args;
5492 bool error_mode = false;
5493 MemberSpec invocable_member = null;
5494 int applicable_candidates = 0;
5497 best_candidate = null;
5498 best_candidate_rate = int.MaxValue;
5500 var type_members = members;
5502 for (int i = 0; i < type_members.Count; ++i) {
5503 var member = type_members[i];
5506 // Methods in a base class are not candidates if any method in a derived
5507 // class is applicable
5509 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5513 if (!member.IsAccessible (rc))
5516 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5519 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5520 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5525 IParametersMember pm = member as IParametersMember;
5528 // Will use it later to report ambiguity between best method and invocable member
5530 if (Invocation.IsMemberInvocable (member))
5531 invocable_member = member;
5537 // Overload resolution is looking for base member but using parameter names
5538 // and default values from the closest member. That means to do expensive lookup
5539 // for the closest override for virtual or abstract members
5541 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5542 var override_params = base_provider.GetOverrideMemberParameters (member);
5543 if (override_params != null)
5544 pm = override_params;
5548 // Check if the member candidate is applicable
5550 bool params_expanded_form = false;
5551 bool dynamic_argument = false;
5552 TypeSpec rt = pm.MemberType;
5553 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5555 if (lambda_conv_msgs != null)
5556 lambda_conv_msgs.EndSession ();
5559 // How does it score compare to others
5561 if (candidate_rate < best_candidate_rate) {
5563 // Fatal error (missing dependency), cannot continue
5564 if (candidate_rate < 0)
5567 applicable_candidates = 1;
5568 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5569 // Only parameterless methods are considered
5571 best_candidate_rate = candidate_rate;
5572 best_candidate = member;
5573 best_candidate_args = candidate_args;
5574 best_candidate_params = params_expanded_form;
5575 best_candidate_dynamic = dynamic_argument;
5576 best_parameter_member = pm;
5577 best_candidate_return_type = rt;
5579 } else if (candidate_rate == 0) {
5581 // The member look is done per type for most operations but sometimes
5582 // it's not possible like for binary operators overload because they
5583 // are unioned between 2 sides
5585 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5586 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5590 ++applicable_candidates;
5592 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5594 // We pack all interface members into top level type which makes the overload resolution
5595 // more complicated for interfaces. We compensate it by removing methods with same
5596 // signature when building the cache hence this path should not really be hit often
5599 // interface IA { void Foo (int arg); }
5600 // interface IB : IA { void Foo (params int[] args); }
5602 // IB::Foo is the best overload when calling IB.Foo (1)
5605 if (ambiguous_candidates != null) {
5606 foreach (var amb_cand in ambiguous_candidates) {
5607 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5616 ambiguous_candidates = null;
5619 // Is the new candidate better
5620 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5624 best_candidate = member;
5625 best_candidate_args = candidate_args;
5626 best_candidate_params = params_expanded_form;
5627 best_candidate_dynamic = dynamic_argument;
5628 best_parameter_member = pm;
5629 best_candidate_return_type = rt;
5631 // It's not better but any other found later could be but we are not sure yet
5632 if (ambiguous_candidates == null)
5633 ambiguous_candidates = new List<AmbiguousCandidate> ();
5635 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5639 // Restore expanded arguments
5640 candidate_args = args;
5642 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5645 // We've found exact match
5647 if (best_candidate_rate == 0)
5651 // Try extension methods lookup when no ordinary method match was found and provider enables it
5654 var emg = base_provider.LookupExtensionMethod (rc);
5656 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5658 best_candidate_extension_group = emg;
5659 return (T) (MemberSpec) emg.BestCandidate;
5664 // Don't run expensive error reporting mode for probing
5671 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5674 lambda_conv_msgs = null;
5679 // No best member match found, report an error
5681 if (best_candidate_rate != 0 || error_mode) {
5682 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5686 if (best_candidate_dynamic) {
5687 if (args[0].IsExtensionType) {
5688 rc.Report.Error (1973, loc,
5689 "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",
5690 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5694 // Check type constraints only when explicit type arguments are used
5696 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5697 MethodSpec bc = best_candidate as MethodSpec;
5698 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5699 ConstraintChecker cc = new ConstraintChecker (rc);
5700 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5704 BestCandidateIsDynamic = true;
5709 // These flags indicates we are running delegate probing conversion. No need to
5710 // do more expensive checks
5712 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5713 return (T) best_candidate;
5715 if (ambiguous_candidates != null) {
5717 // Now check that there are no ambiguities i.e the selected method
5718 // should be better than all the others
5720 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5721 var candidate = ambiguous_candidates [ix];
5723 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5724 var ambiguous = candidate.Member;
5725 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5726 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5727 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5728 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5729 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5732 return (T) best_candidate;
5737 if (invocable_member != null && !IsProbingOnly) {
5738 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5739 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5740 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5741 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5745 // And now check if the arguments are all
5746 // compatible, perform conversions if
5747 // necessary etc. and return if everything is
5750 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5753 if (best_candidate == null)
5757 // Don't run possibly expensive checks in probing mode
5759 if (!IsProbingOnly && !rc.IsInProbingMode) {
5761 // Check ObsoleteAttribute on the best method
5763 best_candidate.CheckObsoleteness (rc, loc);
5765 best_candidate.MemberDefinition.SetIsUsed ();
5768 args = best_candidate_args;
5769 return (T) best_candidate;
5772 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5774 return ResolveMember<MethodSpec> (rc, ref args);
5777 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5778 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5780 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5783 if (a.Type == InternalType.ErrorType)
5786 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5787 ec.Report.SymbolRelatedToPreviousError (method);
5788 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5789 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5790 TypeManager.CSharpSignature (method));
5793 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5794 TypeManager.CSharpSignature (method));
5795 } else if (IsDelegateInvoke) {
5796 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5797 DelegateType.GetSignatureForError ());
5799 ec.Report.SymbolRelatedToPreviousError (method);
5800 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5801 method.GetSignatureForError ());
5804 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5806 string index = (idx + 1).ToString ();
5807 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5808 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5809 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5810 index, Parameter.GetModifierSignature (a.Modifier));
5812 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5813 index, Parameter.GetModifierSignature (mod));
5815 string p1 = a.GetSignatureForError ();
5816 string p2 = paramType.GetSignatureForError ();
5819 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5820 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5823 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5824 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5825 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5828 ec.Report.Error (1503, a.Expr.Location,
5829 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5834 // We have failed to find exact match so we return error info about the closest match
5836 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5838 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5839 int arg_count = args == null ? 0 : args.Count;
5841 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5842 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5843 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5847 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5852 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5853 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5854 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5858 // For candidates which match on parameters count report more details about incorrect arguments
5861 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5862 // Reject any inaccessible member
5863 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5864 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5865 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5869 var ms = best_candidate as MethodSpec;
5870 if (ms != null && ms.IsGeneric) {
5871 bool constr_ok = true;
5872 if (ms.TypeArguments != null)
5873 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5875 if (ta_count == 0 && ms.TypeArguments == null) {
5876 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5880 rc.Report.Error (411, loc,
5881 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5882 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5889 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5895 // We failed to find any method with correct argument count, report best candidate
5897 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5900 if (best_candidate.Kind == MemberKind.Constructor) {
5901 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5902 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5903 } else if (IsDelegateInvoke) {
5904 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5905 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5906 DelegateType.GetSignatureForError (), arg_count.ToString ());
5908 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5909 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5910 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5911 name, arg_count.ToString ());
5915 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5917 var p = ((IParametersMember)best_candidate).Parameters;
5922 for (int i = p.Count - 1; i != 0; --i) {
5923 var fp = p.FixedParameters [i];
5924 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5934 foreach (var arg in args) {
5935 var na = arg as NamedArgument;
5939 if (na.Name == name) {
5948 return args.Count + 1 == pm.Parameters.Count;
5951 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5953 var pd = pm.Parameters;
5954 var cpd = ((IParametersMember) member).Parameters;
5955 var ptypes = cpd.Types;
5957 Parameter.Modifier p_mod = 0;
5959 int a_idx = 0, a_pos = 0;
5961 ArrayInitializer params_initializers = null;
5962 bool has_unsafe_arg = pm.MemberType.IsPointer;
5963 int arg_count = args == null ? 0 : args.Count;
5965 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5970 if (p_mod != Parameter.Modifier.PARAMS) {
5971 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5973 has_unsafe_arg |= pt.IsPointer;
5975 if (p_mod == Parameter.Modifier.PARAMS) {
5976 if (chose_params_expanded) {
5977 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5978 pt = TypeManager.GetElementType (pt);
5984 // Types have to be identical when ref or out modifer is used
5986 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5987 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5990 var arg_type = a.Type;
5994 if (arg_type == InternalType.VarOutType) {
5996 // Set underlying variable type based on parameter type
5998 ((DeclarationExpression)a.Expr).Variable.Type = pt;
6002 if (!TypeSpecComparer.IsEqual (arg_type, pt))
6006 NamedArgument na = a as NamedArgument;
6008 int name_index = pd.GetParameterIndexByName (na.Name);
6009 if (name_index < 0 || name_index >= pd.Count) {
6010 if (IsDelegateInvoke) {
6011 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6012 ec.Report.Error (1746, na.Location,
6013 "The delegate `{0}' does not contain a parameter named `{1}'",
6014 DelegateType.GetSignatureForError (), na.Name);
6016 ec.Report.SymbolRelatedToPreviousError (member);
6017 ec.Report.Error (1739, na.Location,
6018 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6019 TypeManager.CSharpSignature (member), na.Name);
6021 } else if (args[name_index] != a && args[name_index] != null) {
6022 if (IsDelegateInvoke)
6023 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6025 ec.Report.SymbolRelatedToPreviousError (member);
6027 ec.Report.Error (1744, na.Location,
6028 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6033 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6036 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6037 if (a.IsExtensionType) {
6038 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6039 // CS1061 but that still better than confusing CS0123
6040 var ma = new MemberAccess (a.Expr, member.Name, loc);
6041 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6043 custom_errors.NoArgumentMatch (ec, member);
6049 if (a.IsExtensionType) {
6050 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6053 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6055 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6058 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6065 // Convert params arguments to an array initializer
6067 if (params_initializers != null) {
6068 // we choose to use 'a.Expr' rather than 'conv' so that
6069 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6070 params_initializers.Add (a.Expr);
6071 args.RemoveAt (a_idx--);
6077 // Update the argument with the implicit conversion
6081 if (a_idx != arg_count) {
6083 // Convert all var out argument to error type for less confusing error reporting
6084 // when no matching overload is found
6086 for (; a_idx < arg_count; a_idx++) {
6087 var arg = args [a_idx];
6091 if (arg.Type == InternalType.VarOutType) {
6092 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6096 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6101 // Fill not provided arguments required by params modifier
6103 if (params_initializers == null && arg_count + 1 == pd.Count) {
6105 args = new Arguments (1);
6107 pt = ptypes[pd.Count - 1];
6108 pt = TypeManager.GetElementType (pt);
6109 has_unsafe_arg |= pt.IsPointer;
6110 params_initializers = new ArrayInitializer (0, loc);
6114 // Append an array argument with all params arguments
6116 if (params_initializers != null) {
6117 args.Add (new Argument (
6118 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6122 if (has_unsafe_arg) {
6123 if (ec.CurrentIterator != null) {
6124 Expression.UnsafeInsideIteratorError (ec, loc);
6125 } else if (!ec.IsUnsafe) {
6126 Expression.UnsafeError (ec, loc);
6131 // We could infer inaccesible type arguments
6133 if (type_arguments == null && member.IsGeneric) {
6134 var ms = (MethodSpec) member;
6135 foreach (var ta in ms.TypeArguments) {
6136 if (!ta.IsAccessible (ec)) {
6137 ec.Report.SymbolRelatedToPreviousError (ta);
6138 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6148 public class ConstantExpr : MemberExpr
6150 readonly ConstSpec constant;
6152 public ConstantExpr (ConstSpec constant, Location loc)
6154 this.constant = constant;
6158 public override string Name {
6159 get { throw new NotImplementedException (); }
6162 public override string KindName {
6163 get { return "constant"; }
6166 public override bool IsInstance {
6167 get { return !IsStatic; }
6170 public override bool IsStatic {
6171 get { return true; }
6174 protected override TypeSpec DeclaringType {
6175 get { return constant.DeclaringType; }
6178 public override Expression CreateExpressionTree (ResolveContext ec)
6180 throw new NotSupportedException ("ET");
6183 protected override Expression DoResolve (ResolveContext rc)
6185 ResolveInstanceExpression (rc, null);
6186 DoBestMemberChecks (rc, constant);
6188 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6189 eclass = ExprClass.Value;
6190 type = constant.MemberType;
6194 var c = constant.GetConstant (rc);
6196 // Creates reference expression to the constant value
6197 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6200 public override void Emit (EmitContext ec)
6202 throw new NotSupportedException ();
6205 public override string GetSignatureForError ()
6207 return constant.GetSignatureForError ();
6210 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6212 constant.CheckObsoleteness (rc, expr.Location);
6215 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6217 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6222 // Fully resolved expression that references a Field
6224 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6226 protected FieldSpec spec;
6227 VariableInfo variable_info;
6229 LocalTemporary temp;
6232 protected FieldExpr (Location l)
6237 public FieldExpr (FieldSpec spec, Location loc)
6242 type = spec.MemberType;
6245 public FieldExpr (FieldBase fi, Location l)
6252 public override string Name {
6258 public bool IsHoisted {
6260 IVariableReference hv = InstanceExpression as IVariableReference;
6261 return hv != null && hv.IsHoisted;
6265 public override bool IsInstance {
6267 return !spec.IsStatic;
6271 public override bool IsStatic {
6273 return spec.IsStatic;
6277 public override string KindName {
6278 get { return "field"; }
6281 public FieldSpec Spec {
6287 protected override TypeSpec DeclaringType {
6289 return spec.DeclaringType;
6293 public VariableInfo VariableInfo {
6295 return variable_info;
6301 public override string GetSignatureForError ()
6303 return spec.GetSignatureForError ();
6306 public bool IsMarshalByRefAccess (ResolveContext rc)
6308 // Checks possible ldflda of field access expression
6309 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6310 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6311 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6314 public void SetHasAddressTaken ()
6316 IVariableReference vr = InstanceExpression as IVariableReference;
6318 vr.SetHasAddressTaken ();
6322 protected override void CloneTo (CloneContext clonectx, Expression target)
6324 var t = (FieldExpr) target;
6326 if (InstanceExpression != null)
6327 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6330 public override Expression CreateExpressionTree (ResolveContext ec)
6332 if (ConditionalAccess) {
6333 Error_NullShortCircuitInsideExpressionTree (ec);
6336 return CreateExpressionTree (ec, true);
6339 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6342 Expression instance;
6344 if (InstanceExpression == null) {
6345 instance = new NullLiteral (loc);
6346 } else if (convertInstance) {
6347 instance = InstanceExpression.CreateExpressionTree (ec);
6349 args = new Arguments (1);
6350 args.Add (new Argument (InstanceExpression));
6351 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6354 args = Arguments.CreateForExpressionTree (ec, null,
6356 CreateTypeOfExpression ());
6358 return CreateExpressionFactoryCall (ec, "Field", args);
6361 public Expression CreateTypeOfExpression ()
6363 return new TypeOfField (spec, loc);
6366 protected override Expression DoResolve (ResolveContext ec)
6368 spec.MemberDefinition.SetIsUsed ();
6370 return DoResolve (ec, null);
6373 Expression DoResolve (ResolveContext ec, Expression rhs)
6375 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6378 ResolveConditionalAccessReceiver (ec);
6380 if (ResolveInstanceExpression (ec, rhs)) {
6381 // Resolve the field's instance expression while flow analysis is turned
6382 // off: when accessing a field "a.b", we must check whether the field
6383 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6385 if (lvalue_instance) {
6386 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6388 Expression right_side =
6389 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6391 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6393 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6396 if (InstanceExpression == null)
6400 DoBestMemberChecks (ec, spec);
6402 if (conditional_access_receiver)
6403 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6406 var fb = spec as FixedFieldSpec;
6407 IVariableReference var = InstanceExpression as IVariableReference;
6410 IFixedExpression fe = InstanceExpression as IFixedExpression;
6411 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6412 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6415 if (InstanceExpression.eclass != ExprClass.Variable) {
6416 ec.Report.SymbolRelatedToPreviousError (spec);
6417 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6418 TypeManager.GetFullNameSignature (spec));
6419 } else if (var != null && var.IsHoisted) {
6420 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6423 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6427 // Set flow-analysis variable info for struct member access. It will be check later
6428 // for precise error reporting
6430 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6431 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6434 if (conditional_access_receiver)
6435 type = LiftMemberType (ec, type);
6437 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6438 return Constant.CreateConstantFromValue (type, null, loc);
6440 eclass = ExprClass.Variable;
6444 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6446 spec.CheckObsoleteness (rc, expr.Location);
6449 public void SetFieldAssigned (FlowAnalysisContext fc)
6454 bool lvalue_instance = spec.DeclaringType.IsStruct;
6455 if (lvalue_instance) {
6456 var var = InstanceExpression as IVariableReference;
6457 if (var != null && var.VariableInfo != null) {
6458 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6462 var fe = InstanceExpression as FieldExpr;
6464 Expression instance;
6467 instance = fe.InstanceExpression;
6468 var fe_instance = instance as FieldExpr;
6469 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6470 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6471 var var = InstanceExpression as IVariableReference;
6472 if (var != null && var.VariableInfo == null) {
6473 var var_inst = instance as IVariableReference;
6474 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6475 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6479 if (fe_instance != null) {
6488 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6489 instance.FlowAnalysis (fc);
6491 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6492 InstanceExpression.FlowAnalysis (fc);
6496 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6498 // The return value is always null. Returning a value simplifies calling code.
6500 if (right_side == EmptyExpression.OutAccess) {
6502 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6503 GetSignatureForError ());
6505 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6506 GetSignatureForError ());
6512 if (right_side == EmptyExpression.LValueMemberAccess) {
6513 // Already reported as CS1648/CS1650
6517 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6519 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6520 GetSignatureForError ());
6522 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6523 GetSignatureForError ());
6529 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6530 GetSignatureForError ());
6532 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6533 GetSignatureForError ());
6539 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6541 if (HasConditionalAccess ())
6542 Error_NullPropagatingLValue (ec);
6544 if (spec is FixedFieldSpec) {
6545 // It could be much better error message but we want to be error compatible
6546 Error_ValueAssignment (ec, right_side);
6549 Expression e = DoResolve (ec, right_side);
6554 spec.MemberDefinition.SetIsAssigned ();
6556 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6557 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6558 ec.Report.Warning (420, 1, loc,
6559 "`{0}': A volatile field references will not be treated as volatile",
6560 spec.GetSignatureForError ());
6563 if (spec.IsReadOnly) {
6564 // InitOnly fields can only be assigned in constructors or initializers
6565 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6566 return Error_AssignToReadonly (ec, right_side);
6568 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6570 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6571 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6572 return Error_AssignToReadonly (ec, right_side);
6573 // static InitOnly fields cannot be assigned-to in an instance constructor
6574 if (IsStatic && !ec.IsStatic)
6575 return Error_AssignToReadonly (ec, right_side);
6576 // instance constructors can't modify InitOnly fields of other instances of the same type
6577 if (!IsStatic && !(InstanceExpression is This))
6578 return Error_AssignToReadonly (ec, right_side);
6582 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6583 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6584 ec.Report.Warning (197, 1, loc,
6585 "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",
6586 GetSignatureForError ());
6589 eclass = ExprClass.Variable;
6593 public override void FlowAnalysis (FlowAnalysisContext fc)
6595 var var = InstanceExpression as IVariableReference;
6597 var vi = var.VariableInfo;
6598 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6599 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6603 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6604 var le = SkipLeftValueTypeAccess (InstanceExpression);
6606 le.FlowAnalysis (fc);
6612 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6614 base.FlowAnalysis (fc);
6616 if (conditional_access_receiver)
6617 fc.DefiniteAssignment = da;
6620 static Expression SkipLeftValueTypeAccess (Expression expr)
6622 if (!TypeSpec.IsValueType (expr.Type))
6625 if (expr is VariableReference)
6628 var fe = expr as FieldExpr;
6632 if (fe.InstanceExpression == null)
6635 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6638 public override int GetHashCode ()
6640 return spec.GetHashCode ();
6643 public bool IsFixed {
6646 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6648 IVariableReference variable = InstanceExpression as IVariableReference;
6649 if (variable != null)
6650 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6652 IFixedExpression fe = InstanceExpression as IFixedExpression;
6653 return fe != null && fe.IsFixed;
6657 public override bool Equals (object obj)
6659 FieldExpr fe = obj as FieldExpr;
6663 if (spec != fe.spec)
6666 if (InstanceExpression == null || fe.InstanceExpression == null)
6669 return InstanceExpression.Equals (fe.InstanceExpression);
6672 public void Emit (EmitContext ec, bool leave_copy)
6674 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6678 ec.Emit (OpCodes.Volatile);
6680 ec.Emit (OpCodes.Ldsfld, spec);
6682 var ca = ec.ConditionalAccess;
6685 if (conditional_access_receiver)
6686 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6688 EmitInstance (ec, false);
6691 // Optimization for build-in types
6692 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6693 ec.EmitLoadFromPtr (type);
6695 var ff = spec as FixedFieldSpec;
6697 ec.Emit (OpCodes.Ldflda, spec);
6698 ec.Emit (OpCodes.Ldflda, ff.Element);
6701 ec.Emit (OpCodes.Volatile);
6703 ec.Emit (OpCodes.Ldfld, spec);
6707 if (conditional_access_receiver) {
6708 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6709 ec.ConditionalAccess = ca;
6714 ec.Emit (OpCodes.Dup);
6716 temp = new LocalTemporary (this.Type);
6722 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6724 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6725 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6730 if (ConditionalAccess)
6731 throw new NotImplementedException ("null operator assignment");
6733 if (has_await_source)
6734 source = source.EmitToField (ec);
6736 EmitInstance (ec, prepared);
6741 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6742 ec.Emit (OpCodes.Dup);
6744 temp = new LocalTemporary (this.Type);
6749 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6750 ec.Emit (OpCodes.Volatile);
6752 spec.MemberDefinition.SetIsAssigned ();
6755 ec.Emit (OpCodes.Stsfld, spec);
6757 ec.Emit (OpCodes.Stfld, spec);
6759 if (ec.NotifyEvaluatorOnStore) {
6761 throw new NotImplementedException ("instance field write");
6764 ec.Emit (OpCodes.Dup);
6766 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6777 // Emits store to field with prepared values on stack
6779 public void EmitAssignFromStack (EmitContext ec)
6782 ec.Emit (OpCodes.Stsfld, spec);
6784 ec.Emit (OpCodes.Stfld, spec);
6788 public override void Emit (EmitContext ec)
6793 public override void EmitSideEffect (EmitContext ec)
6795 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6797 if (is_volatile) // || is_marshal_by_ref ())
6798 base.EmitSideEffect (ec);
6801 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6803 if ((mode & AddressOp.Store) != 0)
6804 spec.MemberDefinition.SetIsAssigned ();
6805 if ((mode & AddressOp.Load) != 0)
6806 spec.MemberDefinition.SetIsUsed ();
6809 // Handle initonly fields specially: make a copy and then
6810 // get the address of the copy.
6813 if (spec.IsReadOnly){
6815 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6827 var temp = ec.GetTemporaryLocal (type);
6828 ec.Emit (OpCodes.Stloc, temp);
6829 ec.Emit (OpCodes.Ldloca, temp);
6835 ec.Emit (OpCodes.Ldsflda, spec);
6838 EmitInstance (ec, false);
6839 ec.Emit (OpCodes.Ldflda, spec);
6843 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6845 return MakeExpression (ctx);
6848 public override SLE.Expression MakeExpression (BuilderContext ctx)
6851 return base.MakeExpression (ctx);
6853 return SLE.Expression.Field (
6854 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6855 spec.GetMetaInfo ());
6859 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6861 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6867 // Expression that evaluates to a Property.
6869 // This is not an LValue because we need to re-write the expression. We
6870 // can not take data from the stack and store it.
6872 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6874 Arguments arguments;
6875 FieldExpr backing_field;
6877 public PropertyExpr (PropertySpec spec, Location l)
6880 best_candidate = spec;
6881 type = spec.MemberType;
6886 protected override Arguments Arguments {
6895 protected override TypeSpec DeclaringType {
6897 return best_candidate.DeclaringType;
6901 public override string Name {
6903 return best_candidate.Name;
6907 public bool IsAutoPropertyAccess {
6909 var prop = best_candidate.MemberDefinition as Property;
6910 return prop != null && prop.BackingField != null;
6914 public override bool IsInstance {
6920 public override bool IsStatic {
6922 return best_candidate.IsStatic;
6926 public override string KindName {
6927 get { return "property"; }
6930 public PropertySpec PropertyInfo {
6932 return best_candidate;
6938 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6940 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6943 var args_count = arguments == null ? 0 : arguments.Count;
6944 if (args_count != body.Parameters.Count && args_count == 0)
6947 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6948 mg.InstanceExpression = InstanceExpression;
6953 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6955 return new PropertyExpr (spec, loc) {
6961 public override Expression CreateExpressionTree (ResolveContext ec)
6963 if (ConditionalAccess) {
6964 Error_NullShortCircuitInsideExpressionTree (ec);
6968 if (IsSingleDimensionalArrayLength ()) {
6969 args = new Arguments (1);
6970 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6971 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6974 args = new Arguments (2);
6975 if (InstanceExpression == null)
6976 args.Add (new Argument (new NullLiteral (loc)));
6978 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6979 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6980 return CreateExpressionFactoryCall (ec, "Property", args);
6983 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6985 DoResolveLValue (rc, null);
6986 return new TypeOfMethod (Setter, loc);
6989 public override string GetSignatureForError ()
6991 return best_candidate.GetSignatureForError ();
6994 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6997 return base.MakeExpression (ctx);
6999 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
7003 public override SLE.Expression MakeExpression (BuilderContext ctx)
7006 return base.MakeExpression (ctx);
7008 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
7012 void Error_PropertyNotValid (ResolveContext ec)
7014 ec.Report.SymbolRelatedToPreviousError (best_candidate);
7015 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
7016 GetSignatureForError ());
7019 bool IsSingleDimensionalArrayLength ()
7021 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7024 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7025 return ac != null && ac.Rank == 1;
7028 public override void Emit (EmitContext ec, bool leave_copy)
7031 // Special case: length of single dimension array property is turned into ldlen
7033 if (IsSingleDimensionalArrayLength ()) {
7034 if (conditional_access_receiver) {
7035 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7038 EmitInstance (ec, false);
7040 ec.Emit (OpCodes.Ldlen);
7041 ec.Emit (OpCodes.Conv_I4);
7043 if (conditional_access_receiver) {
7044 ec.CloseConditionalAccess (type);
7050 base.Emit (ec, leave_copy);
7053 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7055 if (backing_field != null) {
7056 backing_field.EmitAssign (ec, source, leave_copy, false);
7061 LocalTemporary await_source_arg = null;
7063 if (isCompound && !(source is DynamicExpressionStatement)) {
7064 emitting_compound_assignment = true;
7067 if (has_await_arguments) {
7068 await_source_arg = new LocalTemporary (Type);
7069 await_source_arg.Store (ec);
7071 args = new Arguments (1);
7072 args.Add (new Argument (await_source_arg));
7075 temp = await_source_arg;
7078 has_await_arguments = false;
7083 ec.Emit (OpCodes.Dup);
7084 temp = new LocalTemporary (this.Type);
7089 args = arguments ?? new Arguments (1);
7093 temp = new LocalTemporary (this.Type);
7095 args.Add (new Argument (temp));
7097 args.Add (new Argument (source));
7101 emitting_compound_assignment = false;
7103 var call = new CallEmitter ();
7104 call.InstanceExpression = InstanceExpression;
7106 call.InstanceExpressionOnStack = true;
7108 if (ConditionalAccess) {
7109 call.ConditionalAccess = true;
7113 call.Emit (ec, Setter, args, loc);
7115 call.EmitStatement (ec, Setter, args, loc);
7122 if (await_source_arg != null) {
7123 await_source_arg.Release (ec);
7127 public override void FlowAnalysis (FlowAnalysisContext fc)
7129 var prop = best_candidate.MemberDefinition as Property;
7130 if (prop != null && prop.BackingField != null) {
7131 var var = InstanceExpression as IVariableReference;
7133 var vi = var.VariableInfo;
7134 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7135 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7139 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7144 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7146 base.FlowAnalysis (fc);
7148 if (conditional_access_receiver)
7149 fc.DefiniteAssignment = da;
7152 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7154 eclass = ExprClass.PropertyAccess;
7156 if (best_candidate.IsNotCSharpCompatible) {
7157 Error_PropertyNotValid (rc);
7160 ResolveInstanceExpression (rc, right_side);
7162 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7163 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7164 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7166 type = p.MemberType;
7170 DoBestMemberChecks (rc, best_candidate);
7172 // Handling of com-imported properties with any number of default property parameters
7173 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7174 var p = best_candidate.Get.Parameters;
7175 arguments = new Arguments (p.Count);
7176 for (int i = 0; i < p.Count; ++i) {
7177 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7179 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7180 var p = best_candidate.Set.Parameters;
7181 arguments = new Arguments (p.Count - 1);
7182 for (int i = 0; i < p.Count - 1; ++i) {
7183 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7190 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7192 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7195 var prop = best_candidate.MemberDefinition as Property;
7196 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7197 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7201 prop = (Property)ps.MemberDefinition;
7204 var spec = prop.BackingField;
7208 if (rc.IsStatic != spec.IsStatic)
7211 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7214 backing_field = new FieldExpr (prop.BackingField, loc);
7215 backing_field.ResolveLValue (rc, rhs);
7219 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7221 if (!best_candidate.IsAccessible (rc))
7222 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7224 best_candidate.CheckObsoleteness (rc, expr.Location);
7227 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7229 if (backing_field != null) {
7230 backing_field.SetFieldAssigned (fc);
7234 if (!IsAutoPropertyAccess)
7237 var prop = best_candidate.MemberDefinition as Property;
7238 if (prop != null && prop.BackingField != null) {
7239 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7240 if (lvalue_instance) {
7241 var var = InstanceExpression as IVariableReference;
7242 if (var != null && var.VariableInfo != null) {
7243 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7249 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7251 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7255 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7257 // getter and setter can be different for base calls
7258 MethodSpec getter, setter;
7259 protected T best_candidate;
7261 protected LocalTemporary temp;
7262 protected bool emitting_compound_assignment;
7263 protected bool has_await_arguments;
7265 protected PropertyOrIndexerExpr (Location l)
7272 protected abstract Arguments Arguments { get; set; }
7274 public MethodSpec Getter {
7283 public MethodSpec Setter {
7294 protected override Expression DoResolve (ResolveContext ec)
7296 if (eclass == ExprClass.Unresolved) {
7297 ResolveConditionalAccessReceiver (ec);
7299 var expr = OverloadResolve (ec, null);
7304 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7305 return expr.Resolve (ec);
7308 if (conditional_access_receiver) {
7309 type = LiftMemberType (ec, type);
7313 if (!ResolveGetter (ec))
7319 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7321 if (HasConditionalAccess ())
7322 Error_NullPropagatingLValue (rc);
7324 if (right_side == EmptyExpression.OutAccess) {
7325 // TODO: best_candidate can be null at this point
7326 INamedBlockVariable variable = null;
7327 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7328 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7329 best_candidate.Name);
7331 right_side.DoResolveLValue (rc, this);
7336 if (eclass == ExprClass.Unresolved) {
7337 var expr = OverloadResolve (rc, right_side);
7342 return expr.ResolveLValue (rc, right_side);
7344 ResolveInstanceExpression (rc, right_side);
7347 if (!best_candidate.HasSet) {
7348 if (ResolveAutopropertyAssignment (rc, right_side))
7351 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7352 GetSignatureForError ());
7356 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7357 if (best_candidate.HasDifferentAccessibility) {
7358 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7359 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7360 GetSignatureForError ());
7362 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7363 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7367 if (best_candidate.HasDifferentAccessibility)
7368 CheckProtectedMemberAccess (rc, best_candidate.Set);
7370 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7374 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7376 var ca = ec.ConditionalAccess;
7377 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7379 call.Emit (ec, method, arguments, loc);
7381 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7382 ec.ConditionalAccess = ca;
7386 // Implements the IAssignMethod interface for assignments
7388 public virtual void Emit (EmitContext ec, bool leave_copy)
7390 var call = new CallEmitter ();
7391 call.ConditionalAccess = ConditionalAccess;
7392 call.InstanceExpression = InstanceExpression;
7393 if (has_await_arguments)
7394 call.HasAwaitArguments = true;
7396 call.DuplicateArguments = emitting_compound_assignment;
7398 if (conditional_access_receiver)
7399 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7401 call.Emit (ec, Getter, Arguments, loc);
7403 if (call.HasAwaitArguments) {
7404 InstanceExpression = call.InstanceExpression;
7405 Arguments = call.EmittedArguments;
7406 has_await_arguments = true;
7410 ec.Emit (OpCodes.Dup);
7411 temp = new LocalTemporary (Type);
7416 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7418 public override void Emit (EmitContext ec)
7423 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7425 has_await_arguments = true;
7430 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7432 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7434 bool ResolveGetter (ResolveContext rc)
7436 if (!best_candidate.HasGet) {
7437 if (InstanceExpression != EmptyExpression.Null) {
7438 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7439 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7440 best_candidate.GetSignatureForError ());
7443 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7444 if (best_candidate.HasDifferentAccessibility) {
7445 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7446 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7447 TypeManager.CSharpSignature (best_candidate));
7449 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7450 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7454 if (best_candidate.HasDifferentAccessibility) {
7455 CheckProtectedMemberAccess (rc, best_candidate.Get);
7458 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7462 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7469 /// Fully resolved expression that evaluates to an Event
7471 public class EventExpr : MemberExpr, IAssignMethod
7473 readonly EventSpec spec;
7476 public EventExpr (EventSpec spec, Location loc)
7484 protected override TypeSpec DeclaringType {
7486 return spec.DeclaringType;
7490 public override string Name {
7496 public override bool IsInstance {
7498 return !spec.IsStatic;
7502 public override bool IsStatic {
7504 return spec.IsStatic;
7508 public override string KindName {
7509 get { return "event"; }
7512 public MethodSpec Operator {
7520 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7523 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7525 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7526 if (spec.BackingField != null &&
7527 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7529 spec.MemberDefinition.SetIsUsed ();
7531 spec.CheckObsoleteness (ec, loc);
7533 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7534 Error_AssignmentEventOnly (ec);
7536 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7538 InstanceExpression = null;
7540 return ml.ResolveMemberAccess (ec, left, original);
7544 return base.ResolveMemberAccess (ec, left, original);
7547 public override Expression CreateExpressionTree (ResolveContext ec)
7549 throw new NotSupportedException ("ET");
7552 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7554 if (right_side == EmptyExpression.EventAddition) {
7555 op = spec.AccessorAdd;
7556 } else if (right_side == EmptyExpression.EventSubtraction) {
7557 op = spec.AccessorRemove;
7561 Error_AssignmentEventOnly (ec);
7565 if (HasConditionalAccess ())
7566 Error_NullPropagatingLValue (ec);
7568 op = CandidateToBaseOverride (ec, op);
7572 protected override Expression DoResolve (ResolveContext ec)
7574 eclass = ExprClass.EventAccess;
7575 type = spec.MemberType;
7577 ResolveInstanceExpression (ec, null);
7579 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7580 Error_AssignmentEventOnly (ec);
7583 DoBestMemberChecks (ec, spec);
7587 public override void Emit (EmitContext ec)
7589 throw new NotSupportedException ();
7590 //Error_CannotAssign ();
7593 #region IAssignMethod Members
7595 public void Emit (EmitContext ec, bool leave_copy)
7597 throw new NotImplementedException ();
7600 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7602 if (leave_copy || !isCompound)
7603 throw new NotImplementedException ("EventExpr::EmitAssign");
7605 Arguments args = new Arguments (1);
7606 args.Add (new Argument (source));
7608 // TODO: Wrong, needs receiver
7609 // if (NullShortCircuit) {
7610 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7613 var call = new CallEmitter ();
7614 call.InstanceExpression = InstanceExpression;
7615 call.ConditionalAccess = ConditionalAccess;
7616 call.EmitStatement (ec, op, args, loc);
7618 // if (NullShortCircuit)
7619 // ec.CloseConditionalAccess (null);
7624 void Error_AssignmentEventOnly (ResolveContext ec)
7626 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7627 ec.Report.Error (79, loc,
7628 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7629 GetSignatureForError ());
7631 ec.Report.Error (70, loc,
7632 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7633 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7637 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7639 name = name.Substring (0, name.LastIndexOf ('.'));
7640 base.Error_CannotCallAbstractBase (rc, name);
7643 public override string GetSignatureForError ()
7645 return TypeManager.CSharpSignature (spec);
7648 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7650 spec.CheckObsoleteness (rc, expr.Location);
7653 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7655 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7659 public class TemporaryVariableReference : VariableReference
7661 public class Declarator : Statement
7663 TemporaryVariableReference variable;
7665 public Declarator (TemporaryVariableReference variable)
7667 this.variable = variable;
7671 protected override void DoEmit (EmitContext ec)
7673 variable.li.CreateBuilder (ec);
7676 public override void Emit (EmitContext ec)
7678 // Don't create sequence point
7682 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7687 protected override void CloneTo (CloneContext clonectx, Statement target)
7695 public TemporaryVariableReference (LocalVariable li, Location loc)
7698 this.type = li.Type;
7702 public override bool IsLockedByStatement {
7710 public LocalVariable LocalInfo {
7716 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7718 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7719 return new TemporaryVariableReference (li, loc);
7722 protected override Expression DoResolve (ResolveContext ec)
7724 eclass = ExprClass.Variable;
7727 // Don't capture temporary variables except when using
7728 // state machine redirection and block yields
7730 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7731 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7732 ec.IsVariableCapturingRequired) {
7733 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7734 storey.CaptureLocalVariable (ec, li);
7740 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7742 return Resolve (ec);
7745 public override void Emit (EmitContext ec)
7747 li.CreateBuilder (ec);
7752 public void EmitAssign (EmitContext ec, Expression source)
7754 li.CreateBuilder (ec);
7756 EmitAssign (ec, source, false, false);
7759 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7761 return li.HoistedVariant;
7764 public override bool IsFixed {
7765 get { return true; }
7768 public override bool IsRef {
7769 get { return false; }
7772 public override string Name {
7773 get { throw new NotImplementedException (); }
7776 public override void SetHasAddressTaken ()
7778 throw new NotImplementedException ();
7781 protected override ILocalVariable Variable {
7785 public override VariableInfo VariableInfo {
7786 get { return null; }
7791 /// Handles `var' contextual keyword; var becomes a keyword only
7792 /// if no type called var exists in a variable scope
7794 class VarExpr : SimpleName
7796 public VarExpr (Location loc)
7801 public bool InferType (ResolveContext ec, Expression right_side)
7804 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7806 type = right_side.Type;
7807 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7808 ec.Report.Error (815, loc,
7809 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7810 type.GetSignatureForError ());
7811 type = InternalType.ErrorType;
7815 eclass = ExprClass.Variable;
7819 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7821 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7822 base.Error_TypeOrNamespaceNotFound (ec);
7824 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");