2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression
131 public ExprClass eclass;
132 protected TypeSpec type;
133 protected Location loc;
135 public TypeSpec Type {
137 set { type = value; }
140 public virtual bool IsSideEffectFree {
146 public Location Location {
150 public virtual bool IsNull {
157 // Used to workaround parser limitation where we cannot get
158 // start of statement expression location
160 public virtual Location StartLocation {
166 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
169 // Return method-group expression when the expression can be used as
170 // lambda replacement. A good example is array sorting where instead of
173 // Array.Sort (s, (a, b) => String.Compare (a, b));
175 // we can use method group directly
177 // Array.Sort (s, String.Compare);
179 // Correct overload will be used because we do the reduction after
180 // best candidate was found.
186 // Returns true when the expression during Emit phase breaks stack
187 // by using await expression
189 public virtual bool ContainsEmitWithAwait ()
195 /// Performs semantic analysis on the Expression
199 /// The Resolve method is invoked to perform the semantic analysis
202 /// The return value is an expression (it can be the
203 /// same expression in some cases) or a new
204 /// expression that better represents this node.
206 /// For example, optimizations of Unary (LiteralInt)
207 /// would return a new LiteralInt with a negated
210 /// If there is an error during semantic analysis,
211 /// then an error should be reported (using Report)
212 /// and a null value should be returned.
214 /// There are two side effects expected from calling
215 /// Resolve(): the the field variable "eclass" should
216 /// be set to any value of the enumeration
217 /// `ExprClass' and the type variable should be set
218 /// to a valid type (this is the type of the
221 protected abstract Expression DoResolve (ResolveContext rc);
223 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
229 // This is used if the expression should be resolved as a type or namespace name.
230 // the default implementation fails.
232 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
234 var rc = mc as ResolveContext ?? new ResolveContext (mc);
235 Expression e = Resolve (rc);
237 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
242 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
244 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
247 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
249 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
252 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
254 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
255 name, type.GetSignatureForError ());
258 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
260 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
263 public void Error_InvalidExpressionStatement (BlockContext bc)
265 Error_InvalidExpressionStatement (bc.Report, loc);
268 public void Error_InvalidExpressionStatement (Report report)
270 Error_InvalidExpressionStatement (report, loc);
273 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
275 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
278 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
280 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
283 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
285 // The error was already reported as CS1660
286 if (type == InternalType.AnonymousMethod)
289 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
292 if (type.MemberDefinition.DeclaringAssembly.IsMissing ||
293 target.MemberDefinition.DeclaringAssembly.IsMissing)
296 string from_type = type.GetSignatureForError ();
297 string to_type = target.GetSignatureForError ();
298 if (from_type == to_type) {
299 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
300 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
304 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
309 ec.Report.DisableReporting ();
310 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
311 ec.Report.EnableReporting ();
314 ec.Report.Error (266, loc,
315 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
318 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
323 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
325 // Better message for possible generic expressions
326 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
327 var report = context.Module.Compiler.Report;
328 report.SymbolRelatedToPreviousError (member);
329 if (member is TypeSpec)
330 member = ((TypeSpec) member).GetDefinition ();
332 member = ((MethodSpec) member).GetGenericMethodDefinition ();
334 string name = member.Kind == MemberKind.Method ? "method" : "type";
335 if (member.IsGeneric) {
336 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
337 name, member.GetSignatureForError (), member.Arity.ToString ());
339 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
340 name, member.GetSignatureForError ());
343 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
347 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
349 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
353 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
355 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
358 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
360 ec.Report.SymbolRelatedToPreviousError (type);
361 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
362 type.GetSignatureForError (), name);
365 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
367 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
368 // Already reported as CS1612
369 } else if (rhs == EmptyExpression.OutAccess) {
370 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
372 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
376 protected void Error_VoidPointerOperation (ResolveContext rc)
378 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
381 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
383 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
386 public ResolveFlags ExprClassToResolveFlags {
390 case ExprClass.Namespace:
391 return ResolveFlags.Type;
393 case ExprClass.MethodGroup:
394 return ResolveFlags.MethodGroup;
396 case ExprClass.TypeParameter:
397 return ResolveFlags.TypeParameter;
399 case ExprClass.Value:
400 case ExprClass.Variable:
401 case ExprClass.PropertyAccess:
402 case ExprClass.EventAccess:
403 case ExprClass.IndexerAccess:
404 return ResolveFlags.VariableOrValue;
407 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
413 // Implements identical simple name and type-name resolution
415 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
418 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
421 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
422 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
424 if (left is MemberExpr || left is VariableReference) {
425 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
426 if (identical_type != null && identical_type.Type == left.Type)
427 return identical_type;
433 public virtual string GetSignatureForError ()
435 return type.GetDefinition ().GetSignatureForError ();
438 public static bool IsNeverNull (Expression expr)
440 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
443 var c = expr as Constant;
447 var tc = expr as TypeCast;
449 return IsNeverNull (tc.Child);
454 protected static bool IsNullPropagatingValid (TypeSpec type)
457 case MemberKind.Struct:
458 return type.IsNullableType;
459 case MemberKind.Enum:
460 case MemberKind.Void:
461 case MemberKind.PointerType:
463 case MemberKind.InternalCompilerType:
464 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
465 case MemberKind.TypeParameter:
466 return !((TypeParameterSpec) type).IsValueType;
472 public virtual bool HasConditionalAccess ()
477 protected TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
479 var tps = type as TypeParameterSpec;
480 if (tps != null && !(tps.IsReferenceType || tps.IsValueType)) {
481 Error_OperatorCannotBeApplied (rc, loc, "?", type);
484 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
485 Nullable.NullableInfo.MakeType (rc.Module, type) :
490 /// Resolves an expression and performs semantic analysis on it.
494 /// Currently Resolve wraps DoResolve to perform sanity
495 /// checking and assertion checking on what we expect from Resolve.
497 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
499 if (eclass != ExprClass.Unresolved) {
500 if ((flags & ExprClassToResolveFlags) == 0) {
501 Error_UnexpectedKind (ec, flags, loc);
515 if ((flags & e.ExprClassToResolveFlags) == 0) {
516 e.Error_UnexpectedKind (ec, flags, loc);
521 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
524 } catch (Exception ex) {
525 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
526 ec.Report.Printer is NullReportPrinter)
529 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
530 return ErrorExpression.Instance; // TODO: Add location
535 /// Resolves an expression and performs semantic analysis on it.
537 public Expression Resolve (ResolveContext rc)
539 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
543 /// Resolves an expression for LValue assignment
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
550 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
552 int errors = ec.Report.Errors;
553 bool out_access = right_side == EmptyExpression.OutAccess;
555 Expression e = DoResolveLValue (ec, right_side);
557 if (e != null && out_access && !(e is IMemoryLocation)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
567 if (errors == ec.Report.Errors) {
568 Error_ValueAssignment (ec, right_side);
573 if (e.eclass == ExprClass.Unresolved)
574 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
576 if ((e.type == null) && !(e is GenericTypeExpr))
577 throw new Exception ("Expression " + e + " did not set its type after Resolve");
582 public Constant ResolveLabelConstant (ResolveContext rc)
584 var expr = Resolve (rc);
588 Constant c = expr as Constant;
590 if (expr.type != InternalType.ErrorType)
591 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
599 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
601 if (Attribute.IsValidArgumentType (parameterType)) {
602 rc.Module.Compiler.Report.Error (182, loc,
603 "An attribute argument must be a constant expression, typeof expression or array creation expression");
605 rc.Module.Compiler.Report.Error (181, loc,
606 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
607 targetType.GetSignatureForError ());
612 /// Emits the code for the expression
616 /// The Emit method is invoked to generate the code
617 /// for the expression.
619 public abstract void Emit (EmitContext ec);
622 // Emit code to branch to @target if this expression is equivalent to @on_true.
623 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
624 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
625 // including the use of conditional branches. Note also that a branch MUST be emitted
626 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
629 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
632 // Emit this expression for its side effects, not for its value.
633 // The default implementation is to emit the value, and then throw it away.
634 // Subclasses can provide more efficient implementations, but those MUST be equivalent
635 public virtual void EmitSideEffect (EmitContext ec)
638 ec.Emit (OpCodes.Pop);
642 // Emits the expression into temporary field variable. The method
643 // should be used for await expressions only
645 public virtual Expression EmitToField (EmitContext ec)
648 // This is the await prepare Emit method. When emitting code like
649 // a + b we emit code like
655 // For await a + await b we have to interfere the flow to keep the
656 // stack clean because await yields from the expression. The emit
659 // a = a.EmitToField () // a is changed to temporary field access
660 // b = b.EmitToField ()
666 // The idea is to emit expression and leave the stack empty with
667 // result value still available.
669 // Expressions should override this default implementation when
670 // optimized version can be provided (e.g. FieldExpr)
673 // We can optimize for side-effect free expressions, they can be
674 // emitted out of order
676 if (IsSideEffectFree)
679 bool needs_temporary = ContainsEmitWithAwait ();
680 if (!needs_temporary)
683 // Emit original code
684 var field = EmitToFieldSource (ec);
687 // Store the result to temporary field when we
688 // cannot load `this' directly
690 field = ec.GetTemporaryField (type);
691 if (needs_temporary) {
693 // Create temporary local (we cannot load `this' before Emit)
695 var temp = ec.GetTemporaryLocal (type);
696 ec.Emit (OpCodes.Stloc, temp);
699 ec.Emit (OpCodes.Ldloc, temp);
700 field.EmitAssignFromStack (ec);
702 ec.FreeTemporaryLocal (temp, type);
704 field.EmitAssignFromStack (ec);
711 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
714 // Default implementation calls Emit method
720 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
722 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
723 bool contains_await = false;
725 for (int i = 1; i < expressions.Count; ++i) {
726 if (expressions[i].ContainsEmitWithAwait ()) {
727 contains_await = true;
732 if (contains_await) {
733 for (int i = 0; i < expressions.Count; ++i) {
734 expressions[i] = expressions[i].EmitToField (ec);
739 for (int i = 0; i < expressions.Count; ++i) {
740 expressions[i].Emit (ec);
745 /// Protected constructor. Only derivate types should
746 /// be able to be created
749 protected Expression ()
754 /// Returns a fully formed expression after a MemberLookup
757 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
759 if (spec is EventSpec)
760 return new EventExpr ((EventSpec) spec, loc);
761 if (spec is ConstSpec)
762 return new ConstantExpr ((ConstSpec) spec, loc);
763 if (spec is FieldSpec)
764 return new FieldExpr ((FieldSpec) spec, loc);
765 if (spec is PropertySpec)
766 return new PropertyExpr ((PropertySpec) spec, loc);
767 if (spec is TypeSpec)
768 return new TypeExpression (((TypeSpec) spec), loc);
773 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
775 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
778 case MemberKind.Struct:
779 // Every struct has implicit default constructor if not provided by user
783 rc.Report.SymbolRelatedToPreviousError (type);
784 // Report meaningful error for struct as they always have default ctor in C# context
785 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
787 case MemberKind.MissingType:
788 case MemberKind.InternalCompilerType:
789 // LAMESPEC: dynamic is not really object
790 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
794 rc.Report.SymbolRelatedToPreviousError (type);
795 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
796 type.GetSignatureForError ());
803 if (args == null && type.IsStruct) {
804 bool includes_empty = false;
805 foreach (MethodSpec ctor in ctors) {
806 if (ctor.Parameters.IsEmpty) {
807 includes_empty = true;
815 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
816 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
817 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
820 return r.ResolveMember<MethodSpec> (rc, ref args);
824 public enum MemberLookupRestrictions
830 EmptyArguments = 1 << 4,
831 IgnoreArity = 1 << 5,
832 IgnoreAmbiguity = 1 << 6,
833 NameOfExcluded = 1 << 7,
834 DontSetConditionalAccess = 1 << 8
838 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
839 // `qualifier_type' or null to lookup members in the current class.
841 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
843 var members = MemberCache.FindMembers (queried_type, name, false);
845 if (members != null) {
848 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
852 if (members [0].DeclaringType.BaseType == null)
855 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
856 } while (members != null);
859 var tps = queried_type as TypeParameterSpec;
861 members = MemberCache.FindInterfaceMembers (tps, name);
863 return MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
869 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
871 MemberSpec non_method = null;
872 MemberSpec ambig_non_method = null;
874 for (int i = 0; i < members.Count; ++i) {
875 var member = members [i];
877 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
878 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
881 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
884 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
888 if (!member.IsAccessible (rc))
892 // With runtime binder we can have a situation where queried type is inaccessible
893 // because it came via dynamic object, the check about inconsisted accessibility
894 // had no effect as the type was unknown during compilation
897 // private class N { }
899 // public dynamic Foo ()
905 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
909 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
910 if (member is MethodSpec) {
911 return new MethodGroupExpr (members, queried_type, loc);
914 if (!Invocation.IsMemberInvocable (member))
918 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
920 } else if (!errorMode && !member.IsNotCSharpCompatible) {
922 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
923 // T has both an effective base class other than object and a non-empty effective interface set.
925 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
927 var tps = queried_type as TypeParameterSpec;
928 if (tps != null && tps.HasTypeConstraint) {
929 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
932 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
938 ambig_non_method = member;
942 if (non_method != null) {
943 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
944 var report = rc.Module.Compiler.Report;
945 report.SymbolRelatedToPreviousError (non_method);
946 report.SymbolRelatedToPreviousError (ambig_non_method);
947 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
948 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
951 if (non_method is MethodSpec)
952 return new MethodGroupExpr (members, queried_type, loc);
954 return ExprClassFromMemberInfo (non_method, loc);
960 protected static void Error_NamedArgument (NamedArgument na, Report Report)
962 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
965 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
967 throw new NotImplementedException ();
970 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
972 if (t == InternalType.ErrorType)
975 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
976 oper, t.GetSignatureForError ());
979 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
981 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
984 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
986 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
989 protected void Error_NullPropagatingLValue (ResolveContext rc)
991 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
994 public virtual void FlowAnalysis (FlowAnalysisContext fc)
998 public virtual Reachability MarkReachable (Reachability rc)
1004 // Special version of flow analysis for expressions which can return different
1005 // on-true and on-false result. Used by &&, ||, ?: expressions
1007 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1010 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1014 /// Returns an expression that can be used to invoke operator true
1015 /// on the expression if it exists.
1017 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1019 return GetOperatorTrueOrFalse (ec, e, true, loc);
1023 /// Returns an expression that can be used to invoke operator false
1024 /// on the expression if it exists.
1026 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1028 return GetOperatorTrueOrFalse (ec, e, false, loc);
1031 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1033 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1035 if (type.IsNullableType)
1036 type = Nullable.NullableInfo.GetUnderlyingType (type);
1038 var methods = MemberCache.GetUserOperator (type, op, false);
1039 if (methods == null)
1042 Arguments arguments = new Arguments (1);
1043 arguments.Add (new Argument (e));
1045 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1046 var oper = res.ResolveOperator (ec, ref arguments);
1051 return new UserOperatorCall (oper, arguments, null, loc);
1054 public virtual string ExprClassName
1058 case ExprClass.Unresolved:
1059 return "Unresolved";
1060 case ExprClass.Value:
1062 case ExprClass.Variable:
1064 case ExprClass.Namespace:
1066 case ExprClass.Type:
1068 case ExprClass.MethodGroup:
1069 return "method group";
1070 case ExprClass.PropertyAccess:
1071 return "property access";
1072 case ExprClass.EventAccess:
1073 return "event access";
1074 case ExprClass.IndexerAccess:
1075 return "indexer access";
1076 case ExprClass.Nothing:
1078 case ExprClass.TypeParameter:
1079 return "type parameter";
1081 throw new Exception ("Should not happen");
1086 /// Reports that we were expecting `expr' to be of class `expected'
1088 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1090 var name = memberExpr.GetSignatureForError ();
1092 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1095 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1097 string [] valid = new string [4];
1100 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1101 valid [count++] = "variable";
1102 valid [count++] = "value";
1105 if ((flags & ResolveFlags.Type) != 0)
1106 valid [count++] = "type";
1108 if ((flags & ResolveFlags.MethodGroup) != 0)
1109 valid [count++] = "method group";
1112 valid [count++] = "unknown";
1114 StringBuilder sb = new StringBuilder (valid [0]);
1115 for (int i = 1; i < count - 1; i++) {
1117 sb.Append (valid [i]);
1120 sb.Append ("' or `");
1121 sb.Append (valid [count - 1]);
1124 ec.Report.Error (119, loc,
1125 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1128 public static void UnsafeError (ResolveContext ec, Location loc)
1130 UnsafeError (ec.Report, loc);
1133 public static void UnsafeError (Report Report, Location loc)
1135 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1138 public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
1140 UnsafeInsideIteratorError (rc.Report, loc);
1143 public static void UnsafeInsideIteratorError (Report report, Location loc)
1145 report.Error (1629, loc, "Unsafe code may not appear in iterators");
1149 // Converts `source' to an int, uint, long or ulong.
1151 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1153 var btypes = ec.BuiltinTypes;
1155 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1156 Arguments args = new Arguments (1);
1157 args.Add (new Argument (source));
1158 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1161 Expression converted;
1163 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1164 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1165 if (converted == null)
1166 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1167 if (converted == null)
1168 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1169 if (converted == null)
1170 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1172 if (converted == null) {
1173 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1182 // Only positive constants are allowed at compile time
1184 Constant c = converted as Constant;
1185 if (c != null && c.IsNegative)
1186 Error_NegativeArrayIndex (ec, source.loc);
1188 // No conversion needed to array index
1189 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1192 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1195 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1197 if (args.Count != 1){
1198 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1203 if (arg is NamedArgument)
1204 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1206 var index = arg.Expr.Resolve (rc);
1210 index = ConvertExpressionToArrayIndex (rc, index, true);
1212 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1213 return new Indirection (p, loc);
1217 // Derived classes implement this method by cloning the fields that
1218 // could become altered during the Resolve stage
1220 // Only expressions that are created for the parser need to implement
1223 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1225 throw new NotImplementedException (
1227 "CloneTo not implemented for expression {0}", this.GetType ()));
1231 // Clones an expression created by the parser.
1233 // We only support expressions created by the parser so far, not
1234 // expressions that have been resolved (many more classes would need
1235 // to implement CloneTo).
1237 // This infrastructure is here merely for Lambda expressions which
1238 // compile the same code using different type values for the same
1239 // arguments to find the correct overload
1241 public virtual Expression Clone (CloneContext clonectx)
1243 Expression cloned = (Expression) MemberwiseClone ();
1244 CloneTo (clonectx, cloned);
1250 // Implementation of expression to expression tree conversion
1252 public abstract Expression CreateExpressionTree (ResolveContext ec);
1254 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1256 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1259 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1261 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1264 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1266 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1269 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1271 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1275 return new TypeExpression (t, loc);
1279 // Implemented by all expressions which support conversion from
1280 // compiler expression to invokable runtime expression. Used by
1281 // dynamic C# binder.
1283 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1285 throw new NotImplementedException ("MakeExpression for " + GetType ());
1288 public virtual object Accept (StructuralVisitor visitor)
1290 return visitor.Visit (this);
1295 /// This is just a base class for expressions that can
1296 /// appear on statements (invocations, object creation,
1297 /// assignments, post/pre increment and decrement). The idea
1298 /// being that they would support an extra Emition interface that
1299 /// does not leave a result on the stack.
1301 public abstract class ExpressionStatement : Expression
1303 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1305 Expression e = Resolve (ec);
1309 ExpressionStatement es = e as ExpressionStatement;
1310 if (es == null || e is AnonymousMethodBody) {
1311 var reduced = e as IReducedExpressionStatement;
1312 if (reduced != null) {
1313 return EmptyExpressionStatement.Instance;
1316 Error_InvalidExpressionStatement (ec);
1320 // This is quite expensive warning, try to limit the damage
1322 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1323 WarningAsyncWithoutWait (ec, e);
1329 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1331 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1332 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1337 // Need to do full resolve because GetAwaiter can be extension method
1338 // available only in this context
1340 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1344 var arguments = new Arguments (0);
1345 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1350 // Use same check rules as for real await
1352 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1353 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1356 bc.Report.Warning (4014, 1, e.Location,
1357 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1361 var inv = e as Invocation;
1362 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1363 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1364 bc.Report.Warning (4014, 1, e.Location,
1365 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1371 /// Requests the expression to be emitted in a `statement'
1372 /// context. This means that no new value is left on the
1373 /// stack after invoking this method (constrasted with
1374 /// Emit that will always leave a value on the stack).
1376 public abstract void EmitStatement (EmitContext ec);
1378 public override void EmitSideEffect (EmitContext ec)
1384 interface IReducedExpressionStatement
1389 /// This kind of cast is used to encapsulate the child
1390 /// whose type is child.Type into an expression that is
1391 /// reported to return "return_type". This is used to encapsulate
1392 /// expressions which have compatible types, but need to be dealt
1393 /// at higher levels with.
1395 /// For example, a "byte" expression could be encapsulated in one
1396 /// of these as an "unsigned int". The type for the expression
1397 /// would be "unsigned int".
1400 public abstract class TypeCast : Expression
1402 protected readonly Expression child;
1404 protected TypeCast (Expression child, TypeSpec return_type)
1406 eclass = child.eclass;
1407 loc = child.Location;
1412 public Expression Child {
1418 public override bool ContainsEmitWithAwait ()
1420 return child.ContainsEmitWithAwait ();
1423 public override Expression CreateExpressionTree (ResolveContext ec)
1425 Arguments args = new Arguments (2);
1426 args.Add (new Argument (child.CreateExpressionTree (ec)));
1427 args.Add (new Argument (new TypeOf (type, loc)));
1429 if (type.IsPointer || child.Type.IsPointer)
1430 Error_PointerInsideExpressionTree (ec);
1432 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1435 protected override Expression DoResolve (ResolveContext ec)
1437 // This should never be invoked, we are born in fully
1438 // initialized state.
1443 public override void Emit (EmitContext ec)
1448 public override void FlowAnalysis (FlowAnalysisContext fc)
1450 child.FlowAnalysis (fc);
1453 public override SLE.Expression MakeExpression (BuilderContext ctx)
1456 return base.MakeExpression (ctx);
1458 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1459 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1460 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1464 public override Reachability MarkReachable (Reachability rc)
1466 return child.MarkReachable (rc);
1469 protected override void CloneTo (CloneContext clonectx, Expression t)
1474 public override bool IsNull {
1475 get { return child.IsNull; }
1479 public class EmptyCast : TypeCast {
1480 EmptyCast (Expression child, TypeSpec target_type)
1481 : base (child, target_type)
1485 public static Expression Create (Expression child, TypeSpec type)
1487 Constant c = child as Constant;
1489 var enum_constant = c as EnumConstant;
1490 if (enum_constant != null)
1491 c = enum_constant.Child;
1493 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1497 var res = c.ConvertImplicitly (type);
1503 EmptyCast e = child as EmptyCast;
1505 return new EmptyCast (e.child, type);
1507 return new EmptyCast (child, type);
1510 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1512 child.EmitBranchable (ec, label, on_true);
1515 public override void EmitSideEffect (EmitContext ec)
1517 child.EmitSideEffect (ec);
1522 // Used for predefined type user operator (no obsolete check, etc.)
1524 public class OperatorCast : TypeCast
1526 readonly MethodSpec conversion_operator;
1528 public OperatorCast (Expression expr, TypeSpec target_type)
1529 : this (expr, target_type, target_type, false)
1533 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1534 : this (expr, target_type, target_type, find_explicit)
1538 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1539 : base (expr, returnType)
1541 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1542 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1545 foreach (MethodSpec oper in mi) {
1546 if (oper.ReturnType != returnType)
1549 if (oper.Parameters.Types[0] == expr.Type) {
1550 conversion_operator = oper;
1556 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1557 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1560 public override void Emit (EmitContext ec)
1563 ec.Emit (OpCodes.Call, conversion_operator);
1568 // Constant specialization of EmptyCast.
1569 // We need to special case this since an empty cast of
1570 // a constant is still a constant.
1572 public class EmptyConstantCast : Constant
1574 public readonly Constant child;
1576 public EmptyConstantCast (Constant child, TypeSpec type)
1577 : base (child.Location)
1580 throw new ArgumentNullException ("child");
1583 this.eclass = child.eclass;
1587 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1589 if (child.Type == target_type)
1592 // FIXME: check that 'type' can be converted to 'target_type' first
1593 return child.ConvertExplicitly (in_checked_context, target_type);
1596 public override Expression CreateExpressionTree (ResolveContext ec)
1598 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1599 child.CreateExpressionTree (ec),
1600 new TypeOf (type, loc));
1603 Error_PointerInsideExpressionTree (ec);
1605 return CreateExpressionFactoryCall (ec, "Convert", args);
1608 public override bool IsDefaultValue {
1609 get { return child.IsDefaultValue; }
1612 public override bool IsNegative {
1613 get { return child.IsNegative; }
1616 public override bool IsNull {
1617 get { return child.IsNull; }
1620 public override bool IsOneInteger {
1621 get { return child.IsOneInteger; }
1624 public override bool IsSideEffectFree {
1626 return child.IsSideEffectFree;
1630 public override bool IsZeroInteger {
1631 get { return child.IsZeroInteger; }
1634 public override void Emit (EmitContext ec)
1639 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1641 child.EmitBranchable (ec, label, on_true);
1643 // Only to make verifier happy
1644 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1645 ec.Emit (OpCodes.Unbox_Any, type);
1648 public override void EmitSideEffect (EmitContext ec)
1650 child.EmitSideEffect (ec);
1653 public override object GetValue ()
1655 return child.GetValue ();
1658 public override string GetValueAsLiteral ()
1660 return child.GetValueAsLiteral ();
1663 public override long GetValueAsLong ()
1665 return child.GetValueAsLong ();
1668 public override Constant ConvertImplicitly (TypeSpec target_type)
1670 if (type == target_type)
1673 // FIXME: Do we need to check user conversions?
1674 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1677 return child.ConvertImplicitly (target_type);
1682 /// This class is used to wrap literals which belong inside Enums
1684 public class EnumConstant : Constant
1686 public Constant Child;
1688 public EnumConstant (Constant child, TypeSpec enum_type)
1689 : base (child.Location)
1693 this.eclass = ExprClass.Value;
1694 this.type = enum_type;
1697 protected EnumConstant (Location loc)
1702 public override void Emit (EmitContext ec)
1707 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1709 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1712 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1714 Child.EmitBranchable (ec, label, on_true);
1717 public override void EmitSideEffect (EmitContext ec)
1719 Child.EmitSideEffect (ec);
1722 public override string GetSignatureForError()
1724 return Type.GetSignatureForError ();
1727 public override object GetValue ()
1729 return Child.GetValue ();
1733 public override object GetTypedValue ()
1736 // The method can be used in dynamic context only (on closed types)
1738 // System.Enum.ToObject cannot be called on dynamic types
1739 // EnumBuilder has to be used, but we cannot use EnumBuilder
1740 // because it does not properly support generics
1742 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1746 public override string GetValueAsLiteral ()
1748 return Child.GetValueAsLiteral ();
1751 public override long GetValueAsLong ()
1753 return Child.GetValueAsLong ();
1756 public EnumConstant Increment()
1758 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1761 public override bool IsDefaultValue {
1763 return Child.IsDefaultValue;
1767 public override bool IsSideEffectFree {
1769 return Child.IsSideEffectFree;
1773 public override bool IsZeroInteger {
1774 get { return Child.IsZeroInteger; }
1777 public override bool IsNegative {
1779 return Child.IsNegative;
1783 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1785 if (Child.Type == target_type)
1788 return Child.ConvertExplicitly (in_checked_context, target_type);
1791 public override Constant ConvertImplicitly (TypeSpec type)
1793 if (this.type == type) {
1797 if (!Convert.ImplicitStandardConversionExists (this, type)){
1801 return Child.ConvertImplicitly (type);
1806 /// This kind of cast is used to encapsulate Value Types in objects.
1808 /// The effect of it is to box the value type emitted by the previous
1811 public class BoxedCast : TypeCast {
1813 public BoxedCast (Expression expr, TypeSpec target_type)
1814 : base (expr, target_type)
1816 eclass = ExprClass.Value;
1819 protected override Expression DoResolve (ResolveContext ec)
1821 // This should never be invoked, we are born in fully
1822 // initialized state.
1827 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1829 // Only boxing to object type is supported
1830 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1831 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1835 enc.Encode (child.Type);
1836 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1839 public override void Emit (EmitContext ec)
1843 ec.Emit (OpCodes.Box, child.Type);
1846 public override void EmitSideEffect (EmitContext ec)
1848 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1849 // so, we need to emit the box+pop instructions in most cases
1850 if (child.Type.IsStruct &&
1851 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1852 child.EmitSideEffect (ec);
1854 base.EmitSideEffect (ec);
1858 public class UnboxCast : TypeCast {
1859 public UnboxCast (Expression expr, TypeSpec return_type)
1860 : base (expr, return_type)
1864 protected override Expression DoResolve (ResolveContext ec)
1866 // This should never be invoked, we are born in fully
1867 // initialized state.
1872 public override void Emit (EmitContext ec)
1876 ec.Emit (OpCodes.Unbox_Any, type);
1881 /// This is used to perform explicit numeric conversions.
1883 /// Explicit numeric conversions might trigger exceptions in a checked
1884 /// context, so they should generate the conv.ovf opcodes instead of
1887 public class ConvCast : TypeCast {
1888 public enum Mode : byte {
1889 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1891 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1892 U2_I1, U2_U1, U2_I2, U2_CH,
1893 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1894 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1895 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1896 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1897 CH_I1, CH_U1, CH_I2,
1898 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1899 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1905 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1906 : base (child, return_type)
1911 protected override Expression DoResolve (ResolveContext ec)
1913 // This should never be invoked, we are born in fully
1914 // initialized state.
1919 public override string ToString ()
1921 return String.Format ("ConvCast ({0}, {1})", mode, child);
1924 public override void Emit (EmitContext ec)
1930 public static void Emit (EmitContext ec, Mode mode)
1932 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1934 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1935 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1936 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1937 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1938 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1941 case Mode.U1_CH: /* nothing */ break;
1943 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1944 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1945 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1946 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1948 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1950 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1951 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1952 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1953 case Mode.U2_CH: /* nothing */ break;
1955 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1956 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1957 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1958 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1959 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1960 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1964 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1965 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1967 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1968 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1970 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1971 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1972 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1973 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1974 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1975 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1976 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1977 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1978 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1980 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1981 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1982 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1983 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1984 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1985 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1986 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1987 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1988 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1990 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1991 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1992 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1994 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1995 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1996 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1997 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1998 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1999 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2000 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2001 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2002 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2004 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2005 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2006 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2007 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2008 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2009 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2010 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2011 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2012 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2013 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2015 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2019 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2020 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2021 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2022 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2023 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2025 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2026 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2028 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2029 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2030 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2031 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2032 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2033 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2035 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2036 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2037 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2038 case Mode.U2_CH: /* nothing */ break;
2040 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2041 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2042 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2043 case Mode.I4_U4: /* nothing */ break;
2044 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2045 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2046 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U4_I4: /* nothing */ break;
2053 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2055 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2056 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2057 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2058 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2059 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2060 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2061 case Mode.I8_U8: /* nothing */ break;
2062 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2063 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2065 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2066 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2067 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2068 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2069 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2070 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2071 case Mode.U8_I8: /* nothing */ break;
2072 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2073 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2075 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2076 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2077 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2079 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2080 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2081 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2082 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2083 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2084 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2085 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2086 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2087 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2089 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2090 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2091 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2092 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2093 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2094 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2095 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2096 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2097 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2098 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2100 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2106 class OpcodeCast : TypeCast
2110 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2111 : base (child, return_type)
2116 protected override Expression DoResolve (ResolveContext ec)
2118 // This should never be invoked, we are born in fully
2119 // initialized state.
2124 public override void Emit (EmitContext ec)
2130 public TypeSpec UnderlyingType {
2131 get { return child.Type; }
2136 // Opcode casts expression with 2 opcodes but only
2137 // single expression tree node
2139 class OpcodeCastDuplex : OpcodeCast
2141 readonly OpCode second;
2143 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2144 : base (child, returnType, first)
2146 this.second = second;
2149 public override void Emit (EmitContext ec)
2157 /// This kind of cast is used to encapsulate a child and cast it
2158 /// to the class requested
2160 public sealed class ClassCast : TypeCast {
2161 readonly bool forced;
2163 public ClassCast (Expression child, TypeSpec return_type)
2164 : base (child, return_type)
2168 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2169 : base (child, return_type)
2171 this.forced = forced;
2174 public override void Emit (EmitContext ec)
2178 bool gen = TypeManager.IsGenericParameter (child.Type);
2180 ec.Emit (OpCodes.Box, child.Type);
2182 if (type.IsGenericParameter) {
2183 ec.Emit (OpCodes.Unbox_Any, type);
2190 ec.Emit (OpCodes.Castclass, type);
2195 // Created during resolving pahse when an expression is wrapped or constantified
2196 // and original expression can be used later (e.g. for expression trees)
2198 public class ReducedExpression : Expression
2200 public class ReducedConstantExpression : EmptyConstantCast
2202 readonly Expression orig_expr;
2204 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2205 : base (expr, expr.Type)
2207 this.orig_expr = orig_expr;
2210 public Expression OriginalExpression {
2216 public override Constant ConvertImplicitly (TypeSpec target_type)
2218 Constant c = base.ConvertImplicitly (target_type);
2220 c = new ReducedConstantExpression (c, orig_expr);
2225 public override Expression CreateExpressionTree (ResolveContext ec)
2227 return orig_expr.CreateExpressionTree (ec);
2230 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2232 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2234 c = new ReducedConstantExpression (c, orig_expr);
2238 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2241 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2243 if (orig_expr is Conditional)
2244 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2246 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2250 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2252 public ReducedConstantStatement (Constant expr, Expression origExpr)
2253 : base (expr, origExpr)
2258 sealed class ReducedExpressionStatement : ExpressionStatement
2260 readonly Expression orig_expr;
2261 readonly ExpressionStatement stm;
2263 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2265 this.orig_expr = orig;
2267 this.eclass = stm.eclass;
2268 this.type = stm.Type;
2270 this.loc = orig.Location;
2273 public override bool ContainsEmitWithAwait ()
2275 return stm.ContainsEmitWithAwait ();
2278 public override Expression CreateExpressionTree (ResolveContext ec)
2280 return orig_expr.CreateExpressionTree (ec);
2283 protected override Expression DoResolve (ResolveContext ec)
2288 public override void Emit (EmitContext ec)
2293 public override void EmitStatement (EmitContext ec)
2295 stm.EmitStatement (ec);
2298 public override void FlowAnalysis (FlowAnalysisContext fc)
2300 stm.FlowAnalysis (fc);
2304 readonly Expression expr, orig_expr;
2306 private ReducedExpression (Expression expr, Expression orig_expr)
2309 this.eclass = expr.eclass;
2310 this.type = expr.Type;
2311 this.orig_expr = orig_expr;
2312 this.loc = orig_expr.Location;
2317 public override bool IsSideEffectFree {
2319 return expr.IsSideEffectFree;
2323 public Expression OriginalExpression {
2331 public override bool ContainsEmitWithAwait ()
2333 return expr.ContainsEmitWithAwait ();
2337 // Creates fully resolved expression switcher
2339 public static Constant Create (Constant expr, Expression originalExpr)
2341 if (expr.eclass == ExprClass.Unresolved)
2342 throw new ArgumentException ("Unresolved expression");
2344 if (originalExpr is ExpressionStatement)
2345 return new ReducedConstantStatement (expr, originalExpr);
2347 return new ReducedConstantExpression (expr, originalExpr);
2350 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2352 return new ReducedExpressionStatement (s, orig);
2355 public static Expression Create (Expression expr, Expression original_expr)
2357 return Create (expr, original_expr, true);
2361 // Creates unresolved reduce expression. The original expression has to be
2362 // already resolved. Created expression is constant based based on `expr'
2363 // value unless canBeConstant is used
2365 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2367 if (canBeConstant) {
2368 Constant c = expr as Constant;
2370 return Create (c, original_expr);
2373 ExpressionStatement s = expr as ExpressionStatement;
2375 return Create (s, original_expr);
2377 if (expr.eclass == ExprClass.Unresolved)
2378 throw new ArgumentException ("Unresolved expression");
2380 return new ReducedExpression (expr, original_expr);
2383 public override Expression CreateExpressionTree (ResolveContext ec)
2385 return orig_expr.CreateExpressionTree (ec);
2388 protected override Expression DoResolve (ResolveContext ec)
2393 public override void Emit (EmitContext ec)
2398 public override Expression EmitToField (EmitContext ec)
2400 return expr.EmitToField(ec);
2403 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2405 expr.EmitBranchable (ec, target, on_true);
2408 public override void FlowAnalysis (FlowAnalysisContext fc)
2410 expr.FlowAnalysis (fc);
2413 public override SLE.Expression MakeExpression (BuilderContext ctx)
2415 return orig_expr.MakeExpression (ctx);
2418 public override Reachability MarkReachable (Reachability rc)
2420 return expr.MarkReachable (rc);
2425 // Standard composite pattern
2427 public abstract class CompositeExpression : Expression
2429 protected Expression expr;
2431 protected CompositeExpression (Expression expr)
2434 this.loc = expr.Location;
2437 public override bool ContainsEmitWithAwait ()
2439 return expr.ContainsEmitWithAwait ();
2442 public override Expression CreateExpressionTree (ResolveContext rc)
2444 return expr.CreateExpressionTree (rc);
2447 public Expression Child {
2448 get { return expr; }
2451 protected override Expression DoResolve (ResolveContext rc)
2453 expr = expr.Resolve (rc);
2458 eclass = expr.eclass;
2462 public override void Emit (EmitContext ec)
2467 public override bool IsNull {
2468 get { return expr.IsNull; }
2473 // Base of expressions used only to narrow resolve flow
2475 public abstract class ShimExpression : Expression
2477 protected Expression expr;
2479 protected ShimExpression (Expression expr)
2484 public Expression Expr {
2490 protected override void CloneTo (CloneContext clonectx, Expression t)
2495 ShimExpression target = (ShimExpression) t;
2496 target.expr = expr.Clone (clonectx);
2499 public override bool ContainsEmitWithAwait ()
2501 return expr.ContainsEmitWithAwait ();
2504 public override Expression CreateExpressionTree (ResolveContext ec)
2506 throw new NotSupportedException ("ET");
2509 public override void Emit (EmitContext ec)
2511 throw new InternalErrorException ("Missing Resolve call");
2515 public class UnreachableExpression : Expression
2517 public UnreachableExpression (Expression expr)
2519 this.loc = expr.Location;
2522 public override Expression CreateExpressionTree (ResolveContext ec)
2525 throw new NotImplementedException ();
2528 protected override Expression DoResolve (ResolveContext rc)
2530 throw new NotSupportedException ();
2533 public override void FlowAnalysis (FlowAnalysisContext fc)
2535 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2538 public override void Emit (EmitContext ec)
2542 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2548 // Unresolved type name expressions
2550 public abstract class ATypeNameExpression : FullNamedExpression
2553 protected TypeArguments targs;
2555 protected ATypeNameExpression (string name, Location l)
2561 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2568 protected ATypeNameExpression (string name, int arity, Location l)
2569 : this (name, new UnboundTypeArguments (arity, l), l)
2577 return targs == null ? 0 : targs.Count;
2581 public bool HasTypeArguments {
2583 return targs != null && !targs.IsEmpty;
2587 public string Name {
2596 public TypeArguments TypeArguments {
2604 public override bool Equals (object obj)
2606 ATypeNameExpression atne = obj as ATypeNameExpression;
2607 return atne != null && atne.Name == Name &&
2608 (targs == null || targs.Equals (atne.targs));
2611 public override int GetHashCode ()
2613 return Name.GetHashCode ();
2616 // TODO: Move it to MemberCore
2617 public static string GetMemberType (MemberCore mc)
2623 if (mc is FieldBase)
2625 if (mc is MethodCore)
2627 if (mc is EnumMember)
2635 public override string GetSignatureForError ()
2637 if (targs != null) {
2638 return Name + "<" + targs.GetSignatureForError () + ">";
2644 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2648 /// SimpleName expressions are formed of a single word and only happen at the beginning
2649 /// of a dotted-name.
2651 public class SimpleName : ATypeNameExpression
2653 public SimpleName (string name, Location l)
2658 public SimpleName (string name, TypeArguments args, Location l)
2659 : base (name, args, l)
2663 public SimpleName (string name, int arity, Location l)
2664 : base (name, arity, l)
2668 public SimpleName GetMethodGroup ()
2670 return new SimpleName (Name, targs, loc);
2673 protected override Expression DoResolve (ResolveContext rc)
2675 return SimpleNameResolve (rc, null);
2678 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2680 return SimpleNameResolve (ec, right_side);
2683 public void Error_NameDoesNotExist (ResolveContext rc)
2685 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2688 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2690 if (ctx.CurrentType != null) {
2691 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2692 if (member != null) {
2693 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2698 var report = ctx.Module.Compiler.Report;
2700 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2701 if (retval != null) {
2702 report.SymbolRelatedToPreviousError (retval.Type);
2703 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2707 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2708 if (retval != null) {
2709 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2713 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2714 if (ns_candidates != null) {
2715 if (ctx is UsingAliasNamespace.AliasContext) {
2716 report.Error (246, loc,
2717 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2718 ns_candidates[0], Name);
2720 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2721 report.Error (246, loc,
2722 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2726 report.Error (246, loc,
2727 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2732 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2734 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2737 if (fne.Type != null && Arity > 0) {
2738 if (HasTypeArguments) {
2739 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2740 if (ct.ResolveAsType (mc) == null)
2746 targs.Resolve (mc, allowUnboundTypeArguments);
2748 return new GenericOpenTypeExpr (fne.Type, loc);
2752 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2754 if (!(fne is NamespaceExpression))
2758 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2759 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2760 mc.Module.Compiler.Report.Error (1980, Location,
2761 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2762 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2765 fne = new DynamicTypeExpr (loc);
2766 fne.ResolveAsType (mc);
2772 Error_TypeOrNamespaceNotFound (mc);
2776 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2779 // Has to ignore static usings because we are looking for any member not just type
2782 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2785 public bool IsPossibleType (IMemberContext mc)
2787 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2790 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2792 int lookup_arity = Arity;
2793 bool errorMode = false;
2795 Block current_block = rc.CurrentBlock;
2796 INamedBlockVariable variable = null;
2797 bool variable_found = false;
2801 // Stage 1: binding to local variables or parameters
2803 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2805 if (current_block != null && lookup_arity == 0) {
2806 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2807 if (!variable.IsDeclared) {
2808 // We found local name in accessible block but it's not
2809 // initialized yet, maybe the user wanted to bind to something else
2811 variable_found = true;
2813 e = variable.CreateReferenceExpression (rc, loc);
2816 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2825 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2827 TypeSpec member_type = rc.CurrentType;
2828 for (; member_type != null; member_type = member_type.DeclaringType) {
2829 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2833 var me = e as MemberExpr;
2835 // The name matches a type, defer to ResolveAsTypeStep
2843 if (variable != null) {
2844 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2845 rc.Report.Error (844, loc,
2846 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2847 Name, me.GetSignatureForError ());
2851 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2852 // Leave it to overload resolution to report correct error
2854 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2855 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2859 // MemberLookup does not check accessors availability, this is actually needed for properties only
2861 var pe = me as PropertyExpr;
2864 // Break as there is no other overload available anyway
2865 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2866 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2869 pe.Getter = pe.PropertyInfo.Get;
2871 if (!pe.PropertyInfo.HasSet) {
2872 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2873 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2874 var p = (Property) pe.PropertyInfo.MemberDefinition;
2875 return new FieldExpr (p.BackingField, loc);
2878 variable_found = true;
2882 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2883 variable_found = true;
2887 pe.Setter = pe.PropertyInfo.Set;
2892 // TODO: It's used by EventExpr -> FieldExpr transformation only
2893 // TODO: Should go to MemberAccess
2894 me = me.ResolveMemberAccess (rc, null, null);
2897 targs.Resolve (rc, false);
2898 me.SetTypeArguments (rc, targs);
2905 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2907 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2908 if (IsPossibleTypeOrNamespace (rc)) {
2909 return ResolveAsTypeOrNamespace (rc, false);
2913 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2916 targs.Resolve (rc, false);
2918 var me = expr as MemberExpr;
2920 me.SetTypeArguments (rc, targs);
2925 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2926 return new NameOf (this);
2929 if (variable_found) {
2930 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2933 var tparams = rc.CurrentTypeParameters;
2934 if (tparams != null) {
2935 if (tparams.Find (Name) != null) {
2936 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2941 var ct = rc.CurrentType;
2943 if (ct.MemberDefinition.TypeParametersCount > 0) {
2944 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2945 if (ctp.Name == Name) {
2946 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2952 ct = ct.DeclaringType;
2953 } while (ct != null);
2956 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2957 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2959 rc.Report.SymbolRelatedToPreviousError (e.Type);
2960 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2964 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2966 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2967 return ErrorExpression.Instance;
2971 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2973 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2974 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2978 if (e is TypeExpr) {
2979 // TypeExpression does not have correct location
2980 if (e is TypeExpression)
2981 e = new TypeExpression (e.Type, loc);
2987 Error_NameDoesNotExist (rc);
2990 return ErrorExpression.Instance;
2993 if (rc.Module.Evaluator != null) {
2994 var fi = rc.Module.Evaluator.LookupField (Name);
2996 return new FieldExpr (fi.Item1, loc);
3004 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3006 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3011 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3012 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3016 if (right_side != null) {
3017 e = e.ResolveLValue (ec, right_side);
3025 public override object Accept (StructuralVisitor visitor)
3027 return visitor.Visit (this);
3032 /// Represents a namespace or a type. The name of the class was inspired by
3033 /// section 10.8.1 (Fully Qualified Names).
3035 public abstract class FullNamedExpression : Expression
3037 protected override void CloneTo (CloneContext clonectx, Expression target)
3039 // Do nothing, most unresolved type expressions cannot be
3040 // resolved to different type
3043 public override bool ContainsEmitWithAwait ()
3048 public override Expression CreateExpressionTree (ResolveContext ec)
3050 throw new NotSupportedException ("ET");
3053 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3056 // This is used to resolve the expression as a type, a null
3057 // value will be returned if the expression is not a type
3060 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3062 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3067 TypeExpr te = fne as TypeExpr;
3069 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3077 var dep = type.GetMissingDependencies ();
3079 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3082 if (type.Kind == MemberKind.Void) {
3083 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3087 // Obsolete checks cannot be done when resolving base context as they
3088 // require type dependencies to be set but we are in process of resolving them
3090 if (mc is ResolveContext) {
3091 var oa = type.GetAttributeObsolete ();
3092 if (oa != null && !mc.IsObsolete)
3093 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3100 public override void Emit (EmitContext ec)
3102 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3103 GetSignatureForError ());
3108 /// Expression that evaluates to a type
3110 public abstract class TypeExpr : FullNamedExpression
3112 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3118 protected sealed override Expression DoResolve (ResolveContext ec)
3124 public override bool Equals (object obj)
3126 TypeExpr tobj = obj as TypeExpr;
3130 return Type == tobj.Type;
3133 public override int GetHashCode ()
3135 return Type.GetHashCode ();
3140 /// Fully resolved Expression that already evaluated to a type
3142 public class TypeExpression : TypeExpr
3144 public TypeExpression (TypeSpec t, Location l)
3147 eclass = ExprClass.Type;
3151 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3157 public class NamespaceExpression : FullNamedExpression
3159 readonly Namespace ns;
3161 public NamespaceExpression (Namespace ns, Location loc)
3164 this.Type = InternalType.Namespace;
3165 this.eclass = ExprClass.Namespace;
3169 public Namespace Namespace {
3175 protected override Expression DoResolve (ResolveContext rc)
3177 throw new NotImplementedException ();
3180 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3185 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3187 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3188 if (retval != null) {
3189 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3190 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3194 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3195 if (retval != null) {
3196 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3201 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3202 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3206 string assembly = null;
3207 string possible_name = Namespace.GetSignatureForError () + "." + name;
3209 // Only assembly unique name should be added
3210 switch (possible_name) {
3211 case "System.Drawing":
3212 case "System.Web.Services":
3215 case "System.Configuration":
3216 case "System.Data.Services":
3217 case "System.DirectoryServices":
3219 case "System.Net.Http":
3220 case "System.Numerics":
3221 case "System.Runtime.Caching":
3222 case "System.ServiceModel":
3223 case "System.Transactions":
3224 case "System.Web.Routing":
3225 case "System.Xml.Linq":
3227 assembly = possible_name;
3231 case "System.Linq.Expressions":
3232 assembly = "System.Core";
3235 case "System.Windows.Forms":
3236 case "System.Windows.Forms.Layout":
3237 assembly = "System.Windows.Forms";
3241 assembly = assembly == null ? "an" : "`" + assembly + "'";
3243 if (Namespace is GlobalRootNamespace) {
3244 ctx.Module.Compiler.Report.Error (400, loc,
3245 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3248 ctx.Module.Compiler.Report.Error (234, loc,
3249 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3250 name, GetSignatureForError (), assembly);
3254 public override string GetSignatureForError ()
3256 return ns.GetSignatureForError ();
3259 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3261 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3264 public override string ToString ()
3266 return Namespace.Name;
3271 /// This class denotes an expression which evaluates to a member
3272 /// of a struct or a class.
3274 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3276 protected bool conditional_access_receiver;
3279 // An instance expression associated with this member, if it's a
3280 // non-static member
3282 public Expression InstanceExpression;
3285 /// The name of this member.
3287 public abstract string Name {
3292 // When base.member is used
3294 public bool IsBase {
3295 get { return InstanceExpression is BaseThis; }
3299 /// Whether this is an instance member.
3301 public abstract bool IsInstance {
3306 /// Whether this is a static member.
3308 public abstract bool IsStatic {
3312 public abstract string KindName {
3316 public bool ConditionalAccess { get; set; }
3318 protected abstract TypeSpec DeclaringType {
3322 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3324 return InstanceExpression.Type;
3329 // Converts best base candidate for virtual method starting from QueriedBaseType
3331 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3334 // Only when base.member is used and method is virtual
3340 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3341 // means for base.member access we have to find the closest match after we found best candidate
3343 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3345 // The method could already be what we are looking for
3347 TypeSpec[] targs = null;
3348 if (method.DeclaringType != InstanceExpression.Type) {
3350 // Candidate can have inflated MVAR parameters and we need to find
3351 // base match for original definition not inflated parameter types
3353 var parameters = method.Parameters;
3354 if (method.Arity > 0) {
3355 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3356 var inflated = method.DeclaringType as InflatedTypeSpec;
3357 if (inflated != null) {
3358 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3362 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3363 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3364 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3365 if (base_override.IsGeneric)
3366 targs = method.TypeArguments;
3368 method = base_override;
3373 // When base access is used inside anonymous method/iterator/etc we need to
3374 // get back to the context of original type. We do it by emiting proxy
3375 // method in original class and rewriting base call to this compiler
3376 // generated method call which does the actual base invocation. This may
3377 // introduce redundant storey but with `this' only but it's tricky to avoid
3378 // at this stage as we don't know what expressions follow base
3380 // TODO: It's needed only when the method with base call is moved to a storey
3382 if (rc.CurrentAnonymousMethod != null) {
3383 if (targs == null && method.IsGeneric) {
3384 targs = method.TypeArguments;
3385 method = method.GetGenericMethodDefinition ();
3388 if (method.Parameters.HasArglist)
3389 throw new NotImplementedException ("__arglist base call proxy");
3391 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3393 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3394 // get/set member expressions second call would fail to proxy because left expression
3395 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3396 // FIXME: The async check is another hack but will probably fail with mutators
3397 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3398 InstanceExpression = new This (loc).Resolve (rc);
3402 method = method.MakeGenericMethod (rc, targs);
3406 // Only base will allow this invocation to happen.
3408 if (method.IsAbstract) {
3409 rc.Report.SymbolRelatedToPreviousError (method);
3410 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3416 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3418 if (InstanceExpression == null)
3421 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3422 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3423 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3428 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3430 if (InstanceExpression == null)
3433 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3436 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3438 var ct = rc.CurrentType;
3439 if (ct == qualifier)
3442 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3445 qualifier = qualifier.GetDefinition ();
3446 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3453 public override bool ContainsEmitWithAwait ()
3455 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3458 public override bool HasConditionalAccess ()
3460 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3463 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3466 type = type.GetDefinition ();
3468 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3471 type = type.DeclaringType;
3472 } while (type != null);
3477 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3479 if (InstanceExpression != null) {
3480 InstanceExpression = InstanceExpression.Resolve (rc);
3481 CheckProtectedMemberAccess (rc, member);
3484 if (member.MemberType.IsPointer) {
3485 if (rc.CurrentIterator != null) {
3486 UnsafeInsideIteratorError (rc, loc);
3487 } else if (!rc.IsUnsafe) {
3488 UnsafeError (rc, loc);
3492 var dep = member.GetMissingDependencies ();
3494 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3497 member.CheckObsoleteness (rc, loc);
3499 if (!(member is FieldSpec))
3500 member.MemberDefinition.SetIsUsed ();
3503 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3505 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3508 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3510 rc.Report.SymbolRelatedToPreviousError (member);
3511 rc.Report.Error (1540, loc,
3512 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3513 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3516 public override void FlowAnalysis (FlowAnalysisContext fc)
3518 if (InstanceExpression != null) {
3519 InstanceExpression.FlowAnalysis (fc);
3523 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3525 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3526 conditional_access_receiver = true;
3530 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3532 if (!ResolveInstanceExpressionCore (rc, rhs))
3536 // Check intermediate value modification which won't have any effect
3538 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3539 var fexpr = InstanceExpression as FieldExpr;
3540 if (fexpr != null) {
3541 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3544 if (fexpr.IsStatic) {
3545 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3546 fexpr.GetSignatureForError ());
3548 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3549 fexpr.GetSignatureForError ());
3555 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3556 if (rc.CurrentInitializerVariable != null) {
3557 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3558 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3560 rc.Report.Error (1612, loc,
3561 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3562 InstanceExpression.GetSignatureForError ());
3568 var lvr = InstanceExpression as LocalVariableReference;
3571 if (!lvr.local_info.IsReadonly)
3574 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3575 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3582 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3585 if (InstanceExpression != null) {
3586 if (InstanceExpression is TypeExpr) {
3587 var t = InstanceExpression.Type;
3589 t.CheckObsoleteness (rc, loc);
3591 t = t.DeclaringType;
3592 } while (t != null);
3594 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3595 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3596 rc.Report.Error (176, loc,
3597 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3598 GetSignatureForError ());
3602 InstanceExpression = null;
3608 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3609 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3610 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3611 rc.Report.Error (236, loc,
3612 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3613 GetSignatureForError ());
3615 var fe = this as FieldExpr;
3616 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3617 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3618 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3620 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3624 rc.Report.Error (120, loc,
3625 "An object reference is required to access non-static member `{0}'",
3626 GetSignatureForError ());
3630 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3634 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3635 rc.Report.Error (38, loc,
3636 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3637 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3640 InstanceExpression = new This (loc).Resolve (rc);
3644 var me = InstanceExpression as MemberExpr;
3646 me.ResolveInstanceExpressionCore (rc, rhs);
3648 var fe = me as FieldExpr;
3649 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3650 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3651 rc.Report.Warning (1690, 1, loc,
3652 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3653 me.GetSignatureForError ());
3660 // Additional checks for l-value member access
3663 if (InstanceExpression is UnboxCast) {
3664 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3671 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3673 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3674 ec.Report.Warning (1720, 1, left.Location,
3675 "Expression will always cause a `{0}'", "System.NullReferenceException");
3678 InstanceExpression = left;
3682 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3687 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3689 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3690 inst.Emit (ec, ConditionalAccess);
3692 if (prepare_for_load)
3693 ec.Emit (OpCodes.Dup);
3696 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3699 public class ExtensionMethodCandidates
3701 readonly NamespaceContainer container;
3702 readonly IList<MethodSpec> methods;
3704 readonly IMemberContext context;
3706 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3708 this.context = context;
3709 this.methods = methods;
3710 this.container = nsContainer;
3711 this.index = lookupIndex;
3714 public NamespaceContainer Container {
3720 public IMemberContext Context {
3726 public int LookupIndex {
3732 public IList<MethodSpec> Methods {
3740 // Represents a group of extension method candidates for whole namespace
3742 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3744 ExtensionMethodCandidates candidates;
3745 public Expression ExtensionExpression;
3747 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3748 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3750 this.candidates = candidates;
3751 this.ExtensionExpression = extensionExpr;
3754 public override bool IsStatic {
3755 get { return true; }
3759 // For extension methodgroup we are not looking for base members but parent
3760 // namespace extension methods
3762 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3764 // TODO: candidates are null only when doing error reporting, that's
3765 // incorrect. We have to discover same extension methods in error mode
3766 if (candidates == null)
3769 int arity = type_arguments == null ? 0 : type_arguments.Count;
3771 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3772 if (candidates == null)
3775 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3778 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3781 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3783 // LAMESPEC: or implicit type parameter conversion
3785 return argType == extensionType ||
3786 TypeSpecComparer.IsEqual (argType, extensionType) ||
3787 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3788 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3791 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3793 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3796 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3798 // We are already here
3802 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3804 if (arguments == null)
3805 arguments = new Arguments (1);
3807 ExtensionExpression = ExtensionExpression.Resolve (ec);
3808 if (ExtensionExpression == null)
3811 var cand = candidates;
3812 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3813 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3814 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3816 // Restore candidates in case we are running in probing mode
3819 // Store resolved argument and restore original arguments
3821 // Clean-up modified arguments for error reporting
3822 arguments.RemoveAt (0);
3826 var me = ExtensionExpression as MemberExpr;
3828 me.ResolveInstanceExpression (ec, null);
3829 var fe = me as FieldExpr;
3831 fe.Spec.MemberDefinition.SetIsUsed ();
3834 InstanceExpression = null;
3838 #region IErrorHandler Members
3840 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3845 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3847 rc.Report.SymbolRelatedToPreviousError (best);
3850 rc.Report.Error (1929, loc,
3851 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3852 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3854 rc.Report.Error (1928, loc,
3855 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3856 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3862 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3867 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3876 /// MethodGroupExpr represents a group of method candidates which
3877 /// can be resolved to the best method overload
3879 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3881 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3883 protected IList<MemberSpec> Methods;
3884 MethodSpec best_candidate;
3885 TypeSpec best_candidate_return;
3886 protected TypeArguments type_arguments;
3888 SimpleName simple_name;
3889 protected TypeSpec queried_type;
3891 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3895 this.type = InternalType.MethodGroup;
3897 eclass = ExprClass.MethodGroup;
3898 queried_type = type;
3901 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3902 : this (new MemberSpec[] { m }, type, loc)
3908 public MethodSpec BestCandidate {
3910 return best_candidate;
3914 public TypeSpec BestCandidateReturnType {
3916 return best_candidate_return;
3920 public IList<MemberSpec> Candidates {
3926 protected override TypeSpec DeclaringType {
3928 return queried_type;
3932 public bool IsConditionallyExcluded {
3934 return Methods == Excluded;
3938 public override bool IsInstance {
3940 if (best_candidate != null)
3941 return !best_candidate.IsStatic;
3947 public override bool IsSideEffectFree {
3949 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3953 public override bool IsStatic {
3955 if (best_candidate != null)
3956 return best_candidate.IsStatic;
3962 public override string KindName {
3963 get { return "method"; }
3966 public override string Name {
3968 if (best_candidate != null)
3969 return best_candidate.Name;
3972 return Methods.First ().Name;
3979 // When best candidate is already know this factory can be used
3980 // to avoid expensive overload resolution to be called
3982 // NOTE: InstanceExpression has to be set manually
3984 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3986 return new MethodGroupExpr (best, queriedType, loc) {
3987 best_candidate = best,
3988 best_candidate_return = best.ReturnType
3992 public override string GetSignatureForError ()
3994 if (best_candidate != null)
3995 return best_candidate.GetSignatureForError ();
3997 return Methods.First ().GetSignatureForError ();
4000 public override Expression CreateExpressionTree (ResolveContext ec)
4002 if (best_candidate == null) {
4003 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4007 if (IsConditionallyExcluded)
4008 ec.Report.Error (765, loc,
4009 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4011 if (ConditionalAccess)
4012 Error_NullShortCircuitInsideExpressionTree (ec);
4014 return new TypeOfMethod (best_candidate, loc);
4017 protected override Expression DoResolve (ResolveContext ec)
4019 this.eclass = ExprClass.MethodGroup;
4021 if (InstanceExpression != null) {
4022 InstanceExpression = InstanceExpression.Resolve (ec);
4023 if (InstanceExpression == null)
4030 public override void Emit (EmitContext ec)
4032 throw new NotSupportedException ();
4035 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4037 var call = new CallEmitter ();
4038 call.InstanceExpression = InstanceExpression;
4039 call.ConditionalAccess = ConditionalAccess;
4042 call.EmitStatement (ec, best_candidate, arguments, loc);
4044 call.Emit (ec, best_candidate, arguments, loc);
4047 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4049 var ca = ec.ConditionalAccess;
4050 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4051 Statement = statement
4054 EmitCall (ec, arguments, statement);
4056 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4057 ec.ConditionalAccess = ca;
4060 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4062 if (target != InternalType.ErrorType) {
4063 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4064 Name, target.GetSignatureForError ());
4068 public bool HasAccessibleCandidate (ResolveContext rc)
4070 foreach (var candidate in Candidates) {
4071 if (candidate.IsAccessible (rc))
4078 public static bool IsExtensionMethodArgument (Expression expr)
4081 // LAMESPEC: No details about which expressions are not allowed
4083 return !(expr is TypeExpr) && !(expr is BaseThis);
4087 /// Find the Applicable Function Members (7.4.2.1)
4089 /// me: Method Group expression with the members to select.
4090 /// it might contain constructors or methods (or anything
4091 /// that maps to a method).
4093 /// Arguments: ArrayList containing resolved Argument objects.
4095 /// loc: The location if we want an error to be reported, or a Null
4096 /// location for "probing" purposes.
4098 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4099 /// that is the best match of me on Arguments.
4102 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4104 // TODO: causes issues with probing mode, remove explicit Kind check
4105 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4108 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4109 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4110 r.BaseMembersProvider = this;
4111 r.InstanceQualifier = this;
4114 if (cerrors != null)
4115 r.CustomErrors = cerrors;
4117 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4118 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4119 if (best_candidate == null) {
4120 if (!r.BestCandidateIsDynamic)
4123 if (simple_name != null && ec.IsStatic)
4124 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4129 // Overload resolver had to create a new method group, all checks bellow have already been executed
4130 if (r.BestCandidateNewMethodGroup != null)
4131 return r.BestCandidateNewMethodGroup;
4133 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4134 if (InstanceExpression != null) {
4135 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4136 InstanceExpression = null;
4138 if (simple_name != null && best_candidate.IsStatic) {
4139 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4142 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4146 ResolveInstanceExpression (ec, null);
4149 var base_override = CandidateToBaseOverride (ec, best_candidate);
4150 if (base_override == best_candidate) {
4151 best_candidate_return = r.BestCandidateReturnType;
4153 best_candidate = base_override;
4154 best_candidate_return = best_candidate.ReturnType;
4157 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4158 ConstraintChecker cc = new ConstraintChecker (ec);
4159 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4163 // Additional check for possible imported base override method which
4164 // could not be done during IsOverrideMethodBaseTypeAccessible
4166 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4167 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4168 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4169 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4172 // Speed up the check by not doing it on disallowed targets
4173 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4179 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4181 var fe = left as FieldExpr;
4184 // Using method-group on struct fields makes the struct assigned. I am not sure
4185 // why but that's what .net does
4187 fe.Spec.MemberDefinition.SetIsAssigned ();
4190 simple_name = original;
4191 return base.ResolveMemberAccess (ec, left, original);
4194 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4196 if (!HasAccessibleCandidate (rc)) {
4197 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4200 if (expr.HasTypeArguments) {
4201 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4205 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4207 type_arguments = ta;
4210 #region IBaseMembersProvider Members
4212 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4214 var baseType = type.BaseType;
4216 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4218 if (members == null && !type.IsInterface) {
4219 var tps = queried_type as TypeParameterSpec;
4221 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4227 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4229 if (queried_type == member.DeclaringType)
4232 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4233 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4237 // Extension methods lookup after ordinary methods candidates failed to apply
4239 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4241 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4244 if (!IsExtensionMethodArgument (InstanceExpression))
4247 int arity = type_arguments == null ? 0 : type_arguments.Count;
4248 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4249 if (methods == null)
4252 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4253 emg.SetTypeArguments (rc, type_arguments);
4254 emg.ConditionalAccess = ConditionalAccess;
4261 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4263 public ConstructorInstanceQualifier (TypeSpec type)
4266 InstanceType = type;
4269 public TypeSpec InstanceType { get; private set; }
4271 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4273 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4277 public struct OverloadResolver
4280 public enum Restrictions
4284 ProbingOnly = 1 << 1,
4285 CovariantDelegate = 1 << 2,
4286 NoBaseMembers = 1 << 3,
4287 BaseMembersIncluded = 1 << 4,
4288 GetEnumeratorLookup = 1 << 5
4291 public interface IBaseMembersProvider
4293 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4294 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4295 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4298 public interface IErrorHandler
4300 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4301 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4302 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4303 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4306 public interface IInstanceQualifier
4308 TypeSpec InstanceType { get; }
4309 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4312 sealed class NoBaseMembers : IBaseMembersProvider
4314 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4316 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4321 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4326 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4332 struct AmbiguousCandidate
4334 public readonly MemberSpec Member;
4335 public readonly bool Expanded;
4336 public readonly AParametersCollection Parameters;
4338 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4341 Parameters = parameters;
4342 Expanded = expanded;
4347 IList<MemberSpec> members;
4348 TypeArguments type_arguments;
4349 IBaseMembersProvider base_provider;
4350 IErrorHandler custom_errors;
4351 IInstanceQualifier instance_qualifier;
4352 Restrictions restrictions;
4353 MethodGroupExpr best_candidate_extension_group;
4354 TypeSpec best_candidate_return_type;
4356 SessionReportPrinter lambda_conv_msgs;
4358 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4359 : this (members, null, restrictions, loc)
4363 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4366 if (members == null || members.Count == 0)
4367 throw new ArgumentException ("empty members set");
4369 this.members = members;
4371 type_arguments = targs;
4372 this.restrictions = restrictions;
4373 if (IsDelegateInvoke)
4374 this.restrictions |= Restrictions.NoBaseMembers;
4376 base_provider = NoBaseMembers.Instance;
4381 public IBaseMembersProvider BaseMembersProvider {
4383 return base_provider;
4386 base_provider = value;
4390 public bool BestCandidateIsDynamic { get; set; }
4393 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4395 public MethodGroupExpr BestCandidateNewMethodGroup {
4397 return best_candidate_extension_group;
4402 // Return type can be different between best candidate and closest override
4404 public TypeSpec BestCandidateReturnType {
4406 return best_candidate_return_type;
4410 public IErrorHandler CustomErrors {
4412 return custom_errors;
4415 custom_errors = value;
4419 TypeSpec DelegateType {
4421 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4422 throw new InternalErrorException ("Not running in delegate mode", loc);
4424 return members [0].DeclaringType;
4428 public IInstanceQualifier InstanceQualifier {
4430 return instance_qualifier;
4433 instance_qualifier = value;
4437 bool IsProbingOnly {
4439 return (restrictions & Restrictions.ProbingOnly) != 0;
4443 bool IsDelegateInvoke {
4445 return (restrictions & Restrictions.DelegateInvoke) != 0;
4452 // 7.4.3.3 Better conversion from expression
4453 // Returns : 1 if a->p is better,
4454 // 2 if a->q is better,
4455 // 0 if neither is better
4457 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4459 TypeSpec argument_type = a.Type;
4462 // Exactly matching Expression phase
4466 // If argument is an anonymous function
4468 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4470 // p and q are delegate types or expression tree types
4472 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4473 if (q.MemberDefinition != p.MemberDefinition) {
4478 // Uwrap delegate from Expression<T>
4480 q = TypeManager.GetTypeArguments (q) [0];
4481 p = TypeManager.GetTypeArguments (p) [0];
4484 var p_m = Delegate.GetInvokeMethod (p);
4485 var q_m = Delegate.GetInvokeMethod (q);
4488 // With identical parameter lists
4490 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4498 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4500 if (p.Kind == MemberKind.Void) {
4501 return q.Kind != MemberKind.Void ? 2 : 0;
4505 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4507 if (q.Kind == MemberKind.Void) {
4508 return p.Kind != MemberKind.Void ? 1 : 0;
4511 var am = (AnonymousMethodExpression)a.Expr;
4514 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4515 // better conversion is performed between underlying types Y1 and Y2
4517 if (p.IsGenericTask || q.IsGenericTask) {
4518 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4519 q = q.TypeArguments [0];
4520 p = p.TypeArguments [0];
4526 // An inferred return type X exists for E in the context of the parameter list, and
4527 // an identity conversion exists from X to the return type of D
4529 var inferred_type = am.InferReturnType (ec, null, orig_q);
4530 if (inferred_type != null) {
4531 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4532 inferred_type = ec.BuiltinTypes.Object;
4534 if (inferred_type == p)
4537 if (inferred_type == q)
4543 if (argument_type == p)
4546 if (argument_type == q)
4549 return IsBetterConversionTarget (ec, p, q);
4552 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4554 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4556 if (p.Kind != MemberKind.Delegate) {
4557 p = TypeManager.GetTypeArguments (p) [0];
4560 if (q.Kind != MemberKind.Delegate) {
4561 q = TypeManager.GetTypeArguments (q) [0];
4564 var p_m = Delegate.GetInvokeMethod (p);
4565 var q_m = Delegate.GetInvokeMethod (q);
4571 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4573 if (p.Kind == MemberKind.Void) {
4574 return q.Kind != MemberKind.Void ? 2 : 0;
4578 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4580 if (q.Kind == MemberKind.Void) {
4581 return p.Kind != MemberKind.Void ? 1 : 0;
4584 return IsBetterConversionTarget (rc, p, q);
4587 if (p.IsGenericTask && q.IsGenericTask) {
4588 q = q.TypeArguments [0];
4589 p = p.TypeArguments [0];
4590 return IsBetterConversionTarget (rc, p, q);
4594 if (p.IsNullableType) {
4595 p = Nullable.NullableInfo.GetUnderlyingType (p);
4596 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4597 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4600 // Spec expects implicit conversion check between p and q, q and p
4601 // to be done before nullable unwrapping but that's expensive operation.
4603 // Extra manual tweak is needed because BetterTypeConversion works on
4611 if (q.IsNullableType) {
4612 q = Nullable.NullableInfo.GetUnderlyingType (q);
4613 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4614 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4620 return BetterTypeConversion (rc, p, q);
4624 // 7.4.3.4 Better conversion from type
4626 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4628 if (p == null || q == null)
4629 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4631 switch (p.BuiltinType) {
4632 case BuiltinTypeSpec.Type.Int:
4633 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4636 case BuiltinTypeSpec.Type.Long:
4637 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4640 case BuiltinTypeSpec.Type.SByte:
4641 switch (q.BuiltinType) {
4642 case BuiltinTypeSpec.Type.Byte:
4643 case BuiltinTypeSpec.Type.UShort:
4644 case BuiltinTypeSpec.Type.UInt:
4645 case BuiltinTypeSpec.Type.ULong:
4649 case BuiltinTypeSpec.Type.Short:
4650 switch (q.BuiltinType) {
4651 case BuiltinTypeSpec.Type.UShort:
4652 case BuiltinTypeSpec.Type.UInt:
4653 case BuiltinTypeSpec.Type.ULong:
4657 case BuiltinTypeSpec.Type.Dynamic:
4658 // LAMESPEC: Dynamic conversions is not considered
4659 p = ec.Module.Compiler.BuiltinTypes.Object;
4663 switch (q.BuiltinType) {
4664 case BuiltinTypeSpec.Type.Int:
4665 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4668 case BuiltinTypeSpec.Type.Long:
4669 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4672 case BuiltinTypeSpec.Type.SByte:
4673 switch (p.BuiltinType) {
4674 case BuiltinTypeSpec.Type.Byte:
4675 case BuiltinTypeSpec.Type.UShort:
4676 case BuiltinTypeSpec.Type.UInt:
4677 case BuiltinTypeSpec.Type.ULong:
4681 case BuiltinTypeSpec.Type.Short:
4682 switch (p.BuiltinType) {
4683 case BuiltinTypeSpec.Type.UShort:
4684 case BuiltinTypeSpec.Type.UInt:
4685 case BuiltinTypeSpec.Type.ULong:
4689 case BuiltinTypeSpec.Type.Dynamic:
4690 // LAMESPEC: Dynamic conversions is not considered
4691 q = ec.Module.Compiler.BuiltinTypes.Object;
4695 return BetterTypeConversionImplicitConversion (ec, p, q);
4698 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4700 // TODO: this is expensive
4701 Expression p_tmp = new EmptyExpression (p);
4702 Expression q_tmp = new EmptyExpression (q);
4704 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4705 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4707 if (p_to_q && !q_to_p)
4710 if (q_to_p && !p_to_q)
4717 /// Determines "Better function" between candidate
4718 /// and the current best match
4721 /// Returns a boolean indicating :
4722 /// false if candidate ain't better
4723 /// true if candidate is better than the current best match
4725 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4726 MemberSpec best, AParametersCollection bparam, bool best_params)
4728 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4729 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4731 int candidate_better_count = 0;
4732 int best_better_count = 0;
4734 bool are_equivalent = true;
4735 int args_count = args == null ? 0 : args.Count;
4739 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4742 // Default arguments are ignored for better decision
4743 if (a.IsDefaultArgument)
4747 // When comparing named argument the parameter type index has to be looked up
4748 // in original parameter set (override version for virtual members)
4750 NamedArgument na = a as NamedArgument;
4752 int idx = cparam.GetParameterIndexByName (na.Name);
4753 ct = candidate_pd.Types[idx];
4754 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4755 ct = TypeManager.GetElementType (ct);
4757 idx = bparam.GetParameterIndexByName (na.Name);
4758 bt = best_pd.Types[idx];
4759 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4760 bt = TypeManager.GetElementType (bt);
4762 ct = candidate_pd.Types[c_idx];
4763 bt = best_pd.Types[b_idx];
4765 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4766 ct = TypeManager.GetElementType (ct);
4770 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4771 bt = TypeManager.GetElementType (bt);
4776 if (TypeSpecComparer.IsEqual (ct, bt))
4779 are_equivalent = false;
4780 int result = BetterExpressionConversion (ec, a, ct, bt);
4782 // for each argument, the conversion to 'ct' should be no worse than
4783 // the conversion to 'bt'.
4786 // No optional parameters tie breaking rules for delegates overload resolution
4788 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4791 ++best_better_count;
4795 // for at least one argument, the conversion to 'ct' should be better than
4796 // the conversion to 'bt'.
4798 ++candidate_better_count;
4801 if (candidate_better_count != 0 && best_better_count == 0)
4804 if (best_better_count > 0 && candidate_better_count == 0)
4808 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4810 if (!are_equivalent) {
4811 while (j < args_count && !args [j++].IsDefaultArgument) ;
4814 // A candidate with no default parameters is still better when there
4815 // is no better expression conversion and does not have more parameters
4817 if (candidate_pd.Count < best_pd.Count) {
4818 if (candidate_params)
4821 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4824 if (best_pd.FixedParameters [j].HasDefaultValue)
4827 } else if (candidate_pd.Count == best_pd.Count) {
4828 if (candidate_params)
4831 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4834 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4842 // If candidate is applicable in its normal form and best has a params array and is applicable
4843 // only in its expanded form, then candidate is better
4845 if (candidate_params != best_params)
4846 return !candidate_params;
4849 // We have not reached end of parameters list due to params or used default parameters
4851 bool defaults_ambiguity = false;
4852 while (j < candidate_pd.Count && j < best_pd.Count) {
4853 var cand_param = candidate_pd.FixedParameters [j];
4854 var best_param = best_pd.FixedParameters [j];
4856 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4857 return cand_param.HasDefaultValue;
4859 defaults_ambiguity = true;
4860 if (candidate_pd.Count == best_pd.Count) {
4864 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4865 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4867 if (cand_param.HasDefaultValue) {
4876 // Neither is better when not all arguments are provided
4878 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4879 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4880 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4885 if (candidate_pd.Count != best_pd.Count) {
4886 if (defaults_ambiguity && best_pd.Count - 1 == j)
4887 return best_pd.HasParams;
4889 return candidate_pd.Count < best_pd.Count;
4893 // One is a non-generic method and second is a generic method, then non-generic is better
4895 if (best.IsGeneric != candidate.IsGeneric)
4896 return best.IsGeneric;
4899 // Both methods have the same number of parameters, and the parameters have equal types
4900 // Pick the "more specific" signature using rules over original (non-inflated) types
4902 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4903 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4905 bool specific_at_least_once = false;
4906 for (j = 0; j < args_count; ++j) {
4907 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4909 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4910 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4912 ct = candidate_def_pd.Types[j];
4913 bt = best_def_pd.Types[j];
4918 TypeSpec specific = MoreSpecific (ct, bt);
4922 specific_at_least_once = true;
4925 if (specific_at_least_once)
4931 static bool CheckInflatedArguments (MethodSpec ms)
4933 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4936 // Setup constraint checker for probing only
4937 ConstraintChecker cc = new ConstraintChecker (null);
4939 var mp = ms.Parameters.Types;
4940 for (int i = 0; i < mp.Length; ++i) {
4941 var type = mp[i] as InflatedTypeSpec;
4945 var targs = type.TypeArguments;
4946 if (targs.Length == 0)
4949 // TODO: Checking inflated MVAR arguments should be enough
4950 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4957 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4959 rc.Report.Error (1729, loc,
4960 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4961 type.GetSignatureForError (), argCount.ToString ());
4965 // Determines if the candidate method is applicable to the given set of arguments
4966 // There could be two different set of parameters for same candidate where one
4967 // is the closest override for default values and named arguments checks and second
4968 // one being the virtual base for the parameter types and modifiers.
4970 // A return value rates candidate method compatibility,
4972 // 0 = the best, int.MaxValue = the worst
4974 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)
4977 // Each step has allocated 10 values, it can overflow for
4978 // more than 10 arguments but that's ok as it's used for
4979 // better error reporting only
4981 const int ArgumentCountMismatch = 1000000000;
4982 const int NamedArgumentsMismatch = 100000000;
4983 const int DefaultArgumentMismatch = 10000000;
4984 const int UnexpectedTypeArguments = 1000000;
4985 const int TypeArgumentsMismatch = 100000;
4986 const int InflatedTypesMismatch = 10000;
4988 // Parameters of most-derived type used mainly for named and optional parameters
4989 var pd = pm.Parameters;
4991 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4992 // params modifier instead of most-derived type
4993 var cpd = ((IParametersMember) candidate).Parameters;
4994 int param_count = pd.Count;
4995 int optional_count = 0;
4997 Arguments orig_args = arguments;
4999 if (arg_count != param_count) {
5001 // No arguments expansion when doing exact match for delegates
5003 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
5004 for (int i = 0; i < pd.Count; ++i) {
5005 if (pd.FixedParameters[i].HasDefaultValue) {
5006 optional_count = pd.Count - i;
5012 if (optional_count != 0) {
5013 // Readjust expected number when params used
5014 if (cpd.HasParams) {
5016 if (arg_count < param_count)
5018 } else if (arg_count > param_count) {
5019 int args_gap = System.Math.Abs (arg_count - param_count);
5020 return ArgumentCountMismatch + args_gap;
5021 } else if (arg_count < param_count - optional_count) {
5022 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5023 return ArgumentCountMismatch + args_gap;
5025 } else if (arg_count != param_count) {
5026 int args_gap = System.Math.Abs (arg_count - param_count);
5028 return ArgumentCountMismatch + args_gap;
5029 if (arg_count < param_count - 1)
5030 return ArgumentCountMismatch + args_gap;
5033 // Resize to fit optional arguments
5034 if (optional_count != 0) {
5035 if (arguments == null) {
5036 arguments = new Arguments (optional_count);
5038 // Have to create a new container, so the next run can do same
5039 var resized = new Arguments (param_count);
5040 resized.AddRange (arguments);
5041 arguments = resized;
5044 for (int i = arg_count; i < param_count; ++i)
5045 arguments.Add (null);
5049 if (arg_count > 0) {
5051 // Shuffle named arguments to the right positions if there are any
5053 if (arguments[arg_count - 1] is NamedArgument) {
5054 arg_count = arguments.Count;
5056 for (int i = 0; i < arg_count; ++i) {
5057 bool arg_moved = false;
5059 NamedArgument na = arguments[i] as NamedArgument;
5063 int index = pd.GetParameterIndexByName (na.Name);
5065 // Named parameter not found
5067 return NamedArgumentsMismatch - i;
5069 // already reordered
5074 if (index >= param_count) {
5075 // When using parameters which should not be available to the user
5076 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5079 arguments.Add (null);
5083 if (index == arg_count)
5084 return NamedArgumentsMismatch - i - 1;
5086 temp = arguments [index];
5088 // The slot has been taken by positional argument
5089 if (temp != null && !(temp is NamedArgument))
5090 return NamedArgumentsMismatch - i - 1;
5094 arguments = arguments.MarkOrderedArgument (na);
5098 if (arguments == orig_args) {
5099 arguments = new Arguments (orig_args.Count);
5100 arguments.AddRange (orig_args);
5103 arguments[index] = arguments[i];
5104 arguments[i] = temp;
5111 arg_count = arguments.Count;
5113 } else if (arguments != null) {
5114 arg_count = arguments.Count;
5118 // Don't do any expensive checks when the candidate cannot succeed
5120 if (arg_count != param_count && !cpd.HasParams)
5121 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5123 var dep = candidate.GetMissingDependencies ();
5125 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5130 // 1. Handle generic method using type arguments when specified or type inference
5133 var ms = candidate as MethodSpec;
5134 if (ms != null && ms.IsGeneric) {
5135 if (type_arguments != null) {
5136 var g_args_count = ms.Arity;
5137 if (g_args_count != type_arguments.Count)
5138 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5140 if (type_arguments.Arguments != null)
5141 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5144 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5145 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5146 // candidate was found use the set to report more details about what was wrong with lambda body.
5147 // The general idea is to distinguish between code errors and errors caused by
5148 // trial-and-error type inference
5150 if (lambda_conv_msgs == null) {
5151 for (int i = 0; i < arg_count; i++) {
5152 Argument a = arguments[i];
5156 var am = a.Expr as AnonymousMethodExpression;
5158 if (lambda_conv_msgs == null)
5159 lambda_conv_msgs = new SessionReportPrinter ();
5161 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5166 var ti = new TypeInference (arguments);
5167 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5170 return TypeArgumentsMismatch - ti.InferenceScore;
5173 // Clear any error messages when the result was success
5175 if (lambda_conv_msgs != null)
5176 lambda_conv_msgs.ClearSession ();
5178 if (i_args.Length != 0) {
5180 for (int i = 0; i < i_args.Length; ++i) {
5181 var ta = i_args [i];
5182 if (!ta.IsAccessible (ec))
5183 return TypeArgumentsMismatch - i;
5187 ms = ms.MakeGenericMethod (ec, i_args);
5192 // Type arguments constraints have to match for the method to be applicable
5194 if (!CheckInflatedArguments (ms)) {
5196 return InflatedTypesMismatch;
5200 // We have a generic return type and at same time the method is override which
5201 // means we have to also inflate override return type in case the candidate is
5202 // best candidate and override return type is different to base return type.
5204 // virtual Foo<T, object> with override Foo<T, dynamic>
5206 if (candidate != pm) {
5207 MethodSpec override_ms = (MethodSpec) pm;
5208 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5209 returnType = inflator.Inflate (returnType);
5211 returnType = ms.ReturnType;
5218 if (type_arguments != null)
5219 return UnexpectedTypeArguments;
5225 // 2. Each argument has to be implicitly convertible to method parameter
5227 Parameter.Modifier p_mod = 0;
5230 for (int i = 0; i < arg_count; i++) {
5231 Argument a = arguments[i];
5233 var fp = pd.FixedParameters[i];
5234 if (!fp.HasDefaultValue) {
5235 arguments = orig_args;
5236 return arg_count * 2 + 2;
5240 // Get the default value expression, we can use the same expression
5241 // if the type matches
5243 Expression e = fp.DefaultValue;
5245 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5247 // Restore for possible error reporting
5248 for (int ii = i; ii < arg_count; ++ii)
5249 arguments.RemoveAt (i);
5251 return (arg_count - i) * 2 + 1;
5255 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5257 // LAMESPEC: Attributes can be mixed together with build-in priority
5259 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5260 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5261 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5262 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5263 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5264 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5268 arguments[i] = new Argument (e, Argument.AType.Default);
5272 if (p_mod != Parameter.Modifier.PARAMS) {
5273 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5275 } else if (!params_expanded_form) {
5276 params_expanded_form = true;
5277 pt = ((ElementTypeSpec) pt).Element;
5283 if (!params_expanded_form) {
5284 if (a.IsExtensionType) {
5285 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5290 score = IsArgumentCompatible (ec, a, p_mod, pt);
5293 dynamicArgument = true;
5298 // It can be applicable in expanded form (when not doing exact match like for delegates)
5300 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5301 if (!params_expanded_form) {
5302 pt = ((ElementTypeSpec) pt).Element;
5306 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5309 params_expanded_form = true;
5310 dynamicArgument = true;
5311 } else if (score == 0 || arg_count > pd.Count) {
5312 params_expanded_form = true;
5317 if (params_expanded_form)
5319 return (arg_count - i) * 2 + score;
5324 // Restore original arguments for dynamic binder to keep the intention of original source code
5326 if (dynamicArgument)
5327 arguments = orig_args;
5332 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5334 if (e is Constant && e.Type == ptype)
5338 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5340 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5341 e = new MemberAccess (new MemberAccess (new MemberAccess (
5342 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5343 } else if (e is Constant) {
5345 // Handles int to int? conversions, DefaultParameterValue check
5347 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5351 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5354 return e.Resolve (ec);
5358 // Tests argument compatibility with the parameter
5359 // The possible return values are
5361 // 1 - modifier mismatch
5362 // 2 - type mismatch
5363 // -1 - dynamic binding required
5365 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5368 // Types have to be identical when ref or out modifer
5369 // is used and argument is not of dynamic type
5371 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5372 var arg_type = argument.Type;
5374 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5376 // Using dynamic for ref/out parameter can still succeed at runtime
5378 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5384 if (arg_type != parameter) {
5385 if (arg_type == InternalType.VarOutType)
5389 // Do full equality check after quick path
5391 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5393 // Using dynamic for ref/out parameter can still succeed at runtime
5395 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5403 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5407 // Use implicit conversion in all modes to return same candidates when the expression
5408 // is used as argument or delegate conversion
5410 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5411 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5418 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5420 if (p.IsGenericParameter != q.IsGenericParameter)
5421 return p.IsGenericParameter ? q : p;
5423 var ac_p = p as ArrayContainer;
5425 var ac_q = q as ArrayContainer;
5429 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5430 if (specific == ac_p.Element)
5432 if (specific == ac_q.Element)
5438 if (p.IsGeneric && q.IsGeneric) {
5439 var pargs = p.TypeArguments;
5440 var qargs = q.TypeArguments;
5442 bool p_specific_at_least_once = false;
5443 bool q_specific_at_least_once = false;
5445 for (int i = 0; i < pargs.Length; i++) {
5446 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5447 if (specific == pargs [i])
5448 p_specific_at_least_once = true;
5449 if (specific == qargs [i])
5450 q_specific_at_least_once = true;
5453 if (p_specific_at_least_once && !q_specific_at_least_once)
5455 if (!p_specific_at_least_once && q_specific_at_least_once)
5463 // Find the best method from candidate list
5465 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5467 List<AmbiguousCandidate> ambiguous_candidates = null;
5469 MemberSpec best_candidate;
5470 Arguments best_candidate_args = null;
5471 bool best_candidate_params = false;
5472 bool best_candidate_dynamic = false;
5473 int best_candidate_rate;
5474 IParametersMember best_parameter_member = null;
5476 int args_count = args != null ? args.Count : 0;
5478 Arguments candidate_args = args;
5479 bool error_mode = false;
5480 MemberSpec invocable_member = null;
5481 int applicable_candidates = 0;
5484 best_candidate = null;
5485 best_candidate_rate = int.MaxValue;
5487 var type_members = members;
5489 for (int i = 0; i < type_members.Count; ++i) {
5490 var member = type_members[i];
5493 // Methods in a base class are not candidates if any method in a derived
5494 // class is applicable
5496 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5500 if (!member.IsAccessible (rc))
5503 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5506 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5507 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5512 IParametersMember pm = member as IParametersMember;
5515 // Will use it later to report ambiguity between best method and invocable member
5517 if (Invocation.IsMemberInvocable (member))
5518 invocable_member = member;
5524 // Overload resolution is looking for base member but using parameter names
5525 // and default values from the closest member. That means to do expensive lookup
5526 // for the closest override for virtual or abstract members
5528 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5529 var override_params = base_provider.GetOverrideMemberParameters (member);
5530 if (override_params != null)
5531 pm = override_params;
5535 // Check if the member candidate is applicable
5537 bool params_expanded_form = false;
5538 bool dynamic_argument = false;
5539 TypeSpec rt = pm.MemberType;
5540 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5542 if (lambda_conv_msgs != null)
5543 lambda_conv_msgs.EndSession ();
5546 // How does it score compare to others
5548 if (candidate_rate < best_candidate_rate) {
5550 // Fatal error (missing dependency), cannot continue
5551 if (candidate_rate < 0)
5554 applicable_candidates = 1;
5555 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5556 // Only parameterless methods are considered
5558 best_candidate_rate = candidate_rate;
5559 best_candidate = member;
5560 best_candidate_args = candidate_args;
5561 best_candidate_params = params_expanded_form;
5562 best_candidate_dynamic = dynamic_argument;
5563 best_parameter_member = pm;
5564 best_candidate_return_type = rt;
5566 } else if (candidate_rate == 0) {
5568 // The member look is done per type for most operations but sometimes
5569 // it's not possible like for binary operators overload because they
5570 // are unioned between 2 sides
5572 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5573 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5577 ++applicable_candidates;
5579 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5581 // We pack all interface members into top level type which makes the overload resolution
5582 // more complicated for interfaces. We compensate it by removing methods with same
5583 // signature when building the cache hence this path should not really be hit often
5586 // interface IA { void Foo (int arg); }
5587 // interface IB : IA { void Foo (params int[] args); }
5589 // IB::Foo is the best overload when calling IB.Foo (1)
5592 if (ambiguous_candidates != null) {
5593 foreach (var amb_cand in ambiguous_candidates) {
5594 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5603 ambiguous_candidates = null;
5606 // Is the new candidate better
5607 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5611 best_candidate = member;
5612 best_candidate_args = candidate_args;
5613 best_candidate_params = params_expanded_form;
5614 best_candidate_dynamic = dynamic_argument;
5615 best_parameter_member = pm;
5616 best_candidate_return_type = rt;
5618 // It's not better but any other found later could be but we are not sure yet
5619 if (ambiguous_candidates == null)
5620 ambiguous_candidates = new List<AmbiguousCandidate> ();
5622 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5626 // Restore expanded arguments
5627 candidate_args = args;
5629 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5632 // We've found exact match
5634 if (best_candidate_rate == 0)
5638 // Try extension methods lookup when no ordinary method match was found and provider enables it
5641 var emg = base_provider.LookupExtensionMethod (rc);
5643 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5645 best_candidate_extension_group = emg;
5646 return (T) (MemberSpec) emg.BestCandidate;
5651 // Don't run expensive error reporting mode for probing
5658 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5661 lambda_conv_msgs = null;
5666 // No best member match found, report an error
5668 if (best_candidate_rate != 0 || error_mode) {
5669 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5673 if (best_candidate_dynamic) {
5674 if (args[0].IsExtensionType) {
5675 rc.Report.Error (1973, loc,
5676 "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",
5677 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5681 // Check type constraints only when explicit type arguments are used
5683 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5684 MethodSpec bc = best_candidate as MethodSpec;
5685 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5686 ConstraintChecker cc = new ConstraintChecker (rc);
5687 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5691 BestCandidateIsDynamic = true;
5696 // These flags indicates we are running delegate probing conversion. No need to
5697 // do more expensive checks
5699 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5700 return (T) best_candidate;
5702 if (ambiguous_candidates != null) {
5704 // Now check that there are no ambiguities i.e the selected method
5705 // should be better than all the others
5707 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5708 var candidate = ambiguous_candidates [ix];
5710 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5711 var ambiguous = candidate.Member;
5712 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5713 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5714 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5715 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5716 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5719 return (T) best_candidate;
5724 if (invocable_member != null && !IsProbingOnly) {
5725 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5726 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5727 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5728 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5732 // And now check if the arguments are all
5733 // compatible, perform conversions if
5734 // necessary etc. and return if everything is
5737 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5740 if (best_candidate == null)
5744 // Don't run possibly expensive checks in probing mode
5746 if (!IsProbingOnly && !rc.IsInProbingMode) {
5748 // Check ObsoleteAttribute on the best method
5750 best_candidate.CheckObsoleteness (rc, loc);
5752 best_candidate.MemberDefinition.SetIsUsed ();
5755 args = best_candidate_args;
5756 return (T) best_candidate;
5759 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5761 return ResolveMember<MethodSpec> (rc, ref args);
5764 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5765 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5767 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5770 if (a.Type == InternalType.ErrorType)
5773 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5774 ec.Report.SymbolRelatedToPreviousError (method);
5775 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5776 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5777 TypeManager.CSharpSignature (method));
5780 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5781 TypeManager.CSharpSignature (method));
5782 } else if (IsDelegateInvoke) {
5783 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5784 DelegateType.GetSignatureForError ());
5786 ec.Report.SymbolRelatedToPreviousError (method);
5787 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5788 method.GetSignatureForError ());
5791 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5793 string index = (idx + 1).ToString ();
5794 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5795 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5796 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5797 index, Parameter.GetModifierSignature (a.Modifier));
5799 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5800 index, Parameter.GetModifierSignature (mod));
5802 string p1 = a.GetSignatureForError ();
5803 string p2 = paramType.GetSignatureForError ();
5806 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5807 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5810 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5811 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5812 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5815 ec.Report.Error (1503, a.Expr.Location,
5816 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5821 // We have failed to find exact match so we return error info about the closest match
5823 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5825 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5826 int arg_count = args == null ? 0 : args.Count;
5828 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5829 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5830 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5834 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5839 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5840 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5841 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5845 // For candidates which match on parameters count report more details about incorrect arguments
5848 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5849 // Reject any inaccessible member
5850 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5851 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5852 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5856 var ms = best_candidate as MethodSpec;
5857 if (ms != null && ms.IsGeneric) {
5858 bool constr_ok = true;
5859 if (ms.TypeArguments != null)
5860 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5862 if (ta_count == 0 && ms.TypeArguments == null) {
5863 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5867 rc.Report.Error (411, loc,
5868 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5869 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5876 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5882 // We failed to find any method with correct argument count, report best candidate
5884 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5887 if (best_candidate.Kind == MemberKind.Constructor) {
5888 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5889 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5890 } else if (IsDelegateInvoke) {
5891 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5892 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5893 DelegateType.GetSignatureForError (), arg_count.ToString ());
5895 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5896 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5897 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5898 name, arg_count.ToString ());
5902 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5904 var p = ((IParametersMember)best_candidate).Parameters;
5909 for (int i = p.Count - 1; i != 0; --i) {
5910 var fp = p.FixedParameters [i];
5911 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5921 foreach (var arg in args) {
5922 var na = arg as NamedArgument;
5926 if (na.Name == name) {
5935 return args.Count + 1 == pm.Parameters.Count;
5938 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5940 var pd = pm.Parameters;
5941 var cpd = ((IParametersMember) member).Parameters;
5942 var ptypes = cpd.Types;
5944 Parameter.Modifier p_mod = 0;
5946 int a_idx = 0, a_pos = 0;
5948 ArrayInitializer params_initializers = null;
5949 bool has_unsafe_arg = pm.MemberType.IsPointer;
5950 int arg_count = args == null ? 0 : args.Count;
5952 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5957 if (p_mod != Parameter.Modifier.PARAMS) {
5958 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5960 has_unsafe_arg |= pt.IsPointer;
5962 if (p_mod == Parameter.Modifier.PARAMS) {
5963 if (chose_params_expanded) {
5964 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5965 pt = TypeManager.GetElementType (pt);
5971 // Types have to be identical when ref or out modifer is used
5973 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5974 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5977 var arg_type = a.Type;
5981 if (arg_type == InternalType.VarOutType) {
5983 // Set underlying variable type based on parameter type
5985 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5989 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5993 NamedArgument na = a as NamedArgument;
5995 int name_index = pd.GetParameterIndexByName (na.Name);
5996 if (name_index < 0 || name_index >= pd.Count) {
5997 if (IsDelegateInvoke) {
5998 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5999 ec.Report.Error (1746, na.Location,
6000 "The delegate `{0}' does not contain a parameter named `{1}'",
6001 DelegateType.GetSignatureForError (), na.Name);
6003 ec.Report.SymbolRelatedToPreviousError (member);
6004 ec.Report.Error (1739, na.Location,
6005 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
6006 TypeManager.CSharpSignature (member), na.Name);
6008 } else if (args[name_index] != a && args[name_index] != null) {
6009 if (IsDelegateInvoke)
6010 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6012 ec.Report.SymbolRelatedToPreviousError (member);
6014 ec.Report.Error (1744, na.Location,
6015 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6020 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6023 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6024 if (a.IsExtensionType) {
6025 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6026 // CS1061 but that still better than confusing CS0123
6027 var ma = new MemberAccess (a.Expr, member.Name, loc);
6028 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6030 custom_errors.NoArgumentMatch (ec, member);
6036 if (a.IsExtensionType) {
6037 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6040 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6042 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6045 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6052 // Convert params arguments to an array initializer
6054 if (params_initializers != null) {
6055 // we choose to use 'a.Expr' rather than 'conv' so that
6056 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6057 params_initializers.Add (a.Expr);
6058 args.RemoveAt (a_idx--);
6064 // Update the argument with the implicit conversion
6068 if (a_idx != arg_count) {
6070 // Convert all var out argument to error type for less confusing error reporting
6071 // when no matching overload is found
6073 for (; a_idx < arg_count; a_idx++) {
6074 var arg = args [a_idx];
6078 if (arg.Type == InternalType.VarOutType) {
6079 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6083 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6088 // Fill not provided arguments required by params modifier
6090 if (params_initializers == null && arg_count + 1 == pd.Count) {
6092 args = new Arguments (1);
6094 pt = ptypes[pd.Count - 1];
6095 pt = TypeManager.GetElementType (pt);
6096 has_unsafe_arg |= pt.IsPointer;
6097 params_initializers = new ArrayInitializer (0, loc);
6101 // Append an array argument with all params arguments
6103 if (params_initializers != null) {
6104 args.Add (new Argument (
6105 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6109 if (has_unsafe_arg) {
6110 if (ec.CurrentIterator != null) {
6111 Expression.UnsafeInsideIteratorError (ec, loc);
6112 } else if (!ec.IsUnsafe) {
6113 Expression.UnsafeError (ec, loc);
6118 // We could infer inaccesible type arguments
6120 if (type_arguments == null && member.IsGeneric) {
6121 var ms = (MethodSpec) member;
6122 foreach (var ta in ms.TypeArguments) {
6123 if (!ta.IsAccessible (ec)) {
6124 ec.Report.SymbolRelatedToPreviousError (ta);
6125 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6135 public class ConstantExpr : MemberExpr
6137 readonly ConstSpec constant;
6139 public ConstantExpr (ConstSpec constant, Location loc)
6141 this.constant = constant;
6145 public override string Name {
6146 get { throw new NotImplementedException (); }
6149 public override string KindName {
6150 get { return "constant"; }
6153 public override bool IsInstance {
6154 get { return !IsStatic; }
6157 public override bool IsStatic {
6158 get { return true; }
6161 protected override TypeSpec DeclaringType {
6162 get { return constant.DeclaringType; }
6165 public override Expression CreateExpressionTree (ResolveContext ec)
6167 throw new NotSupportedException ("ET");
6170 protected override Expression DoResolve (ResolveContext rc)
6172 ResolveInstanceExpression (rc, null);
6173 DoBestMemberChecks (rc, constant);
6175 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6176 eclass = ExprClass.Value;
6177 type = constant.MemberType;
6181 var c = constant.GetConstant (rc);
6183 // Creates reference expression to the constant value
6184 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6187 public override void Emit (EmitContext ec)
6189 throw new NotSupportedException ();
6192 public override string GetSignatureForError ()
6194 return constant.GetSignatureForError ();
6197 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6199 constant.CheckObsoleteness (rc, expr.Location);
6202 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6204 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6209 // Fully resolved expression that references a Field
6211 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6213 protected FieldSpec spec;
6214 VariableInfo variable_info;
6216 LocalTemporary temp;
6219 protected FieldExpr (Location l)
6224 public FieldExpr (FieldSpec spec, Location loc)
6229 type = spec.MemberType;
6232 public FieldExpr (FieldBase fi, Location l)
6239 public override string Name {
6245 public bool IsHoisted {
6247 IVariableReference hv = InstanceExpression as IVariableReference;
6248 return hv != null && hv.IsHoisted;
6252 public override bool IsInstance {
6254 return !spec.IsStatic;
6258 public override bool IsStatic {
6260 return spec.IsStatic;
6264 public override string KindName {
6265 get { return "field"; }
6268 public FieldSpec Spec {
6274 protected override TypeSpec DeclaringType {
6276 return spec.DeclaringType;
6280 public VariableInfo VariableInfo {
6282 return variable_info;
6288 public override string GetSignatureForError ()
6290 return spec.GetSignatureForError ();
6293 public bool IsMarshalByRefAccess (ResolveContext rc)
6295 // Checks possible ldflda of field access expression
6296 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6297 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6298 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6301 public void SetHasAddressTaken ()
6303 IVariableReference vr = InstanceExpression as IVariableReference;
6305 vr.SetHasAddressTaken ();
6309 protected override void CloneTo (CloneContext clonectx, Expression target)
6311 var t = (FieldExpr) target;
6313 if (InstanceExpression != null)
6314 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6317 public override Expression CreateExpressionTree (ResolveContext ec)
6319 if (ConditionalAccess) {
6320 Error_NullShortCircuitInsideExpressionTree (ec);
6323 return CreateExpressionTree (ec, true);
6326 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6329 Expression instance;
6331 if (InstanceExpression == null) {
6332 instance = new NullLiteral (loc);
6333 } else if (convertInstance) {
6334 instance = InstanceExpression.CreateExpressionTree (ec);
6336 args = new Arguments (1);
6337 args.Add (new Argument (InstanceExpression));
6338 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6341 args = Arguments.CreateForExpressionTree (ec, null,
6343 CreateTypeOfExpression ());
6345 return CreateExpressionFactoryCall (ec, "Field", args);
6348 public Expression CreateTypeOfExpression ()
6350 return new TypeOfField (spec, loc);
6353 protected override Expression DoResolve (ResolveContext ec)
6355 spec.MemberDefinition.SetIsUsed ();
6357 return DoResolve (ec, null);
6360 Expression DoResolve (ResolveContext ec, Expression rhs)
6362 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6365 ResolveConditionalAccessReceiver (ec);
6367 if (ResolveInstanceExpression (ec, rhs)) {
6368 // Resolve the field's instance expression while flow analysis is turned
6369 // off: when accessing a field "a.b", we must check whether the field
6370 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6372 if (lvalue_instance) {
6373 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6375 Expression right_side =
6376 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6378 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6380 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6383 if (InstanceExpression == null)
6387 DoBestMemberChecks (ec, spec);
6389 if (conditional_access_receiver)
6390 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6393 var fb = spec as FixedFieldSpec;
6394 IVariableReference var = InstanceExpression as IVariableReference;
6397 IFixedExpression fe = InstanceExpression as IFixedExpression;
6398 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6399 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6402 if (InstanceExpression.eclass != ExprClass.Variable) {
6403 ec.Report.SymbolRelatedToPreviousError (spec);
6404 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6405 TypeManager.GetFullNameSignature (spec));
6406 } else if (var != null && var.IsHoisted) {
6407 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6410 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6414 // Set flow-analysis variable info for struct member access. It will be check later
6415 // for precise error reporting
6417 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6418 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6421 if (conditional_access_receiver)
6422 type = LiftMemberType (ec, type);
6424 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6425 return Constant.CreateConstantFromValue (type, null, loc);
6427 eclass = ExprClass.Variable;
6431 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6433 spec.CheckObsoleteness (rc, expr.Location);
6436 public void SetFieldAssigned (FlowAnalysisContext fc)
6441 bool lvalue_instance = spec.DeclaringType.IsStruct;
6442 if (lvalue_instance) {
6443 var var = InstanceExpression as IVariableReference;
6444 if (var != null && var.VariableInfo != null) {
6445 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6449 var fe = InstanceExpression as FieldExpr;
6451 Expression instance;
6454 instance = fe.InstanceExpression;
6455 var fe_instance = instance as FieldExpr;
6456 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6457 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6458 var var = InstanceExpression as IVariableReference;
6459 if (var != null && var.VariableInfo == null) {
6460 var var_inst = instance as IVariableReference;
6461 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6462 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6466 if (fe_instance != null) {
6475 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6476 instance.FlowAnalysis (fc);
6478 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6479 InstanceExpression.FlowAnalysis (fc);
6483 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6485 // The return value is always null. Returning a value simplifies calling code.
6487 if (right_side == EmptyExpression.OutAccess) {
6489 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6490 GetSignatureForError ());
6492 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6493 GetSignatureForError ());
6499 if (right_side == EmptyExpression.LValueMemberAccess) {
6500 // Already reported as CS1648/CS1650
6504 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6506 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6507 GetSignatureForError ());
6509 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6510 GetSignatureForError ());
6516 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6517 GetSignatureForError ());
6519 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6520 GetSignatureForError ());
6526 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6528 if (HasConditionalAccess ())
6529 Error_NullPropagatingLValue (ec);
6531 if (spec is FixedFieldSpec) {
6532 // It could be much better error message but we want to be error compatible
6533 Error_ValueAssignment (ec, right_side);
6536 Expression e = DoResolve (ec, right_side);
6541 spec.MemberDefinition.SetIsAssigned ();
6543 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6544 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6545 ec.Report.Warning (420, 1, loc,
6546 "`{0}': A volatile field references will not be treated as volatile",
6547 spec.GetSignatureForError ());
6550 if (spec.IsReadOnly) {
6551 // InitOnly fields can only be assigned in constructors or initializers
6552 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6553 return Error_AssignToReadonly (ec, right_side);
6555 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6557 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6558 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6559 return Error_AssignToReadonly (ec, right_side);
6560 // static InitOnly fields cannot be assigned-to in an instance constructor
6561 if (IsStatic && !ec.IsStatic)
6562 return Error_AssignToReadonly (ec, right_side);
6563 // instance constructors can't modify InitOnly fields of other instances of the same type
6564 if (!IsStatic && !(InstanceExpression is This))
6565 return Error_AssignToReadonly (ec, right_side);
6569 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6570 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6571 ec.Report.Warning (197, 1, loc,
6572 "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",
6573 GetSignatureForError ());
6576 eclass = ExprClass.Variable;
6580 public override void FlowAnalysis (FlowAnalysisContext fc)
6582 var var = InstanceExpression as IVariableReference;
6584 var vi = var.VariableInfo;
6585 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6586 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6590 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6591 var le = SkipLeftValueTypeAccess (InstanceExpression);
6593 le.FlowAnalysis (fc);
6599 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6601 base.FlowAnalysis (fc);
6603 if (conditional_access_receiver)
6604 fc.DefiniteAssignment = da;
6607 static Expression SkipLeftValueTypeAccess (Expression expr)
6609 if (!TypeSpec.IsValueType (expr.Type))
6612 if (expr is VariableReference)
6615 var fe = expr as FieldExpr;
6619 if (fe.InstanceExpression == null)
6622 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6625 public override int GetHashCode ()
6627 return spec.GetHashCode ();
6630 public bool IsFixed {
6633 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6635 IVariableReference variable = InstanceExpression as IVariableReference;
6636 if (variable != null)
6637 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6639 IFixedExpression fe = InstanceExpression as IFixedExpression;
6640 return fe != null && fe.IsFixed;
6644 public override bool Equals (object obj)
6646 FieldExpr fe = obj as FieldExpr;
6650 if (spec != fe.spec)
6653 if (InstanceExpression == null || fe.InstanceExpression == null)
6656 return InstanceExpression.Equals (fe.InstanceExpression);
6659 public void Emit (EmitContext ec, bool leave_copy)
6661 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6665 ec.Emit (OpCodes.Volatile);
6667 ec.Emit (OpCodes.Ldsfld, spec);
6669 var ca = ec.ConditionalAccess;
6672 if (conditional_access_receiver)
6673 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6675 EmitInstance (ec, false);
6678 // Optimization for build-in types
6679 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6680 ec.EmitLoadFromPtr (type);
6682 var ff = spec as FixedFieldSpec;
6684 ec.Emit (OpCodes.Ldflda, spec);
6685 ec.Emit (OpCodes.Ldflda, ff.Element);
6688 ec.Emit (OpCodes.Volatile);
6690 ec.Emit (OpCodes.Ldfld, spec);
6694 if (conditional_access_receiver) {
6695 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6696 ec.ConditionalAccess = ca;
6701 ec.Emit (OpCodes.Dup);
6703 temp = new LocalTemporary (this.Type);
6709 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6711 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6712 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6717 if (ConditionalAccess)
6718 throw new NotImplementedException ("null operator assignment");
6720 if (has_await_source)
6721 source = source.EmitToField (ec);
6723 EmitInstance (ec, prepared);
6728 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6729 ec.Emit (OpCodes.Dup);
6731 temp = new LocalTemporary (this.Type);
6736 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6737 ec.Emit (OpCodes.Volatile);
6739 spec.MemberDefinition.SetIsAssigned ();
6742 ec.Emit (OpCodes.Stsfld, spec);
6744 ec.Emit (OpCodes.Stfld, spec);
6746 if (ec.NotifyEvaluatorOnStore) {
6748 throw new NotImplementedException ("instance field write");
6751 ec.Emit (OpCodes.Dup);
6753 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6764 // Emits store to field with prepared values on stack
6766 public void EmitAssignFromStack (EmitContext ec)
6769 ec.Emit (OpCodes.Stsfld, spec);
6771 ec.Emit (OpCodes.Stfld, spec);
6775 public override void Emit (EmitContext ec)
6780 public override void EmitSideEffect (EmitContext ec)
6782 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6784 if (is_volatile) // || is_marshal_by_ref ())
6785 base.EmitSideEffect (ec);
6788 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6790 if ((mode & AddressOp.Store) != 0)
6791 spec.MemberDefinition.SetIsAssigned ();
6792 if ((mode & AddressOp.Load) != 0)
6793 spec.MemberDefinition.SetIsUsed ();
6796 // Handle initonly fields specially: make a copy and then
6797 // get the address of the copy.
6800 if (spec.IsReadOnly){
6802 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6814 var temp = ec.GetTemporaryLocal (type);
6815 ec.Emit (OpCodes.Stloc, temp);
6816 ec.Emit (OpCodes.Ldloca, temp);
6822 ec.Emit (OpCodes.Ldsflda, spec);
6825 EmitInstance (ec, false);
6826 ec.Emit (OpCodes.Ldflda, spec);
6830 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6832 return MakeExpression (ctx);
6835 public override SLE.Expression MakeExpression (BuilderContext ctx)
6838 return base.MakeExpression (ctx);
6840 return SLE.Expression.Field (
6841 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6842 spec.GetMetaInfo ());
6846 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6848 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6854 // Expression that evaluates to a Property.
6856 // This is not an LValue because we need to re-write the expression. We
6857 // can not take data from the stack and store it.
6859 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6861 Arguments arguments;
6862 FieldExpr backing_field;
6864 public PropertyExpr (PropertySpec spec, Location l)
6867 best_candidate = spec;
6868 type = spec.MemberType;
6873 protected override Arguments Arguments {
6882 protected override TypeSpec DeclaringType {
6884 return best_candidate.DeclaringType;
6888 public override string Name {
6890 return best_candidate.Name;
6894 public bool IsAutoPropertyAccess {
6896 var prop = best_candidate.MemberDefinition as Property;
6897 return prop != null && prop.BackingField != null;
6901 public override bool IsInstance {
6907 public override bool IsStatic {
6909 return best_candidate.IsStatic;
6913 public override string KindName {
6914 get { return "property"; }
6917 public PropertySpec PropertyInfo {
6919 return best_candidate;
6925 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6927 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6930 var args_count = arguments == null ? 0 : arguments.Count;
6931 if (args_count != body.Parameters.Count && args_count == 0)
6934 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6935 mg.InstanceExpression = InstanceExpression;
6940 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6942 return new PropertyExpr (spec, loc) {
6948 public override Expression CreateExpressionTree (ResolveContext ec)
6950 if (ConditionalAccess) {
6951 Error_NullShortCircuitInsideExpressionTree (ec);
6955 if (IsSingleDimensionalArrayLength ()) {
6956 args = new Arguments (1);
6957 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6958 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6961 args = new Arguments (2);
6962 if (InstanceExpression == null)
6963 args.Add (new Argument (new NullLiteral (loc)));
6965 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6966 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6967 return CreateExpressionFactoryCall (ec, "Property", args);
6970 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6972 DoResolveLValue (rc, null);
6973 return new TypeOfMethod (Setter, loc);
6976 public override string GetSignatureForError ()
6978 return best_candidate.GetSignatureForError ();
6981 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6984 return base.MakeExpression (ctx);
6986 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6990 public override SLE.Expression MakeExpression (BuilderContext ctx)
6993 return base.MakeExpression (ctx);
6995 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6999 void Error_PropertyNotValid (ResolveContext ec)
7001 ec.Report.SymbolRelatedToPreviousError (best_candidate);
7002 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
7003 GetSignatureForError ());
7006 bool IsSingleDimensionalArrayLength ()
7008 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7011 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7012 return ac != null && ac.Rank == 1;
7015 public override void Emit (EmitContext ec, bool leave_copy)
7018 // Special case: length of single dimension array property is turned into ldlen
7020 if (IsSingleDimensionalArrayLength ()) {
7021 if (conditional_access_receiver) {
7022 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7025 EmitInstance (ec, false);
7027 ec.Emit (OpCodes.Ldlen);
7028 ec.Emit (OpCodes.Conv_I4);
7030 if (conditional_access_receiver) {
7031 ec.CloseConditionalAccess (type);
7037 base.Emit (ec, leave_copy);
7040 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7042 if (backing_field != null) {
7043 backing_field.EmitAssign (ec, source, leave_copy, false);
7048 LocalTemporary await_source_arg = null;
7050 if (isCompound && !(source is DynamicExpressionStatement)) {
7051 emitting_compound_assignment = true;
7054 if (has_await_arguments) {
7055 await_source_arg = new LocalTemporary (Type);
7056 await_source_arg.Store (ec);
7058 args = new Arguments (1);
7059 args.Add (new Argument (await_source_arg));
7062 temp = await_source_arg;
7065 has_await_arguments = false;
7070 ec.Emit (OpCodes.Dup);
7071 temp = new LocalTemporary (this.Type);
7076 args = arguments ?? new Arguments (1);
7080 temp = new LocalTemporary (this.Type);
7082 args.Add (new Argument (temp));
7084 args.Add (new Argument (source));
7088 emitting_compound_assignment = false;
7090 var call = new CallEmitter ();
7091 call.InstanceExpression = InstanceExpression;
7093 call.InstanceExpressionOnStack = true;
7095 if (ConditionalAccess) {
7096 call.ConditionalAccess = true;
7100 call.Emit (ec, Setter, args, loc);
7102 call.EmitStatement (ec, Setter, args, loc);
7109 if (await_source_arg != null) {
7110 await_source_arg.Release (ec);
7114 public override void FlowAnalysis (FlowAnalysisContext fc)
7116 var prop = best_candidate.MemberDefinition as Property;
7117 if (prop != null && prop.BackingField != null) {
7118 var var = InstanceExpression as IVariableReference;
7120 var vi = var.VariableInfo;
7121 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7122 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7126 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7131 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7133 base.FlowAnalysis (fc);
7135 if (conditional_access_receiver)
7136 fc.DefiniteAssignment = da;
7139 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7141 eclass = ExprClass.PropertyAccess;
7143 if (best_candidate.IsNotCSharpCompatible) {
7144 Error_PropertyNotValid (rc);
7147 ResolveInstanceExpression (rc, right_side);
7149 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7150 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7151 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7153 type = p.MemberType;
7157 DoBestMemberChecks (rc, best_candidate);
7159 // Handling of com-imported properties with any number of default property parameters
7160 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7161 var p = best_candidate.Get.Parameters;
7162 arguments = new Arguments (p.Count);
7163 for (int i = 0; i < p.Count; ++i) {
7164 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7166 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7167 var p = best_candidate.Set.Parameters;
7168 arguments = new Arguments (p.Count - 1);
7169 for (int i = 0; i < p.Count - 1; ++i) {
7170 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7177 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7179 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7182 var prop = best_candidate.MemberDefinition as Property;
7183 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7184 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7188 prop = (Property)ps.MemberDefinition;
7191 var spec = prop.BackingField;
7195 if (rc.IsStatic != spec.IsStatic)
7198 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7201 backing_field = new FieldExpr (prop.BackingField, loc);
7202 backing_field.ResolveLValue (rc, rhs);
7206 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7208 if (!best_candidate.IsAccessible (rc))
7209 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7211 best_candidate.CheckObsoleteness (rc, expr.Location);
7214 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7216 if (backing_field != null) {
7217 backing_field.SetFieldAssigned (fc);
7221 if (!IsAutoPropertyAccess)
7224 var prop = best_candidate.MemberDefinition as Property;
7225 if (prop != null && prop.BackingField != null) {
7226 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7227 if (lvalue_instance) {
7228 var var = InstanceExpression as IVariableReference;
7229 if (var != null && var.VariableInfo != null) {
7230 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7236 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7238 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7242 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7244 // getter and setter can be different for base calls
7245 MethodSpec getter, setter;
7246 protected T best_candidate;
7248 protected LocalTemporary temp;
7249 protected bool emitting_compound_assignment;
7250 protected bool has_await_arguments;
7252 protected PropertyOrIndexerExpr (Location l)
7259 protected abstract Arguments Arguments { get; set; }
7261 public MethodSpec Getter {
7270 public MethodSpec Setter {
7281 protected override Expression DoResolve (ResolveContext ec)
7283 if (eclass == ExprClass.Unresolved) {
7284 ResolveConditionalAccessReceiver (ec);
7286 var expr = OverloadResolve (ec, null);
7291 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7292 return expr.Resolve (ec);
7295 if (conditional_access_receiver) {
7296 type = LiftMemberType (ec, type);
7300 if (!ResolveGetter (ec))
7306 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7308 if (HasConditionalAccess ())
7309 Error_NullPropagatingLValue (rc);
7311 if (right_side == EmptyExpression.OutAccess) {
7312 // TODO: best_candidate can be null at this point
7313 INamedBlockVariable variable = null;
7314 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7315 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7316 best_candidate.Name);
7318 right_side.DoResolveLValue (rc, this);
7323 if (eclass == ExprClass.Unresolved) {
7324 var expr = OverloadResolve (rc, right_side);
7329 return expr.ResolveLValue (rc, right_side);
7331 ResolveInstanceExpression (rc, right_side);
7334 if (!best_candidate.HasSet) {
7335 if (ResolveAutopropertyAssignment (rc, right_side))
7338 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7339 GetSignatureForError ());
7343 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7344 if (best_candidate.HasDifferentAccessibility) {
7345 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7346 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7347 GetSignatureForError ());
7349 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7350 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7354 if (best_candidate.HasDifferentAccessibility)
7355 CheckProtectedMemberAccess (rc, best_candidate.Set);
7357 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7361 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7363 var ca = ec.ConditionalAccess;
7364 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7366 call.Emit (ec, method, arguments, loc);
7368 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7369 ec.ConditionalAccess = ca;
7373 // Implements the IAssignMethod interface for assignments
7375 public virtual void Emit (EmitContext ec, bool leave_copy)
7377 var call = new CallEmitter ();
7378 call.ConditionalAccess = ConditionalAccess;
7379 call.InstanceExpression = InstanceExpression;
7380 if (has_await_arguments)
7381 call.HasAwaitArguments = true;
7383 call.DuplicateArguments = emitting_compound_assignment;
7385 if (conditional_access_receiver)
7386 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7388 call.Emit (ec, Getter, Arguments, loc);
7390 if (call.HasAwaitArguments) {
7391 InstanceExpression = call.InstanceExpression;
7392 Arguments = call.EmittedArguments;
7393 has_await_arguments = true;
7397 ec.Emit (OpCodes.Dup);
7398 temp = new LocalTemporary (Type);
7403 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7405 public override void Emit (EmitContext ec)
7410 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7412 has_await_arguments = true;
7417 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7419 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7421 bool ResolveGetter (ResolveContext rc)
7423 if (!best_candidate.HasGet) {
7424 if (InstanceExpression != EmptyExpression.Null) {
7425 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7426 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7427 best_candidate.GetSignatureForError ());
7430 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7431 if (best_candidate.HasDifferentAccessibility) {
7432 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7433 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7434 TypeManager.CSharpSignature (best_candidate));
7436 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7437 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7441 if (best_candidate.HasDifferentAccessibility) {
7442 CheckProtectedMemberAccess (rc, best_candidate.Get);
7445 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7449 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7456 /// Fully resolved expression that evaluates to an Event
7458 public class EventExpr : MemberExpr, IAssignMethod
7460 readonly EventSpec spec;
7463 public EventExpr (EventSpec spec, Location loc)
7471 protected override TypeSpec DeclaringType {
7473 return spec.DeclaringType;
7477 public override string Name {
7483 public override bool IsInstance {
7485 return !spec.IsStatic;
7489 public override bool IsStatic {
7491 return spec.IsStatic;
7495 public override string KindName {
7496 get { return "event"; }
7499 public MethodSpec Operator {
7507 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7510 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7512 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7513 if (spec.BackingField != null &&
7514 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7516 spec.MemberDefinition.SetIsUsed ();
7518 spec.CheckObsoleteness (ec, loc);
7520 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7521 Error_AssignmentEventOnly (ec);
7523 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7525 InstanceExpression = null;
7527 return ml.ResolveMemberAccess (ec, left, original);
7531 return base.ResolveMemberAccess (ec, left, original);
7534 public override Expression CreateExpressionTree (ResolveContext ec)
7536 throw new NotSupportedException ("ET");
7539 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7541 if (right_side == EmptyExpression.EventAddition) {
7542 op = spec.AccessorAdd;
7543 } else if (right_side == EmptyExpression.EventSubtraction) {
7544 op = spec.AccessorRemove;
7548 Error_AssignmentEventOnly (ec);
7552 if (HasConditionalAccess ())
7553 Error_NullPropagatingLValue (ec);
7555 op = CandidateToBaseOverride (ec, op);
7559 protected override Expression DoResolve (ResolveContext ec)
7561 eclass = ExprClass.EventAccess;
7562 type = spec.MemberType;
7564 ResolveInstanceExpression (ec, null);
7566 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7567 Error_AssignmentEventOnly (ec);
7570 DoBestMemberChecks (ec, spec);
7574 public override void Emit (EmitContext ec)
7576 throw new NotSupportedException ();
7577 //Error_CannotAssign ();
7580 #region IAssignMethod Members
7582 public void Emit (EmitContext ec, bool leave_copy)
7584 throw new NotImplementedException ();
7587 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7589 if (leave_copy || !isCompound)
7590 throw new NotImplementedException ("EventExpr::EmitAssign");
7592 Arguments args = new Arguments (1);
7593 args.Add (new Argument (source));
7595 // TODO: Wrong, needs receiver
7596 // if (NullShortCircuit) {
7597 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7600 var call = new CallEmitter ();
7601 call.InstanceExpression = InstanceExpression;
7602 call.ConditionalAccess = ConditionalAccess;
7603 call.EmitStatement (ec, op, args, loc);
7605 // if (NullShortCircuit)
7606 // ec.CloseConditionalAccess (null);
7611 void Error_AssignmentEventOnly (ResolveContext ec)
7613 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7614 ec.Report.Error (79, loc,
7615 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7616 GetSignatureForError ());
7618 ec.Report.Error (70, loc,
7619 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7620 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7624 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7626 name = name.Substring (0, name.LastIndexOf ('.'));
7627 base.Error_CannotCallAbstractBase (rc, name);
7630 public override string GetSignatureForError ()
7632 return TypeManager.CSharpSignature (spec);
7635 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7637 spec.CheckObsoleteness (rc, expr.Location);
7640 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7642 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7646 public class TemporaryVariableReference : VariableReference
7648 public class Declarator : Statement
7650 TemporaryVariableReference variable;
7652 public Declarator (TemporaryVariableReference variable)
7654 this.variable = variable;
7658 protected override void DoEmit (EmitContext ec)
7660 variable.li.CreateBuilder (ec);
7663 public override void Emit (EmitContext ec)
7665 // Don't create sequence point
7669 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7674 protected override void CloneTo (CloneContext clonectx, Statement target)
7682 public TemporaryVariableReference (LocalVariable li, Location loc)
7685 this.type = li.Type;
7689 public override bool IsLockedByStatement {
7697 public LocalVariable LocalInfo {
7703 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7705 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7706 return new TemporaryVariableReference (li, loc);
7709 protected override Expression DoResolve (ResolveContext ec)
7711 eclass = ExprClass.Variable;
7714 // Don't capture temporary variables except when using
7715 // state machine redirection and block yields
7717 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7718 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7719 ec.IsVariableCapturingRequired) {
7720 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7721 storey.CaptureLocalVariable (ec, li);
7727 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7729 return Resolve (ec);
7732 public override void Emit (EmitContext ec)
7734 li.CreateBuilder (ec);
7739 public void EmitAssign (EmitContext ec, Expression source)
7741 li.CreateBuilder (ec);
7743 EmitAssign (ec, source, false, false);
7746 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7748 return li.HoistedVariant;
7751 public override bool IsFixed {
7752 get { return true; }
7755 public override bool IsRef {
7756 get { return false; }
7759 public override string Name {
7760 get { throw new NotImplementedException (); }
7763 public override void SetHasAddressTaken ()
7765 throw new NotImplementedException ();
7768 protected override ILocalVariable Variable {
7772 public override VariableInfo VariableInfo {
7773 get { return null; }
7778 /// Handles `var' contextual keyword; var becomes a keyword only
7779 /// if no type called var exists in a variable scope
7781 class VarExpr : SimpleName
7783 public VarExpr (Location loc)
7788 public bool InferType (ResolveContext ec, Expression right_side)
7791 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7793 type = right_side.Type;
7794 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7795 ec.Report.Error (815, loc,
7796 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7797 type.GetSignatureForError ());
7798 type = InternalType.ErrorType;
7802 eclass = ExprClass.Variable;
7806 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7808 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7809 base.Error_TypeOrNamespaceNotFound (ec);
7811 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");