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)
999 // Special version of flow analysis for expressions which can return different
1000 // on-true and on-false result. Used by &&, ||, ?: expressions
1002 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1005 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1009 /// Returns an expression that can be used to invoke operator true
1010 /// on the expression if it exists.
1012 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1014 return GetOperatorTrueOrFalse (ec, e, true, loc);
1018 /// Returns an expression that can be used to invoke operator false
1019 /// on the expression if it exists.
1021 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1023 return GetOperatorTrueOrFalse (ec, e, false, loc);
1026 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1028 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1030 if (type.IsNullableType)
1031 type = Nullable.NullableInfo.GetUnderlyingType (type);
1033 var methods = MemberCache.GetUserOperator (type, op, false);
1034 if (methods == null)
1037 Arguments arguments = new Arguments (1);
1038 arguments.Add (new Argument (e));
1040 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1041 var oper = res.ResolveOperator (ec, ref arguments);
1046 return new UserOperatorCall (oper, arguments, null, loc);
1049 public virtual string ExprClassName
1053 case ExprClass.Unresolved:
1054 return "Unresolved";
1055 case ExprClass.Value:
1057 case ExprClass.Variable:
1059 case ExprClass.Namespace:
1061 case ExprClass.Type:
1063 case ExprClass.MethodGroup:
1064 return "method group";
1065 case ExprClass.PropertyAccess:
1066 return "property access";
1067 case ExprClass.EventAccess:
1068 return "event access";
1069 case ExprClass.IndexerAccess:
1070 return "indexer access";
1071 case ExprClass.Nothing:
1073 case ExprClass.TypeParameter:
1074 return "type parameter";
1076 throw new Exception ("Should not happen");
1081 /// Reports that we were expecting `expr' to be of class `expected'
1083 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1085 var name = memberExpr.GetSignatureForError ();
1087 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1090 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1092 string [] valid = new string [4];
1095 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1096 valid [count++] = "variable";
1097 valid [count++] = "value";
1100 if ((flags & ResolveFlags.Type) != 0)
1101 valid [count++] = "type";
1103 if ((flags & ResolveFlags.MethodGroup) != 0)
1104 valid [count++] = "method group";
1107 valid [count++] = "unknown";
1109 StringBuilder sb = new StringBuilder (valid [0]);
1110 for (int i = 1; i < count - 1; i++) {
1112 sb.Append (valid [i]);
1115 sb.Append ("' or `");
1116 sb.Append (valid [count - 1]);
1119 ec.Report.Error (119, loc,
1120 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1123 public static void UnsafeError (ResolveContext ec, Location loc)
1125 UnsafeError (ec.Report, loc);
1128 public static void UnsafeError (Report Report, Location loc)
1130 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1133 public static void UnsafeInsideIteratorError (ResolveContext rc, Location loc)
1135 UnsafeInsideIteratorError (rc.Report, loc);
1138 public static void UnsafeInsideIteratorError (Report report, Location loc)
1140 report.Error (1629, loc, "Unsafe code may not appear in iterators");
1144 // Converts `source' to an int, uint, long or ulong.
1146 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1148 var btypes = ec.BuiltinTypes;
1150 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1151 Arguments args = new Arguments (1);
1152 args.Add (new Argument (source));
1153 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1156 Expression converted;
1158 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1159 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1160 if (converted == null)
1161 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1162 if (converted == null)
1163 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1164 if (converted == null)
1165 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1167 if (converted == null) {
1168 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1177 // Only positive constants are allowed at compile time
1179 Constant c = converted as Constant;
1180 if (c != null && c.IsNegative)
1181 Error_NegativeArrayIndex (ec, source.loc);
1183 // No conversion needed to array index
1184 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1187 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1190 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1192 if (args.Count != 1){
1193 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1198 if (arg is NamedArgument)
1199 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1201 var index = arg.Expr.Resolve (rc);
1205 index = ConvertExpressionToArrayIndex (rc, index, true);
1207 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1208 return new Indirection (p, loc);
1212 // Derived classes implement this method by cloning the fields that
1213 // could become altered during the Resolve stage
1215 // Only expressions that are created for the parser need to implement
1218 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1220 throw new NotImplementedException (
1222 "CloneTo not implemented for expression {0}", this.GetType ()));
1226 // Clones an expression created by the parser.
1228 // We only support expressions created by the parser so far, not
1229 // expressions that have been resolved (many more classes would need
1230 // to implement CloneTo).
1232 // This infrastructure is here merely for Lambda expressions which
1233 // compile the same code using different type values for the same
1234 // arguments to find the correct overload
1236 public virtual Expression Clone (CloneContext clonectx)
1238 Expression cloned = (Expression) MemberwiseClone ();
1239 CloneTo (clonectx, cloned);
1245 // Implementation of expression to expression tree conversion
1247 public abstract Expression CreateExpressionTree (ResolveContext ec);
1249 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1251 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1254 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1256 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1259 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1261 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1264 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1266 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1270 return new TypeExpression (t, loc);
1274 // Implemented by all expressions which support conversion from
1275 // compiler expression to invokable runtime expression. Used by
1276 // dynamic C# binder.
1278 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1280 throw new NotImplementedException ("MakeExpression for " + GetType ());
1283 public virtual object Accept (StructuralVisitor visitor)
1285 return visitor.Visit (this);
1290 /// This is just a base class for expressions that can
1291 /// appear on statements (invocations, object creation,
1292 /// assignments, post/pre increment and decrement). The idea
1293 /// being that they would support an extra Emition interface that
1294 /// does not leave a result on the stack.
1296 public abstract class ExpressionStatement : Expression
1298 public virtual void MarkReachable (Reachability rc)
1302 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1304 Expression e = Resolve (ec);
1308 ExpressionStatement es = e as ExpressionStatement;
1309 if (es == null || e is AnonymousMethodBody) {
1310 var reduced = e as IReducedExpressionStatement;
1311 if (reduced != null) {
1312 return EmptyExpressionStatement.Instance;
1315 Error_InvalidExpressionStatement (ec);
1319 // This is quite expensive warning, try to limit the damage
1321 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1322 WarningAsyncWithoutWait (ec, e);
1328 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1330 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1331 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1336 // Need to do full resolve because GetAwaiter can be extension method
1337 // available only in this context
1339 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1343 var arguments = new Arguments (0);
1344 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1349 // Use same check rules as for real await
1351 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1352 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1355 bc.Report.Warning (4014, 1, e.Location,
1356 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1360 var inv = e as Invocation;
1361 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1362 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1363 bc.Report.Warning (4014, 1, e.Location,
1364 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1370 /// Requests the expression to be emitted in a `statement'
1371 /// context. This means that no new value is left on the
1372 /// stack after invoking this method (constrasted with
1373 /// Emit that will always leave a value on the stack).
1375 public abstract void EmitStatement (EmitContext ec);
1377 public override void EmitSideEffect (EmitContext ec)
1383 interface IReducedExpressionStatement
1388 /// This kind of cast is used to encapsulate the child
1389 /// whose type is child.Type into an expression that is
1390 /// reported to return "return_type". This is used to encapsulate
1391 /// expressions which have compatible types, but need to be dealt
1392 /// at higher levels with.
1394 /// For example, a "byte" expression could be encapsulated in one
1395 /// of these as an "unsigned int". The type for the expression
1396 /// would be "unsigned int".
1399 public abstract class TypeCast : Expression
1401 protected readonly Expression child;
1403 protected TypeCast (Expression child, TypeSpec return_type)
1405 eclass = child.eclass;
1406 loc = child.Location;
1411 public Expression Child {
1417 public override bool ContainsEmitWithAwait ()
1419 return child.ContainsEmitWithAwait ();
1422 public override Expression CreateExpressionTree (ResolveContext ec)
1424 Arguments args = new Arguments (2);
1425 args.Add (new Argument (child.CreateExpressionTree (ec)));
1426 args.Add (new Argument (new TypeOf (type, loc)));
1428 if (type.IsPointer || child.Type.IsPointer)
1429 Error_PointerInsideExpressionTree (ec);
1431 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1434 protected override Expression DoResolve (ResolveContext ec)
1436 // This should never be invoked, we are born in fully
1437 // initialized state.
1442 public override void Emit (EmitContext ec)
1447 public override void FlowAnalysis (FlowAnalysisContext fc)
1449 child.FlowAnalysis (fc);
1452 public override SLE.Expression MakeExpression (BuilderContext ctx)
1455 return base.MakeExpression (ctx);
1457 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1458 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1459 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1463 protected override void CloneTo (CloneContext clonectx, Expression t)
1468 public override bool IsNull {
1469 get { return child.IsNull; }
1473 public class EmptyCast : TypeCast {
1474 EmptyCast (Expression child, TypeSpec target_type)
1475 : base (child, target_type)
1479 public static Expression Create (Expression child, TypeSpec type)
1481 Constant c = child as Constant;
1483 var enum_constant = c as EnumConstant;
1484 if (enum_constant != null)
1485 c = enum_constant.Child;
1487 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1491 var res = c.ConvertImplicitly (type);
1497 EmptyCast e = child as EmptyCast;
1499 return new EmptyCast (e.child, type);
1501 return new EmptyCast (child, type);
1504 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1506 child.EmitBranchable (ec, label, on_true);
1509 public override void EmitSideEffect (EmitContext ec)
1511 child.EmitSideEffect (ec);
1516 // Used for predefined type user operator (no obsolete check, etc.)
1518 public class OperatorCast : TypeCast
1520 readonly MethodSpec conversion_operator;
1522 public OperatorCast (Expression expr, TypeSpec target_type)
1523 : this (expr, target_type, target_type, false)
1527 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1528 : this (expr, target_type, target_type, find_explicit)
1532 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1533 : base (expr, returnType)
1535 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1536 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1539 foreach (MethodSpec oper in mi) {
1540 if (oper.ReturnType != returnType)
1543 if (oper.Parameters.Types[0] == expr.Type) {
1544 conversion_operator = oper;
1550 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1551 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1554 public override void Emit (EmitContext ec)
1557 ec.Emit (OpCodes.Call, conversion_operator);
1562 // Constant specialization of EmptyCast.
1563 // We need to special case this since an empty cast of
1564 // a constant is still a constant.
1566 public class EmptyConstantCast : Constant
1568 public readonly Constant child;
1570 public EmptyConstantCast (Constant child, TypeSpec type)
1571 : base (child.Location)
1574 throw new ArgumentNullException ("child");
1577 this.eclass = child.eclass;
1581 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1583 if (child.Type == target_type)
1586 // FIXME: check that 'type' can be converted to 'target_type' first
1587 return child.ConvertExplicitly (in_checked_context, target_type);
1590 public override Expression CreateExpressionTree (ResolveContext ec)
1592 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1593 child.CreateExpressionTree (ec),
1594 new TypeOf (type, loc));
1597 Error_PointerInsideExpressionTree (ec);
1599 return CreateExpressionFactoryCall (ec, "Convert", args);
1602 public override bool IsDefaultValue {
1603 get { return child.IsDefaultValue; }
1606 public override bool IsNegative {
1607 get { return child.IsNegative; }
1610 public override bool IsNull {
1611 get { return child.IsNull; }
1614 public override bool IsOneInteger {
1615 get { return child.IsOneInteger; }
1618 public override bool IsSideEffectFree {
1620 return child.IsSideEffectFree;
1624 public override bool IsZeroInteger {
1625 get { return child.IsZeroInteger; }
1628 public override void Emit (EmitContext ec)
1633 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1635 child.EmitBranchable (ec, label, on_true);
1637 // Only to make verifier happy
1638 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1639 ec.Emit (OpCodes.Unbox_Any, type);
1642 public override void EmitSideEffect (EmitContext ec)
1644 child.EmitSideEffect (ec);
1647 public override object GetValue ()
1649 return child.GetValue ();
1652 public override string GetValueAsLiteral ()
1654 return child.GetValueAsLiteral ();
1657 public override long GetValueAsLong ()
1659 return child.GetValueAsLong ();
1662 public override Constant ConvertImplicitly (TypeSpec target_type)
1664 if (type == target_type)
1667 // FIXME: Do we need to check user conversions?
1668 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1671 return child.ConvertImplicitly (target_type);
1676 /// This class is used to wrap literals which belong inside Enums
1678 public class EnumConstant : Constant
1680 public Constant Child;
1682 public EnumConstant (Constant child, TypeSpec enum_type)
1683 : base (child.Location)
1687 this.eclass = ExprClass.Value;
1688 this.type = enum_type;
1691 protected EnumConstant (Location loc)
1696 public override void Emit (EmitContext ec)
1701 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1703 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1706 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1708 Child.EmitBranchable (ec, label, on_true);
1711 public override void EmitSideEffect (EmitContext ec)
1713 Child.EmitSideEffect (ec);
1716 public override string GetSignatureForError()
1718 return Type.GetSignatureForError ();
1721 public override object GetValue ()
1723 return Child.GetValue ();
1727 public override object GetTypedValue ()
1730 // The method can be used in dynamic context only (on closed types)
1732 // System.Enum.ToObject cannot be called on dynamic types
1733 // EnumBuilder has to be used, but we cannot use EnumBuilder
1734 // because it does not properly support generics
1736 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1740 public override string GetValueAsLiteral ()
1742 return Child.GetValueAsLiteral ();
1745 public override long GetValueAsLong ()
1747 return Child.GetValueAsLong ();
1750 public EnumConstant Increment()
1752 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1755 public override bool IsDefaultValue {
1757 return Child.IsDefaultValue;
1761 public override bool IsSideEffectFree {
1763 return Child.IsSideEffectFree;
1767 public override bool IsZeroInteger {
1768 get { return Child.IsZeroInteger; }
1771 public override bool IsNegative {
1773 return Child.IsNegative;
1777 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1779 if (Child.Type == target_type)
1782 return Child.ConvertExplicitly (in_checked_context, target_type);
1785 public override Constant ConvertImplicitly (TypeSpec type)
1787 if (this.type == type) {
1791 if (!Convert.ImplicitStandardConversionExists (this, type)){
1795 return Child.ConvertImplicitly (type);
1800 /// This kind of cast is used to encapsulate Value Types in objects.
1802 /// The effect of it is to box the value type emitted by the previous
1805 public class BoxedCast : TypeCast {
1807 public BoxedCast (Expression expr, TypeSpec target_type)
1808 : base (expr, target_type)
1810 eclass = ExprClass.Value;
1813 protected override Expression DoResolve (ResolveContext ec)
1815 // This should never be invoked, we are born in fully
1816 // initialized state.
1821 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1823 // Only boxing to object type is supported
1824 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1825 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1829 enc.Encode (child.Type);
1830 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1833 public override void Emit (EmitContext ec)
1837 ec.Emit (OpCodes.Box, child.Type);
1840 public override void EmitSideEffect (EmitContext ec)
1842 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1843 // so, we need to emit the box+pop instructions in most cases
1844 if (child.Type.IsStruct &&
1845 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1846 child.EmitSideEffect (ec);
1848 base.EmitSideEffect (ec);
1852 public class UnboxCast : TypeCast {
1853 public UnboxCast (Expression expr, TypeSpec return_type)
1854 : base (expr, return_type)
1858 protected override Expression DoResolve (ResolveContext ec)
1860 // This should never be invoked, we are born in fully
1861 // initialized state.
1866 public override void Emit (EmitContext ec)
1870 ec.Emit (OpCodes.Unbox_Any, type);
1875 /// This is used to perform explicit numeric conversions.
1877 /// Explicit numeric conversions might trigger exceptions in a checked
1878 /// context, so they should generate the conv.ovf opcodes instead of
1881 public class ConvCast : TypeCast {
1882 public enum Mode : byte {
1883 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1885 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1886 U2_I1, U2_U1, U2_I2, U2_CH,
1887 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1888 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1889 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1890 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1891 CH_I1, CH_U1, CH_I2,
1892 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1893 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1899 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1900 : base (child, return_type)
1905 protected override Expression DoResolve (ResolveContext ec)
1907 // This should never be invoked, we are born in fully
1908 // initialized state.
1913 public override string ToString ()
1915 return String.Format ("ConvCast ({0}, {1})", mode, child);
1918 public override void Emit (EmitContext ec)
1924 public static void Emit (EmitContext ec, Mode mode)
1926 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1928 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1929 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1930 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1931 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1932 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1935 case Mode.U1_CH: /* nothing */ break;
1937 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1938 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1939 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1940 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1941 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1942 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1944 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1945 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1946 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1947 case Mode.U2_CH: /* nothing */ break;
1949 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1950 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1951 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1952 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1953 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1954 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1955 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1957 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1961 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1962 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1964 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1965 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1966 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1967 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1968 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1969 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1970 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1971 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1972 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1974 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1975 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1976 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1977 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1978 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1979 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1980 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1981 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1982 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1984 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1985 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1986 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1988 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1989 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1990 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1991 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1993 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1994 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1995 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1996 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1998 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1999 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2000 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2001 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2002 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2003 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2004 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2005 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2006 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2007 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2009 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2013 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2022 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2023 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2024 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2025 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2026 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2027 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2029 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2030 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2031 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2032 case Mode.U2_CH: /* nothing */ break;
2034 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2035 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2036 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2037 case Mode.I4_U4: /* nothing */ break;
2038 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2039 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2040 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2042 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2046 case Mode.U4_I4: /* nothing */ break;
2047 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2049 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2050 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2051 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2052 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2053 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2054 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2055 case Mode.I8_U8: /* nothing */ break;
2056 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2057 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2059 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2060 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2061 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2062 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2063 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2064 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2065 case Mode.U8_I8: /* nothing */ break;
2066 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2067 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2069 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2070 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2071 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2073 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2074 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2075 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2076 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2077 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2078 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2079 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2080 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2081 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2083 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2084 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2085 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2086 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2087 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2088 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2089 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2090 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2091 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2092 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2094 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2100 class OpcodeCast : TypeCast
2104 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2105 : base (child, return_type)
2110 protected override Expression DoResolve (ResolveContext ec)
2112 // This should never be invoked, we are born in fully
2113 // initialized state.
2118 public override void Emit (EmitContext ec)
2124 public TypeSpec UnderlyingType {
2125 get { return child.Type; }
2130 // Opcode casts expression with 2 opcodes but only
2131 // single expression tree node
2133 class OpcodeCastDuplex : OpcodeCast
2135 readonly OpCode second;
2137 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2138 : base (child, returnType, first)
2140 this.second = second;
2143 public override void Emit (EmitContext ec)
2151 /// This kind of cast is used to encapsulate a child and cast it
2152 /// to the class requested
2154 public sealed class ClassCast : TypeCast {
2155 readonly bool forced;
2157 public ClassCast (Expression child, TypeSpec return_type)
2158 : base (child, return_type)
2162 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2163 : base (child, return_type)
2165 this.forced = forced;
2168 public override void Emit (EmitContext ec)
2172 bool gen = TypeManager.IsGenericParameter (child.Type);
2174 ec.Emit (OpCodes.Box, child.Type);
2176 if (type.IsGenericParameter) {
2177 ec.Emit (OpCodes.Unbox_Any, type);
2184 ec.Emit (OpCodes.Castclass, type);
2189 // Created during resolving pahse when an expression is wrapped or constantified
2190 // and original expression can be used later (e.g. for expression trees)
2192 public class ReducedExpression : Expression
2194 public class ReducedConstantExpression : EmptyConstantCast
2196 readonly Expression orig_expr;
2198 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2199 : base (expr, expr.Type)
2201 this.orig_expr = orig_expr;
2204 public Expression OriginalExpression {
2210 public override Constant ConvertImplicitly (TypeSpec target_type)
2212 Constant c = base.ConvertImplicitly (target_type);
2214 c = new ReducedConstantExpression (c, orig_expr);
2219 public override Expression CreateExpressionTree (ResolveContext ec)
2221 return orig_expr.CreateExpressionTree (ec);
2224 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2226 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2228 c = new ReducedConstantExpression (c, orig_expr);
2232 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2235 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2237 if (orig_expr is Conditional)
2238 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2240 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2244 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2246 public ReducedConstantStatement (Constant expr, Expression origExpr)
2247 : base (expr, origExpr)
2252 sealed class ReducedExpressionStatement : ExpressionStatement
2254 readonly Expression orig_expr;
2255 readonly ExpressionStatement stm;
2257 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2259 this.orig_expr = orig;
2261 this.eclass = stm.eclass;
2262 this.type = stm.Type;
2264 this.loc = orig.Location;
2267 public override bool ContainsEmitWithAwait ()
2269 return stm.ContainsEmitWithAwait ();
2272 public override Expression CreateExpressionTree (ResolveContext ec)
2274 return orig_expr.CreateExpressionTree (ec);
2277 protected override Expression DoResolve (ResolveContext ec)
2282 public override void Emit (EmitContext ec)
2287 public override void EmitStatement (EmitContext ec)
2289 stm.EmitStatement (ec);
2292 public override void FlowAnalysis (FlowAnalysisContext fc)
2294 stm.FlowAnalysis (fc);
2298 readonly Expression expr, orig_expr;
2300 private ReducedExpression (Expression expr, Expression orig_expr)
2303 this.eclass = expr.eclass;
2304 this.type = expr.Type;
2305 this.orig_expr = orig_expr;
2306 this.loc = orig_expr.Location;
2311 public override bool IsSideEffectFree {
2313 return expr.IsSideEffectFree;
2317 public Expression OriginalExpression {
2325 public override bool ContainsEmitWithAwait ()
2327 return expr.ContainsEmitWithAwait ();
2331 // Creates fully resolved expression switcher
2333 public static Constant Create (Constant expr, Expression originalExpr)
2335 if (expr.eclass == ExprClass.Unresolved)
2336 throw new ArgumentException ("Unresolved expression");
2338 if (originalExpr is ExpressionStatement)
2339 return new ReducedConstantStatement (expr, originalExpr);
2341 return new ReducedConstantExpression (expr, originalExpr);
2344 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2346 return new ReducedExpressionStatement (s, orig);
2349 public static Expression Create (Expression expr, Expression original_expr)
2351 return Create (expr, original_expr, true);
2355 // Creates unresolved reduce expression. The original expression has to be
2356 // already resolved. Created expression is constant based based on `expr'
2357 // value unless canBeConstant is used
2359 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2361 if (canBeConstant) {
2362 Constant c = expr as Constant;
2364 return Create (c, original_expr);
2367 ExpressionStatement s = expr as ExpressionStatement;
2369 return Create (s, original_expr);
2371 if (expr.eclass == ExprClass.Unresolved)
2372 throw new ArgumentException ("Unresolved expression");
2374 return new ReducedExpression (expr, original_expr);
2377 public override Expression CreateExpressionTree (ResolveContext ec)
2379 return orig_expr.CreateExpressionTree (ec);
2382 protected override Expression DoResolve (ResolveContext ec)
2387 public override void Emit (EmitContext ec)
2392 public override Expression EmitToField (EmitContext ec)
2394 return expr.EmitToField(ec);
2397 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2399 expr.EmitBranchable (ec, target, on_true);
2402 public override void FlowAnalysis (FlowAnalysisContext fc)
2404 expr.FlowAnalysis (fc);
2407 public override SLE.Expression MakeExpression (BuilderContext ctx)
2409 return orig_expr.MakeExpression (ctx);
2414 // Standard composite pattern
2416 public abstract class CompositeExpression : Expression
2418 protected Expression expr;
2420 protected CompositeExpression (Expression expr)
2423 this.loc = expr.Location;
2426 public override bool ContainsEmitWithAwait ()
2428 return expr.ContainsEmitWithAwait ();
2431 public override Expression CreateExpressionTree (ResolveContext rc)
2433 return expr.CreateExpressionTree (rc);
2436 public Expression Child {
2437 get { return expr; }
2440 protected override Expression DoResolve (ResolveContext rc)
2442 expr = expr.Resolve (rc);
2447 eclass = expr.eclass;
2451 public override void Emit (EmitContext ec)
2456 public override bool IsNull {
2457 get { return expr.IsNull; }
2462 // Base of expressions used only to narrow resolve flow
2464 public abstract class ShimExpression : Expression
2466 protected Expression expr;
2468 protected ShimExpression (Expression expr)
2473 public Expression Expr {
2479 protected override void CloneTo (CloneContext clonectx, Expression t)
2484 ShimExpression target = (ShimExpression) t;
2485 target.expr = expr.Clone (clonectx);
2488 public override bool ContainsEmitWithAwait ()
2490 return expr.ContainsEmitWithAwait ();
2493 public override Expression CreateExpressionTree (ResolveContext ec)
2495 throw new NotSupportedException ("ET");
2498 public override void Emit (EmitContext ec)
2500 throw new InternalErrorException ("Missing Resolve call");
2504 public class UnreachableExpression : Expression
2506 public UnreachableExpression (Expression expr)
2508 this.loc = expr.Location;
2511 public override Expression CreateExpressionTree (ResolveContext ec)
2514 throw new NotImplementedException ();
2517 protected override Expression DoResolve (ResolveContext rc)
2519 throw new NotSupportedException ();
2522 public override void FlowAnalysis (FlowAnalysisContext fc)
2524 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2527 public override void Emit (EmitContext ec)
2531 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2537 // Unresolved type name expressions
2539 public abstract class ATypeNameExpression : FullNamedExpression
2542 protected TypeArguments targs;
2544 protected ATypeNameExpression (string name, Location l)
2550 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2557 protected ATypeNameExpression (string name, int arity, Location l)
2558 : this (name, new UnboundTypeArguments (arity, l), l)
2566 return targs == null ? 0 : targs.Count;
2570 public bool HasTypeArguments {
2572 return targs != null && !targs.IsEmpty;
2576 public string Name {
2585 public TypeArguments TypeArguments {
2593 public override bool Equals (object obj)
2595 ATypeNameExpression atne = obj as ATypeNameExpression;
2596 return atne != null && atne.Name == Name &&
2597 (targs == null || targs.Equals (atne.targs));
2600 public override int GetHashCode ()
2602 return Name.GetHashCode ();
2605 // TODO: Move it to MemberCore
2606 public static string GetMemberType (MemberCore mc)
2612 if (mc is FieldBase)
2614 if (mc is MethodCore)
2616 if (mc is EnumMember)
2624 public override string GetSignatureForError ()
2626 if (targs != null) {
2627 return Name + "<" + targs.GetSignatureForError () + ">";
2633 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2637 /// SimpleName expressions are formed of a single word and only happen at the beginning
2638 /// of a dotted-name.
2640 public class SimpleName : ATypeNameExpression
2642 public SimpleName (string name, Location l)
2647 public SimpleName (string name, TypeArguments args, Location l)
2648 : base (name, args, l)
2652 public SimpleName (string name, int arity, Location l)
2653 : base (name, arity, l)
2657 public SimpleName GetMethodGroup ()
2659 return new SimpleName (Name, targs, loc);
2662 protected override Expression DoResolve (ResolveContext rc)
2664 return SimpleNameResolve (rc, null);
2667 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2669 return SimpleNameResolve (ec, right_side);
2672 public void Error_NameDoesNotExist (ResolveContext rc)
2674 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2677 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2679 if (ctx.CurrentType != null) {
2680 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2681 if (member != null) {
2682 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2687 var report = ctx.Module.Compiler.Report;
2689 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2690 if (retval != null) {
2691 report.SymbolRelatedToPreviousError (retval.Type);
2692 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2696 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2697 if (retval != null) {
2698 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2702 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2703 if (ns_candidates != null) {
2704 if (ctx is UsingAliasNamespace.AliasContext) {
2705 report.Error (246, loc,
2706 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2707 ns_candidates[0], Name);
2709 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2710 report.Error (246, loc,
2711 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2715 report.Error (246, loc,
2716 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2721 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2723 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2726 if (fne.Type != null && Arity > 0) {
2727 if (HasTypeArguments) {
2728 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2729 if (ct.ResolveAsType (mc) == null)
2735 targs.Resolve (mc, allowUnboundTypeArguments);
2737 return new GenericOpenTypeExpr (fne.Type, loc);
2741 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2743 if (!(fne is NamespaceExpression))
2747 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2748 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2749 mc.Module.Compiler.Report.Error (1980, Location,
2750 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2751 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2754 fne = new DynamicTypeExpr (loc);
2755 fne.ResolveAsType (mc);
2761 Error_TypeOrNamespaceNotFound (mc);
2765 bool IsPossibleTypeOrNamespace (IMemberContext mc)
2768 // Has to ignore static usings because we are looking for any member not just type
2771 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing | LookupMode.IgnoreStaticUsing, loc) != null;
2774 public bool IsPossibleType (IMemberContext mc)
2776 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2779 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2781 int lookup_arity = Arity;
2782 bool errorMode = false;
2784 Block current_block = rc.CurrentBlock;
2785 INamedBlockVariable variable = null;
2786 bool variable_found = false;
2790 // Stage 1: binding to local variables or parameters
2792 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2794 if (current_block != null && lookup_arity == 0) {
2795 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2796 if (!variable.IsDeclared) {
2797 // We found local name in accessible block but it's not
2798 // initialized yet, maybe the user wanted to bind to something else
2800 variable_found = true;
2802 e = variable.CreateReferenceExpression (rc, loc);
2805 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2814 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2816 TypeSpec member_type = rc.CurrentType;
2817 for (; member_type != null; member_type = member_type.DeclaringType) {
2818 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2822 var me = e as MemberExpr;
2824 // The name matches a type, defer to ResolveAsTypeStep
2832 if (variable != null) {
2833 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2834 rc.Report.Error (844, loc,
2835 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2836 Name, me.GetSignatureForError ());
2840 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2841 // Leave it to overload resolution to report correct error
2843 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2844 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2848 // MemberLookup does not check accessors availability, this is actually needed for properties only
2850 var pe = me as PropertyExpr;
2853 // Break as there is no other overload available anyway
2854 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2855 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2858 pe.Getter = pe.PropertyInfo.Get;
2860 if (!pe.PropertyInfo.HasSet) {
2861 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2862 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2863 var p = (Property) pe.PropertyInfo.MemberDefinition;
2864 return new FieldExpr (p.BackingField, loc);
2867 variable_found = true;
2871 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2872 variable_found = true;
2876 pe.Setter = pe.PropertyInfo.Set;
2881 // TODO: It's used by EventExpr -> FieldExpr transformation only
2882 // TODO: Should go to MemberAccess
2883 me = me.ResolveMemberAccess (rc, null, null);
2886 targs.Resolve (rc, false);
2887 me.SetTypeArguments (rc, targs);
2894 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2896 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2897 if (IsPossibleTypeOrNamespace (rc)) {
2898 return ResolveAsTypeOrNamespace (rc, false);
2902 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2905 targs.Resolve (rc, false);
2907 var me = expr as MemberExpr;
2909 me.SetTypeArguments (rc, targs);
2914 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2915 return new NameOf (this);
2918 if (variable_found) {
2919 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2922 var tparams = rc.CurrentTypeParameters;
2923 if (tparams != null) {
2924 if (tparams.Find (Name) != null) {
2925 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2930 var ct = rc.CurrentType;
2932 if (ct.MemberDefinition.TypeParametersCount > 0) {
2933 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2934 if (ctp.Name == Name) {
2935 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2941 ct = ct.DeclaringType;
2942 } while (ct != null);
2945 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2946 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2948 rc.Report.SymbolRelatedToPreviousError (e.Type);
2949 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2953 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2955 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2956 return ErrorExpression.Instance;
2960 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2962 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2963 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2967 if (e is TypeExpr) {
2968 // TypeExpression does not have correct location
2969 if (e is TypeExpression)
2970 e = new TypeExpression (e.Type, loc);
2976 Error_NameDoesNotExist (rc);
2979 return ErrorExpression.Instance;
2982 if (rc.Module.Evaluator != null) {
2983 var fi = rc.Module.Evaluator.LookupField (Name);
2985 return new FieldExpr (fi.Item1, loc);
2993 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2995 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3000 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3001 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3005 if (right_side != null) {
3006 e = e.ResolveLValue (ec, right_side);
3014 public override object Accept (StructuralVisitor visitor)
3016 return visitor.Visit (this);
3021 /// Represents a namespace or a type. The name of the class was inspired by
3022 /// section 10.8.1 (Fully Qualified Names).
3024 public abstract class FullNamedExpression : Expression
3026 protected override void CloneTo (CloneContext clonectx, Expression target)
3028 // Do nothing, most unresolved type expressions cannot be
3029 // resolved to different type
3032 public override bool ContainsEmitWithAwait ()
3037 public override Expression CreateExpressionTree (ResolveContext ec)
3039 throw new NotSupportedException ("ET");
3042 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3045 // This is used to resolve the expression as a type, a null
3046 // value will be returned if the expression is not a type
3049 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3051 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3056 TypeExpr te = fne as TypeExpr;
3058 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3066 var dep = type.GetMissingDependencies ();
3068 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3071 if (type.Kind == MemberKind.Void) {
3072 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3076 // Obsolete checks cannot be done when resolving base context as they
3077 // require type dependencies to be set but we are in process of resolving them
3079 if (mc is ResolveContext) {
3080 var oa = type.GetAttributeObsolete ();
3081 if (oa != null && !mc.IsObsolete)
3082 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3089 public override void Emit (EmitContext ec)
3091 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3092 GetSignatureForError ());
3097 /// Expression that evaluates to a type
3099 public abstract class TypeExpr : FullNamedExpression
3101 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3107 protected sealed override Expression DoResolve (ResolveContext ec)
3113 public override bool Equals (object obj)
3115 TypeExpr tobj = obj as TypeExpr;
3119 return Type == tobj.Type;
3122 public override int GetHashCode ()
3124 return Type.GetHashCode ();
3129 /// Fully resolved Expression that already evaluated to a type
3131 public class TypeExpression : TypeExpr
3133 public TypeExpression (TypeSpec t, Location l)
3136 eclass = ExprClass.Type;
3140 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3146 public class NamespaceExpression : FullNamedExpression
3148 readonly Namespace ns;
3150 public NamespaceExpression (Namespace ns, Location loc)
3153 this.Type = InternalType.Namespace;
3154 this.eclass = ExprClass.Namespace;
3158 public Namespace Namespace {
3164 protected override Expression DoResolve (ResolveContext rc)
3166 throw new NotImplementedException ();
3169 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3174 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3176 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3177 if (retval != null) {
3178 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3179 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3183 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3184 if (retval != null) {
3185 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3190 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3191 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3195 string assembly = null;
3196 string possible_name = Namespace.GetSignatureForError () + "." + name;
3198 // Only assembly unique name should be added
3199 switch (possible_name) {
3200 case "System.Drawing":
3201 case "System.Web.Services":
3204 case "System.Configuration":
3205 case "System.Data.Services":
3206 case "System.DirectoryServices":
3208 case "System.Net.Http":
3209 case "System.Numerics":
3210 case "System.Runtime.Caching":
3211 case "System.ServiceModel":
3212 case "System.Transactions":
3213 case "System.Web.Routing":
3214 case "System.Xml.Linq":
3216 assembly = possible_name;
3220 case "System.Linq.Expressions":
3221 assembly = "System.Core";
3224 case "System.Windows.Forms":
3225 case "System.Windows.Forms.Layout":
3226 assembly = "System.Windows.Forms";
3230 assembly = assembly == null ? "an" : "`" + assembly + "'";
3232 if (Namespace is GlobalRootNamespace) {
3233 ctx.Module.Compiler.Report.Error (400, loc,
3234 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3237 ctx.Module.Compiler.Report.Error (234, loc,
3238 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3239 name, GetSignatureForError (), assembly);
3243 public override string GetSignatureForError ()
3245 return ns.GetSignatureForError ();
3248 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3250 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3253 public override string ToString ()
3255 return Namespace.Name;
3260 /// This class denotes an expression which evaluates to a member
3261 /// of a struct or a class.
3263 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3265 protected bool conditional_access_receiver;
3268 // An instance expression associated with this member, if it's a
3269 // non-static member
3271 public Expression InstanceExpression;
3274 /// The name of this member.
3276 public abstract string Name {
3281 // When base.member is used
3283 public bool IsBase {
3284 get { return InstanceExpression is BaseThis; }
3288 /// Whether this is an instance member.
3290 public abstract bool IsInstance {
3295 /// Whether this is a static member.
3297 public abstract bool IsStatic {
3301 public abstract string KindName {
3305 public bool ConditionalAccess { get; set; }
3307 protected abstract TypeSpec DeclaringType {
3311 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3313 return InstanceExpression.Type;
3318 // Converts best base candidate for virtual method starting from QueriedBaseType
3320 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3323 // Only when base.member is used and method is virtual
3329 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3330 // means for base.member access we have to find the closest match after we found best candidate
3332 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3334 // The method could already be what we are looking for
3336 TypeSpec[] targs = null;
3337 if (method.DeclaringType != InstanceExpression.Type) {
3339 // Candidate can have inflated MVAR parameters and we need to find
3340 // base match for original definition not inflated parameter types
3342 var parameters = method.Parameters;
3343 if (method.Arity > 0) {
3344 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3345 var inflated = method.DeclaringType as InflatedTypeSpec;
3346 if (inflated != null) {
3347 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3351 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3352 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3353 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3354 if (base_override.IsGeneric)
3355 targs = method.TypeArguments;
3357 method = base_override;
3362 // When base access is used inside anonymous method/iterator/etc we need to
3363 // get back to the context of original type. We do it by emiting proxy
3364 // method in original class and rewriting base call to this compiler
3365 // generated method call which does the actual base invocation. This may
3366 // introduce redundant storey but with `this' only but it's tricky to avoid
3367 // at this stage as we don't know what expressions follow base
3369 // TODO: It's needed only when the method with base call is moved to a storey
3371 if (rc.CurrentAnonymousMethod != null) {
3372 if (targs == null && method.IsGeneric) {
3373 targs = method.TypeArguments;
3374 method = method.GetGenericMethodDefinition ();
3377 if (method.Parameters.HasArglist)
3378 throw new NotImplementedException ("__arglist base call proxy");
3380 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3382 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3383 // get/set member expressions second call would fail to proxy because left expression
3384 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3385 // FIXME: The async check is another hack but will probably fail with mutators
3386 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3387 InstanceExpression = new This (loc).Resolve (rc);
3391 method = method.MakeGenericMethod (rc, targs);
3395 // Only base will allow this invocation to happen.
3397 if (method.IsAbstract) {
3398 rc.Report.SymbolRelatedToPreviousError (method);
3399 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3405 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3407 if (InstanceExpression == null)
3410 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3411 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3412 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3417 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3419 if (InstanceExpression == null)
3422 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3425 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3427 var ct = rc.CurrentType;
3428 if (ct == qualifier)
3431 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3434 qualifier = qualifier.GetDefinition ();
3435 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3442 public override bool ContainsEmitWithAwait ()
3444 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3447 public override bool HasConditionalAccess ()
3449 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3452 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3455 type = type.GetDefinition ();
3457 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3460 type = type.DeclaringType;
3461 } while (type != null);
3466 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3468 if (InstanceExpression != null) {
3469 InstanceExpression = InstanceExpression.Resolve (rc);
3470 CheckProtectedMemberAccess (rc, member);
3473 if (member.MemberType.IsPointer) {
3474 if (rc.CurrentIterator != null) {
3475 UnsafeInsideIteratorError (rc, loc);
3476 } else if (!rc.IsUnsafe) {
3477 UnsafeError (rc, loc);
3481 var dep = member.GetMissingDependencies ();
3483 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3486 member.CheckObsoleteness (rc, loc);
3488 if (!(member is FieldSpec))
3489 member.MemberDefinition.SetIsUsed ();
3492 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3494 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3497 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3499 rc.Report.SymbolRelatedToPreviousError (member);
3500 rc.Report.Error (1540, loc,
3501 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3502 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3505 public override void FlowAnalysis (FlowAnalysisContext fc)
3507 if (InstanceExpression != null) {
3508 InstanceExpression.FlowAnalysis (fc);
3512 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3514 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3515 conditional_access_receiver = true;
3519 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3521 if (!ResolveInstanceExpressionCore (rc, rhs))
3525 // Check intermediate value modification which won't have any effect
3527 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3528 var fexpr = InstanceExpression as FieldExpr;
3529 if (fexpr != null) {
3530 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3533 if (fexpr.IsStatic) {
3534 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3535 fexpr.GetSignatureForError ());
3537 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3538 fexpr.GetSignatureForError ());
3544 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3545 if (rc.CurrentInitializerVariable != null) {
3546 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3547 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3549 rc.Report.Error (1612, loc,
3550 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3551 InstanceExpression.GetSignatureForError ());
3557 var lvr = InstanceExpression as LocalVariableReference;
3560 if (!lvr.local_info.IsReadonly)
3563 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3564 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3571 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3574 if (InstanceExpression != null) {
3575 if (InstanceExpression is TypeExpr) {
3576 var t = InstanceExpression.Type;
3578 t.CheckObsoleteness (rc, loc);
3580 t = t.DeclaringType;
3581 } while (t != null);
3583 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3584 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3585 rc.Report.Error (176, loc,
3586 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3587 GetSignatureForError ());
3591 InstanceExpression = null;
3597 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3598 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3599 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3600 rc.Report.Error (236, loc,
3601 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3602 GetSignatureForError ());
3604 var fe = this as FieldExpr;
3605 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3606 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3607 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3609 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3613 rc.Report.Error (120, loc,
3614 "An object reference is required to access non-static member `{0}'",
3615 GetSignatureForError ());
3619 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3623 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3624 rc.Report.Error (38, loc,
3625 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3626 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3629 InstanceExpression = new This (loc).Resolve (rc);
3633 var me = InstanceExpression as MemberExpr;
3635 me.ResolveInstanceExpressionCore (rc, rhs);
3637 var fe = me as FieldExpr;
3638 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3639 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3640 rc.Report.Warning (1690, 1, loc,
3641 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3642 me.GetSignatureForError ());
3649 // Additional checks for l-value member access
3652 if (InstanceExpression is UnboxCast) {
3653 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3660 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3662 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3663 ec.Report.Warning (1720, 1, left.Location,
3664 "Expression will always cause a `{0}'", "System.NullReferenceException");
3667 InstanceExpression = left;
3671 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3676 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3678 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3679 inst.Emit (ec, ConditionalAccess);
3681 if (prepare_for_load)
3682 ec.Emit (OpCodes.Dup);
3685 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3688 public class ExtensionMethodCandidates
3690 readonly NamespaceContainer container;
3691 readonly IList<MethodSpec> methods;
3693 readonly IMemberContext context;
3695 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3697 this.context = context;
3698 this.methods = methods;
3699 this.container = nsContainer;
3700 this.index = lookupIndex;
3703 public NamespaceContainer Container {
3709 public IMemberContext Context {
3715 public int LookupIndex {
3721 public IList<MethodSpec> Methods {
3729 // Represents a group of extension method candidates for whole namespace
3731 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3733 ExtensionMethodCandidates candidates;
3734 public Expression ExtensionExpression;
3736 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3737 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3739 this.candidates = candidates;
3740 this.ExtensionExpression = extensionExpr;
3743 public override bool IsStatic {
3744 get { return true; }
3748 // For extension methodgroup we are not looking for base members but parent
3749 // namespace extension methods
3751 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3753 // TODO: candidates are null only when doing error reporting, that's
3754 // incorrect. We have to discover same extension methods in error mode
3755 if (candidates == null)
3758 int arity = type_arguments == null ? 0 : type_arguments.Count;
3760 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3761 if (candidates == null)
3764 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3767 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3770 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3772 // LAMESPEC: or implicit type parameter conversion
3774 return argType == extensionType ||
3775 TypeSpecComparer.IsEqual (argType, extensionType) ||
3776 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3777 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3780 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3782 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3785 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3787 // We are already here
3791 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3793 if (arguments == null)
3794 arguments = new Arguments (1);
3796 ExtensionExpression = ExtensionExpression.Resolve (ec);
3797 if (ExtensionExpression == null)
3800 var cand = candidates;
3801 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3802 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3803 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3805 // Restore candidates in case we are running in probing mode
3808 // Store resolved argument and restore original arguments
3810 // Clean-up modified arguments for error reporting
3811 arguments.RemoveAt (0);
3815 var me = ExtensionExpression as MemberExpr;
3817 me.ResolveInstanceExpression (ec, null);
3818 var fe = me as FieldExpr;
3820 fe.Spec.MemberDefinition.SetIsUsed ();
3823 InstanceExpression = null;
3827 #region IErrorHandler Members
3829 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3834 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3836 rc.Report.SymbolRelatedToPreviousError (best);
3839 rc.Report.Error (1929, loc,
3840 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3841 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3843 rc.Report.Error (1928, loc,
3844 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3845 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3851 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3856 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3865 /// MethodGroupExpr represents a group of method candidates which
3866 /// can be resolved to the best method overload
3868 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3870 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3872 protected IList<MemberSpec> Methods;
3873 MethodSpec best_candidate;
3874 TypeSpec best_candidate_return;
3875 protected TypeArguments type_arguments;
3877 SimpleName simple_name;
3878 protected TypeSpec queried_type;
3880 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3884 this.type = InternalType.MethodGroup;
3886 eclass = ExprClass.MethodGroup;
3887 queried_type = type;
3890 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3891 : this (new MemberSpec[] { m }, type, loc)
3897 public MethodSpec BestCandidate {
3899 return best_candidate;
3903 public TypeSpec BestCandidateReturnType {
3905 return best_candidate_return;
3909 public IList<MemberSpec> Candidates {
3915 protected override TypeSpec DeclaringType {
3917 return queried_type;
3921 public bool IsConditionallyExcluded {
3923 return Methods == Excluded;
3927 public override bool IsInstance {
3929 if (best_candidate != null)
3930 return !best_candidate.IsStatic;
3936 public override bool IsSideEffectFree {
3938 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3942 public override bool IsStatic {
3944 if (best_candidate != null)
3945 return best_candidate.IsStatic;
3951 public override string KindName {
3952 get { return "method"; }
3955 public override string Name {
3957 if (best_candidate != null)
3958 return best_candidate.Name;
3961 return Methods.First ().Name;
3968 // When best candidate is already know this factory can be used
3969 // to avoid expensive overload resolution to be called
3971 // NOTE: InstanceExpression has to be set manually
3973 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3975 return new MethodGroupExpr (best, queriedType, loc) {
3976 best_candidate = best,
3977 best_candidate_return = best.ReturnType
3981 public override string GetSignatureForError ()
3983 if (best_candidate != null)
3984 return best_candidate.GetSignatureForError ();
3986 return Methods.First ().GetSignatureForError ();
3989 public override Expression CreateExpressionTree (ResolveContext ec)
3991 if (best_candidate == null) {
3992 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3996 if (IsConditionallyExcluded)
3997 ec.Report.Error (765, loc,
3998 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4000 if (ConditionalAccess)
4001 Error_NullShortCircuitInsideExpressionTree (ec);
4003 return new TypeOfMethod (best_candidate, loc);
4006 protected override Expression DoResolve (ResolveContext ec)
4008 this.eclass = ExprClass.MethodGroup;
4010 if (InstanceExpression != null) {
4011 InstanceExpression = InstanceExpression.Resolve (ec);
4012 if (InstanceExpression == null)
4019 public override void Emit (EmitContext ec)
4021 throw new NotSupportedException ();
4024 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4026 var call = new CallEmitter ();
4027 call.InstanceExpression = InstanceExpression;
4028 call.ConditionalAccess = ConditionalAccess;
4031 call.EmitStatement (ec, best_candidate, arguments, loc);
4033 call.Emit (ec, best_candidate, arguments, loc);
4036 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4038 var ca = ec.ConditionalAccess;
4039 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4040 Statement = statement
4043 EmitCall (ec, arguments, statement);
4045 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4046 ec.ConditionalAccess = ca;
4049 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4051 if (target != InternalType.ErrorType) {
4052 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4053 Name, target.GetSignatureForError ());
4057 public bool HasAccessibleCandidate (ResolveContext rc)
4059 foreach (var candidate in Candidates) {
4060 if (candidate.IsAccessible (rc))
4067 public static bool IsExtensionMethodArgument (Expression expr)
4070 // LAMESPEC: No details about which expressions are not allowed
4072 return !(expr is TypeExpr) && !(expr is BaseThis);
4076 /// Find the Applicable Function Members (7.4.2.1)
4078 /// me: Method Group expression with the members to select.
4079 /// it might contain constructors or methods (or anything
4080 /// that maps to a method).
4082 /// Arguments: ArrayList containing resolved Argument objects.
4084 /// loc: The location if we want an error to be reported, or a Null
4085 /// location for "probing" purposes.
4087 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4088 /// that is the best match of me on Arguments.
4091 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4093 // TODO: causes issues with probing mode, remove explicit Kind check
4094 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4097 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4098 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4099 r.BaseMembersProvider = this;
4100 r.InstanceQualifier = this;
4103 if (cerrors != null)
4104 r.CustomErrors = cerrors;
4106 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4107 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4108 if (best_candidate == null) {
4109 if (!r.BestCandidateIsDynamic)
4112 if (simple_name != null && ec.IsStatic)
4113 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4118 // Overload resolver had to create a new method group, all checks bellow have already been executed
4119 if (r.BestCandidateNewMethodGroup != null)
4120 return r.BestCandidateNewMethodGroup;
4122 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4123 if (InstanceExpression != null) {
4124 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4125 InstanceExpression = null;
4127 if (simple_name != null && best_candidate.IsStatic) {
4128 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4131 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4135 ResolveInstanceExpression (ec, null);
4138 var base_override = CandidateToBaseOverride (ec, best_candidate);
4139 if (base_override == best_candidate) {
4140 best_candidate_return = r.BestCandidateReturnType;
4142 best_candidate = base_override;
4143 best_candidate_return = best_candidate.ReturnType;
4146 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4147 ConstraintChecker cc = new ConstraintChecker (ec);
4148 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4152 // Additional check for possible imported base override method which
4153 // could not be done during IsOverrideMethodBaseTypeAccessible
4155 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4156 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4157 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4158 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4161 // Speed up the check by not doing it on disallowed targets
4162 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4168 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4170 var fe = left as FieldExpr;
4173 // Using method-group on struct fields makes the struct assigned. I am not sure
4174 // why but that's what .net does
4176 fe.Spec.MemberDefinition.SetIsAssigned ();
4179 simple_name = original;
4180 return base.ResolveMemberAccess (ec, left, original);
4183 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4185 if (!HasAccessibleCandidate (rc)) {
4186 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4189 if (expr.HasTypeArguments) {
4190 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4194 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4196 type_arguments = ta;
4199 #region IBaseMembersProvider Members
4201 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4203 var baseType = type.BaseType;
4205 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4207 if (members == null && !type.IsInterface) {
4208 var tps = queried_type as TypeParameterSpec;
4210 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4216 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4218 if (queried_type == member.DeclaringType)
4221 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4222 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4226 // Extension methods lookup after ordinary methods candidates failed to apply
4228 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4230 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4233 if (!IsExtensionMethodArgument (InstanceExpression))
4236 int arity = type_arguments == null ? 0 : type_arguments.Count;
4237 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4238 if (methods == null)
4241 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4242 emg.SetTypeArguments (rc, type_arguments);
4243 emg.ConditionalAccess = ConditionalAccess;
4250 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4252 public ConstructorInstanceQualifier (TypeSpec type)
4255 InstanceType = type;
4258 public TypeSpec InstanceType { get; private set; }
4260 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4262 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4266 public struct OverloadResolver
4269 public enum Restrictions
4273 ProbingOnly = 1 << 1,
4274 CovariantDelegate = 1 << 2,
4275 NoBaseMembers = 1 << 3,
4276 BaseMembersIncluded = 1 << 4,
4277 GetEnumeratorLookup = 1 << 5
4280 public interface IBaseMembersProvider
4282 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4283 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4284 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4287 public interface IErrorHandler
4289 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4290 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4291 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4292 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4295 public interface IInstanceQualifier
4297 TypeSpec InstanceType { get; }
4298 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4301 sealed class NoBaseMembers : IBaseMembersProvider
4303 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4305 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4310 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4315 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4321 struct AmbiguousCandidate
4323 public readonly MemberSpec Member;
4324 public readonly bool Expanded;
4325 public readonly AParametersCollection Parameters;
4327 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4330 Parameters = parameters;
4331 Expanded = expanded;
4336 IList<MemberSpec> members;
4337 TypeArguments type_arguments;
4338 IBaseMembersProvider base_provider;
4339 IErrorHandler custom_errors;
4340 IInstanceQualifier instance_qualifier;
4341 Restrictions restrictions;
4342 MethodGroupExpr best_candidate_extension_group;
4343 TypeSpec best_candidate_return_type;
4345 SessionReportPrinter lambda_conv_msgs;
4347 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4348 : this (members, null, restrictions, loc)
4352 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4355 if (members == null || members.Count == 0)
4356 throw new ArgumentException ("empty members set");
4358 this.members = members;
4360 type_arguments = targs;
4361 this.restrictions = restrictions;
4362 if (IsDelegateInvoke)
4363 this.restrictions |= Restrictions.NoBaseMembers;
4365 base_provider = NoBaseMembers.Instance;
4370 public IBaseMembersProvider BaseMembersProvider {
4372 return base_provider;
4375 base_provider = value;
4379 public bool BestCandidateIsDynamic { get; set; }
4382 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4384 public MethodGroupExpr BestCandidateNewMethodGroup {
4386 return best_candidate_extension_group;
4391 // Return type can be different between best candidate and closest override
4393 public TypeSpec BestCandidateReturnType {
4395 return best_candidate_return_type;
4399 public IErrorHandler CustomErrors {
4401 return custom_errors;
4404 custom_errors = value;
4408 TypeSpec DelegateType {
4410 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4411 throw new InternalErrorException ("Not running in delegate mode", loc);
4413 return members [0].DeclaringType;
4417 public IInstanceQualifier InstanceQualifier {
4419 return instance_qualifier;
4422 instance_qualifier = value;
4426 bool IsProbingOnly {
4428 return (restrictions & Restrictions.ProbingOnly) != 0;
4432 bool IsDelegateInvoke {
4434 return (restrictions & Restrictions.DelegateInvoke) != 0;
4441 // 7.4.3.3 Better conversion from expression
4442 // Returns : 1 if a->p is better,
4443 // 2 if a->q is better,
4444 // 0 if neither is better
4446 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4448 TypeSpec argument_type = a.Type;
4451 // Exactly matching Expression phase
4455 // If argument is an anonymous function
4457 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4459 // p and q are delegate types or expression tree types
4461 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4462 if (q.MemberDefinition != p.MemberDefinition) {
4467 // Uwrap delegate from Expression<T>
4469 q = TypeManager.GetTypeArguments (q) [0];
4470 p = TypeManager.GetTypeArguments (p) [0];
4473 var p_m = Delegate.GetInvokeMethod (p);
4474 var q_m = Delegate.GetInvokeMethod (q);
4477 // With identical parameter lists
4479 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4487 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4489 if (p.Kind == MemberKind.Void) {
4490 return q.Kind != MemberKind.Void ? 2 : 0;
4494 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4496 if (q.Kind == MemberKind.Void) {
4497 return p.Kind != MemberKind.Void ? 1 : 0;
4500 var am = (AnonymousMethodExpression)a.Expr;
4503 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4504 // better conversion is performed between underlying types Y1 and Y2
4506 if (p.IsGenericTask || q.IsGenericTask) {
4507 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4508 q = q.TypeArguments [0];
4509 p = p.TypeArguments [0];
4515 // An inferred return type X exists for E in the context of the parameter list, and
4516 // an identity conversion exists from X to the return type of D
4518 var inferred_type = am.InferReturnType (ec, null, orig_q);
4519 if (inferred_type != null) {
4520 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4521 inferred_type = ec.BuiltinTypes.Object;
4523 if (inferred_type == p)
4526 if (inferred_type == q)
4532 if (argument_type == p)
4535 if (argument_type == q)
4538 return IsBetterConversionTarget (ec, p, q);
4541 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4543 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4545 if (p.Kind != MemberKind.Delegate) {
4546 p = TypeManager.GetTypeArguments (p) [0];
4549 if (q.Kind != MemberKind.Delegate) {
4550 q = TypeManager.GetTypeArguments (q) [0];
4553 var p_m = Delegate.GetInvokeMethod (p);
4554 var q_m = Delegate.GetInvokeMethod (q);
4560 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4562 if (p.Kind == MemberKind.Void) {
4563 return q.Kind != MemberKind.Void ? 2 : 0;
4567 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4569 if (q.Kind == MemberKind.Void) {
4570 return p.Kind != MemberKind.Void ? 1 : 0;
4573 return IsBetterConversionTarget (rc, p, q);
4576 if (p.IsGenericTask && q.IsGenericTask) {
4577 q = q.TypeArguments [0];
4578 p = p.TypeArguments [0];
4579 return IsBetterConversionTarget (rc, p, q);
4583 if (p.IsNullableType) {
4584 p = Nullable.NullableInfo.GetUnderlyingType (p);
4585 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4586 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4589 // Spec expects implicit conversion check between p and q, q and p
4590 // to be done before nullable unwrapping but that's expensive operation.
4592 // Extra manual tweak is needed because BetterTypeConversion works on
4600 if (q.IsNullableType) {
4601 q = Nullable.NullableInfo.GetUnderlyingType (q);
4602 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4603 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4609 return BetterTypeConversion (rc, p, q);
4613 // 7.4.3.4 Better conversion from type
4615 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4617 if (p == null || q == null)
4618 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4620 switch (p.BuiltinType) {
4621 case BuiltinTypeSpec.Type.Int:
4622 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4625 case BuiltinTypeSpec.Type.Long:
4626 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4629 case BuiltinTypeSpec.Type.SByte:
4630 switch (q.BuiltinType) {
4631 case BuiltinTypeSpec.Type.Byte:
4632 case BuiltinTypeSpec.Type.UShort:
4633 case BuiltinTypeSpec.Type.UInt:
4634 case BuiltinTypeSpec.Type.ULong:
4638 case BuiltinTypeSpec.Type.Short:
4639 switch (q.BuiltinType) {
4640 case BuiltinTypeSpec.Type.UShort:
4641 case BuiltinTypeSpec.Type.UInt:
4642 case BuiltinTypeSpec.Type.ULong:
4646 case BuiltinTypeSpec.Type.Dynamic:
4647 // LAMESPEC: Dynamic conversions is not considered
4648 p = ec.Module.Compiler.BuiltinTypes.Object;
4652 switch (q.BuiltinType) {
4653 case BuiltinTypeSpec.Type.Int:
4654 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4657 case BuiltinTypeSpec.Type.Long:
4658 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4661 case BuiltinTypeSpec.Type.SByte:
4662 switch (p.BuiltinType) {
4663 case BuiltinTypeSpec.Type.Byte:
4664 case BuiltinTypeSpec.Type.UShort:
4665 case BuiltinTypeSpec.Type.UInt:
4666 case BuiltinTypeSpec.Type.ULong:
4670 case BuiltinTypeSpec.Type.Short:
4671 switch (p.BuiltinType) {
4672 case BuiltinTypeSpec.Type.UShort:
4673 case BuiltinTypeSpec.Type.UInt:
4674 case BuiltinTypeSpec.Type.ULong:
4678 case BuiltinTypeSpec.Type.Dynamic:
4679 // LAMESPEC: Dynamic conversions is not considered
4680 q = ec.Module.Compiler.BuiltinTypes.Object;
4684 return BetterTypeConversionImplicitConversion (ec, p, q);
4687 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4689 // TODO: this is expensive
4690 Expression p_tmp = new EmptyExpression (p);
4691 Expression q_tmp = new EmptyExpression (q);
4693 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4694 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4696 if (p_to_q && !q_to_p)
4699 if (q_to_p && !p_to_q)
4706 /// Determines "Better function" between candidate
4707 /// and the current best match
4710 /// Returns a boolean indicating :
4711 /// false if candidate ain't better
4712 /// true if candidate is better than the current best match
4714 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4715 MemberSpec best, AParametersCollection bparam, bool best_params)
4717 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4718 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4720 int candidate_better_count = 0;
4721 int best_better_count = 0;
4723 bool are_equivalent = true;
4724 int args_count = args == null ? 0 : args.Count;
4728 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4731 // Default arguments are ignored for better decision
4732 if (a.IsDefaultArgument)
4736 // When comparing named argument the parameter type index has to be looked up
4737 // in original parameter set (override version for virtual members)
4739 NamedArgument na = a as NamedArgument;
4741 int idx = cparam.GetParameterIndexByName (na.Name);
4742 ct = candidate_pd.Types[idx];
4743 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4744 ct = TypeManager.GetElementType (ct);
4746 idx = bparam.GetParameterIndexByName (na.Name);
4747 bt = best_pd.Types[idx];
4748 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4749 bt = TypeManager.GetElementType (bt);
4751 ct = candidate_pd.Types[c_idx];
4752 bt = best_pd.Types[b_idx];
4754 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4755 ct = TypeManager.GetElementType (ct);
4759 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4760 bt = TypeManager.GetElementType (bt);
4765 if (TypeSpecComparer.IsEqual (ct, bt))
4768 are_equivalent = false;
4769 int result = BetterExpressionConversion (ec, a, ct, bt);
4771 // for each argument, the conversion to 'ct' should be no worse than
4772 // the conversion to 'bt'.
4775 // No optional parameters tie breaking rules for delegates overload resolution
4777 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4780 ++best_better_count;
4784 // for at least one argument, the conversion to 'ct' should be better than
4785 // the conversion to 'bt'.
4787 ++candidate_better_count;
4790 if (candidate_better_count != 0 && best_better_count == 0)
4793 if (best_better_count > 0 && candidate_better_count == 0)
4797 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4799 if (!are_equivalent) {
4800 while (j < args_count && !args [j++].IsDefaultArgument) ;
4803 // A candidate with no default parameters is still better when there
4804 // is no better expression conversion and does not have more parameters
4806 if (candidate_pd.Count < best_pd.Count) {
4807 if (candidate_params)
4810 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4813 if (best_pd.FixedParameters [j].HasDefaultValue)
4816 } else if (candidate_pd.Count == best_pd.Count) {
4817 if (candidate_params)
4820 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4823 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4831 // If candidate is applicable in its normal form and best has a params array and is applicable
4832 // only in its expanded form, then candidate is better
4834 if (candidate_params != best_params)
4835 return !candidate_params;
4838 // We have not reached end of parameters list due to params or used default parameters
4840 bool defaults_ambiguity = false;
4841 while (j < candidate_pd.Count && j < best_pd.Count) {
4842 var cand_param = candidate_pd.FixedParameters [j];
4843 var best_param = best_pd.FixedParameters [j];
4845 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4846 return cand_param.HasDefaultValue;
4848 defaults_ambiguity = true;
4849 if (candidate_pd.Count == best_pd.Count) {
4853 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4854 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4856 if (cand_param.HasDefaultValue) {
4865 // Neither is better when not all arguments are provided
4867 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4868 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4869 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4874 if (candidate_pd.Count != best_pd.Count) {
4875 if (defaults_ambiguity && best_pd.Count - 1 == j)
4876 return best_pd.HasParams;
4878 return candidate_pd.Count < best_pd.Count;
4882 // One is a non-generic method and second is a generic method, then non-generic is better
4884 if (best.IsGeneric != candidate.IsGeneric)
4885 return best.IsGeneric;
4888 // Both methods have the same number of parameters, and the parameters have equal types
4889 // Pick the "more specific" signature using rules over original (non-inflated) types
4891 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4892 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4894 bool specific_at_least_once = false;
4895 for (j = 0; j < args_count; ++j) {
4896 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4898 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4899 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4901 ct = candidate_def_pd.Types[j];
4902 bt = best_def_pd.Types[j];
4907 TypeSpec specific = MoreSpecific (ct, bt);
4911 specific_at_least_once = true;
4914 if (specific_at_least_once)
4920 static bool CheckInflatedArguments (MethodSpec ms)
4922 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4925 // Setup constraint checker for probing only
4926 ConstraintChecker cc = new ConstraintChecker (null);
4928 var mp = ms.Parameters.Types;
4929 for (int i = 0; i < mp.Length; ++i) {
4930 var type = mp[i] as InflatedTypeSpec;
4934 var targs = type.TypeArguments;
4935 if (targs.Length == 0)
4938 // TODO: Checking inflated MVAR arguments should be enough
4939 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4946 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4948 rc.Report.Error (1729, loc,
4949 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4950 type.GetSignatureForError (), argCount.ToString ());
4954 // Determines if the candidate method is applicable to the given set of arguments
4955 // There could be two different set of parameters for same candidate where one
4956 // is the closest override for default values and named arguments checks and second
4957 // one being the virtual base for the parameter types and modifiers.
4959 // A return value rates candidate method compatibility,
4961 // 0 = the best, int.MaxValue = the worst
4963 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)
4966 // Each step has allocated 10 values, it can overflow for
4967 // more than 10 arguments but that's ok as it's used for
4968 // better error reporting only
4970 const int ArgumentCountMismatch = 1000000000;
4971 const int NamedArgumentsMismatch = 100000000;
4972 const int DefaultArgumentMismatch = 10000000;
4973 const int UnexpectedTypeArguments = 1000000;
4974 const int TypeArgumentsMismatch = 100000;
4975 const int InflatedTypesMismatch = 10000;
4977 // Parameters of most-derived type used mainly for named and optional parameters
4978 var pd = pm.Parameters;
4980 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4981 // params modifier instead of most-derived type
4982 var cpd = ((IParametersMember) candidate).Parameters;
4983 int param_count = pd.Count;
4984 int optional_count = 0;
4986 Arguments orig_args = arguments;
4988 if (arg_count != param_count) {
4990 // No arguments expansion when doing exact match for delegates
4992 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4993 for (int i = 0; i < pd.Count; ++i) {
4994 if (pd.FixedParameters[i].HasDefaultValue) {
4995 optional_count = pd.Count - i;
5001 if (optional_count != 0) {
5002 // Readjust expected number when params used
5003 if (cpd.HasParams) {
5005 if (arg_count < param_count)
5007 } else if (arg_count > param_count) {
5008 int args_gap = System.Math.Abs (arg_count - param_count);
5009 return ArgumentCountMismatch + args_gap;
5010 } else if (arg_count < param_count - optional_count) {
5011 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
5012 return ArgumentCountMismatch + args_gap;
5014 } else if (arg_count != param_count) {
5015 int args_gap = System.Math.Abs (arg_count - param_count);
5017 return ArgumentCountMismatch + args_gap;
5018 if (arg_count < param_count - 1)
5019 return ArgumentCountMismatch + args_gap;
5022 // Resize to fit optional arguments
5023 if (optional_count != 0) {
5024 if (arguments == null) {
5025 arguments = new Arguments (optional_count);
5027 // Have to create a new container, so the next run can do same
5028 var resized = new Arguments (param_count);
5029 resized.AddRange (arguments);
5030 arguments = resized;
5033 for (int i = arg_count; i < param_count; ++i)
5034 arguments.Add (null);
5038 if (arg_count > 0) {
5040 // Shuffle named arguments to the right positions if there are any
5042 if (arguments[arg_count - 1] is NamedArgument) {
5043 arg_count = arguments.Count;
5045 for (int i = 0; i < arg_count; ++i) {
5046 bool arg_moved = false;
5048 NamedArgument na = arguments[i] as NamedArgument;
5052 int index = pd.GetParameterIndexByName (na.Name);
5054 // Named parameter not found
5056 return NamedArgumentsMismatch - i;
5058 // already reordered
5063 if (index >= param_count) {
5064 // When using parameters which should not be available to the user
5065 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5068 arguments.Add (null);
5072 if (index == arg_count)
5073 return NamedArgumentsMismatch - i - 1;
5075 temp = arguments [index];
5077 // The slot has been taken by positional argument
5078 if (temp != null && !(temp is NamedArgument))
5079 return NamedArgumentsMismatch - i - 1;
5083 arguments = arguments.MarkOrderedArgument (na);
5087 if (arguments == orig_args) {
5088 arguments = new Arguments (orig_args.Count);
5089 arguments.AddRange (orig_args);
5092 arguments[index] = arguments[i];
5093 arguments[i] = temp;
5100 arg_count = arguments.Count;
5102 } else if (arguments != null) {
5103 arg_count = arguments.Count;
5107 // Don't do any expensive checks when the candidate cannot succeed
5109 if (arg_count != param_count && !cpd.HasParams)
5110 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5112 var dep = candidate.GetMissingDependencies ();
5114 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5119 // 1. Handle generic method using type arguments when specified or type inference
5122 var ms = candidate as MethodSpec;
5123 if (ms != null && ms.IsGeneric) {
5124 if (type_arguments != null) {
5125 var g_args_count = ms.Arity;
5126 if (g_args_count != type_arguments.Count)
5127 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5129 if (type_arguments.Arguments != null)
5130 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5133 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5134 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5135 // candidate was found use the set to report more details about what was wrong with lambda body.
5136 // The general idea is to distinguish between code errors and errors caused by
5137 // trial-and-error type inference
5139 if (lambda_conv_msgs == null) {
5140 for (int i = 0; i < arg_count; i++) {
5141 Argument a = arguments[i];
5145 var am = a.Expr as AnonymousMethodExpression;
5147 if (lambda_conv_msgs == null)
5148 lambda_conv_msgs = new SessionReportPrinter ();
5150 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5155 var ti = new TypeInference (arguments);
5156 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5159 return TypeArgumentsMismatch - ti.InferenceScore;
5162 // Clear any error messages when the result was success
5164 if (lambda_conv_msgs != null)
5165 lambda_conv_msgs.ClearSession ();
5167 if (i_args.Length != 0) {
5169 for (int i = 0; i < i_args.Length; ++i) {
5170 var ta = i_args [i];
5171 if (!ta.IsAccessible (ec))
5172 return TypeArgumentsMismatch - i;
5176 ms = ms.MakeGenericMethod (ec, i_args);
5181 // Type arguments constraints have to match for the method to be applicable
5183 if (!CheckInflatedArguments (ms)) {
5185 return InflatedTypesMismatch;
5189 // We have a generic return type and at same time the method is override which
5190 // means we have to also inflate override return type in case the candidate is
5191 // best candidate and override return type is different to base return type.
5193 // virtual Foo<T, object> with override Foo<T, dynamic>
5195 if (candidate != pm) {
5196 MethodSpec override_ms = (MethodSpec) pm;
5197 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5198 returnType = inflator.Inflate (returnType);
5200 returnType = ms.ReturnType;
5207 if (type_arguments != null)
5208 return UnexpectedTypeArguments;
5214 // 2. Each argument has to be implicitly convertible to method parameter
5216 Parameter.Modifier p_mod = 0;
5219 for (int i = 0; i < arg_count; i++) {
5220 Argument a = arguments[i];
5222 var fp = pd.FixedParameters[i];
5223 if (!fp.HasDefaultValue) {
5224 arguments = orig_args;
5225 return arg_count * 2 + 2;
5229 // Get the default value expression, we can use the same expression
5230 // if the type matches
5232 Expression e = fp.DefaultValue;
5234 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5236 // Restore for possible error reporting
5237 for (int ii = i; ii < arg_count; ++ii)
5238 arguments.RemoveAt (i);
5240 return (arg_count - i) * 2 + 1;
5244 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5246 // LAMESPEC: Attributes can be mixed together with build-in priority
5248 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5249 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5250 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5251 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5252 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5253 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5257 arguments[i] = new Argument (e, Argument.AType.Default);
5261 if (p_mod != Parameter.Modifier.PARAMS) {
5262 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5264 } else if (!params_expanded_form) {
5265 params_expanded_form = true;
5266 pt = ((ElementTypeSpec) pt).Element;
5272 if (!params_expanded_form) {
5273 if (a.IsExtensionType) {
5274 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5279 score = IsArgumentCompatible (ec, a, p_mod, pt);
5282 dynamicArgument = true;
5287 // It can be applicable in expanded form (when not doing exact match like for delegates)
5289 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5290 if (!params_expanded_form) {
5291 pt = ((ElementTypeSpec) pt).Element;
5295 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5298 params_expanded_form = true;
5299 dynamicArgument = true;
5300 } else if (score == 0 || arg_count > pd.Count) {
5301 params_expanded_form = true;
5306 if (params_expanded_form)
5308 return (arg_count - i) * 2 + score;
5313 // Restore original arguments for dynamic binder to keep the intention of original source code
5315 if (dynamicArgument)
5316 arguments = orig_args;
5321 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5323 if (e is Constant && e.Type == ptype)
5327 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5329 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5330 e = new MemberAccess (new MemberAccess (new MemberAccess (
5331 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5332 } else if (e is Constant) {
5334 // Handles int to int? conversions, DefaultParameterValue check
5336 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5340 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5343 return e.Resolve (ec);
5347 // Tests argument compatibility with the parameter
5348 // The possible return values are
5350 // 1 - modifier mismatch
5351 // 2 - type mismatch
5352 // -1 - dynamic binding required
5354 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5357 // Types have to be identical when ref or out modifer
5358 // is used and argument is not of dynamic type
5360 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5361 var arg_type = argument.Type;
5363 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5365 // Using dynamic for ref/out parameter can still succeed at runtime
5367 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5373 if (arg_type != parameter) {
5374 if (arg_type == InternalType.VarOutType)
5378 // Do full equality check after quick path
5380 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5382 // Using dynamic for ref/out parameter can still succeed at runtime
5384 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5392 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5396 // Use implicit conversion in all modes to return same candidates when the expression
5397 // is used as argument or delegate conversion
5399 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5400 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5407 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5409 if (p.IsGenericParameter != q.IsGenericParameter)
5410 return p.IsGenericParameter ? q : p;
5412 var ac_p = p as ArrayContainer;
5414 var ac_q = q as ArrayContainer;
5418 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5419 if (specific == ac_p.Element)
5421 if (specific == ac_q.Element)
5427 if (p.IsGeneric && q.IsGeneric) {
5428 var pargs = p.TypeArguments;
5429 var qargs = q.TypeArguments;
5431 bool p_specific_at_least_once = false;
5432 bool q_specific_at_least_once = false;
5434 for (int i = 0; i < pargs.Length; i++) {
5435 TypeSpec specific = MoreSpecific (pargs [i], qargs [i]);
5436 if (specific == pargs [i])
5437 p_specific_at_least_once = true;
5438 if (specific == qargs [i])
5439 q_specific_at_least_once = true;
5442 if (p_specific_at_least_once && !q_specific_at_least_once)
5444 if (!p_specific_at_least_once && q_specific_at_least_once)
5452 // Find the best method from candidate list
5454 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5456 List<AmbiguousCandidate> ambiguous_candidates = null;
5458 MemberSpec best_candidate;
5459 Arguments best_candidate_args = null;
5460 bool best_candidate_params = false;
5461 bool best_candidate_dynamic = false;
5462 int best_candidate_rate;
5463 IParametersMember best_parameter_member = null;
5465 int args_count = args != null ? args.Count : 0;
5467 Arguments candidate_args = args;
5468 bool error_mode = false;
5469 MemberSpec invocable_member = null;
5470 int applicable_candidates = 0;
5473 best_candidate = null;
5474 best_candidate_rate = int.MaxValue;
5476 var type_members = members;
5478 for (int i = 0; i < type_members.Count; ++i) {
5479 var member = type_members[i];
5482 // Methods in a base class are not candidates if any method in a derived
5483 // class is applicable
5485 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5489 if (!member.IsAccessible (rc))
5492 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5495 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5496 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5501 IParametersMember pm = member as IParametersMember;
5504 // Will use it later to report ambiguity between best method and invocable member
5506 if (Invocation.IsMemberInvocable (member))
5507 invocable_member = member;
5513 // Overload resolution is looking for base member but using parameter names
5514 // and default values from the closest member. That means to do expensive lookup
5515 // for the closest override for virtual or abstract members
5517 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5518 var override_params = base_provider.GetOverrideMemberParameters (member);
5519 if (override_params != null)
5520 pm = override_params;
5524 // Check if the member candidate is applicable
5526 bool params_expanded_form = false;
5527 bool dynamic_argument = false;
5528 TypeSpec rt = pm.MemberType;
5529 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5531 if (lambda_conv_msgs != null)
5532 lambda_conv_msgs.EndSession ();
5535 // How does it score compare to others
5537 if (candidate_rate < best_candidate_rate) {
5539 // Fatal error (missing dependency), cannot continue
5540 if (candidate_rate < 0)
5543 applicable_candidates = 1;
5544 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5545 // Only parameterless methods are considered
5547 best_candidate_rate = candidate_rate;
5548 best_candidate = member;
5549 best_candidate_args = candidate_args;
5550 best_candidate_params = params_expanded_form;
5551 best_candidate_dynamic = dynamic_argument;
5552 best_parameter_member = pm;
5553 best_candidate_return_type = rt;
5555 } else if (candidate_rate == 0) {
5557 // The member look is done per type for most operations but sometimes
5558 // it's not possible like for binary operators overload because they
5559 // are unioned between 2 sides
5561 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5562 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5566 ++applicable_candidates;
5568 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5570 // We pack all interface members into top level type which makes the overload resolution
5571 // more complicated for interfaces. We compensate it by removing methods with same
5572 // signature when building the cache hence this path should not really be hit often
5575 // interface IA { void Foo (int arg); }
5576 // interface IB : IA { void Foo (params int[] args); }
5578 // IB::Foo is the best overload when calling IB.Foo (1)
5581 if (ambiguous_candidates != null) {
5582 foreach (var amb_cand in ambiguous_candidates) {
5583 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5592 ambiguous_candidates = null;
5595 // Is the new candidate better
5596 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5600 best_candidate = member;
5601 best_candidate_args = candidate_args;
5602 best_candidate_params = params_expanded_form;
5603 best_candidate_dynamic = dynamic_argument;
5604 best_parameter_member = pm;
5605 best_candidate_return_type = rt;
5607 // It's not better but any other found later could be but we are not sure yet
5608 if (ambiguous_candidates == null)
5609 ambiguous_candidates = new List<AmbiguousCandidate> ();
5611 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5615 // Restore expanded arguments
5616 candidate_args = args;
5618 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5621 // We've found exact match
5623 if (best_candidate_rate == 0)
5627 // Try extension methods lookup when no ordinary method match was found and provider enables it
5630 var emg = base_provider.LookupExtensionMethod (rc);
5632 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5634 best_candidate_extension_group = emg;
5635 return (T) (MemberSpec) emg.BestCandidate;
5640 // Don't run expensive error reporting mode for probing
5647 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5650 lambda_conv_msgs = null;
5655 // No best member match found, report an error
5657 if (best_candidate_rate != 0 || error_mode) {
5658 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5662 if (best_candidate_dynamic) {
5663 if (args[0].IsExtensionType) {
5664 rc.Report.Error (1973, loc,
5665 "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",
5666 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5670 // Check type constraints only when explicit type arguments are used
5672 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5673 MethodSpec bc = best_candidate as MethodSpec;
5674 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5675 ConstraintChecker cc = new ConstraintChecker (rc);
5676 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5680 BestCandidateIsDynamic = true;
5685 // These flags indicates we are running delegate probing conversion. No need to
5686 // do more expensive checks
5688 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5689 return (T) best_candidate;
5691 if (ambiguous_candidates != null) {
5693 // Now check that there are no ambiguities i.e the selected method
5694 // should be better than all the others
5696 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5697 var candidate = ambiguous_candidates [ix];
5699 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5700 var ambiguous = candidate.Member;
5701 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5702 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5703 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5704 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5705 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5708 return (T) best_candidate;
5713 if (invocable_member != null && !IsProbingOnly) {
5714 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5715 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5716 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5717 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5721 // And now check if the arguments are all
5722 // compatible, perform conversions if
5723 // necessary etc. and return if everything is
5726 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5729 if (best_candidate == null)
5733 // Don't run possibly expensive checks in probing mode
5735 if (!IsProbingOnly && !rc.IsInProbingMode) {
5737 // Check ObsoleteAttribute on the best method
5739 best_candidate.CheckObsoleteness (rc, loc);
5741 best_candidate.MemberDefinition.SetIsUsed ();
5744 args = best_candidate_args;
5745 return (T) best_candidate;
5748 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5750 return ResolveMember<MethodSpec> (rc, ref args);
5753 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5754 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5756 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5759 if (a.Type == InternalType.ErrorType)
5762 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5763 ec.Report.SymbolRelatedToPreviousError (method);
5764 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5765 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5766 TypeManager.CSharpSignature (method));
5769 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5770 TypeManager.CSharpSignature (method));
5771 } else if (IsDelegateInvoke) {
5772 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5773 DelegateType.GetSignatureForError ());
5775 ec.Report.SymbolRelatedToPreviousError (method);
5776 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5777 method.GetSignatureForError ());
5780 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5782 string index = (idx + 1).ToString ();
5783 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5784 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5785 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5786 index, Parameter.GetModifierSignature (a.Modifier));
5788 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5789 index, Parameter.GetModifierSignature (mod));
5791 string p1 = a.GetSignatureForError ();
5792 string p2 = paramType.GetSignatureForError ();
5795 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5796 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5799 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5800 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5801 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5804 ec.Report.Error (1503, a.Expr.Location,
5805 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5810 // We have failed to find exact match so we return error info about the closest match
5812 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5814 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5815 int arg_count = args == null ? 0 : args.Count;
5817 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5818 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5819 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5823 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5828 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5829 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5830 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5834 // For candidates which match on parameters count report more details about incorrect arguments
5837 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5838 // Reject any inaccessible member
5839 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5840 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5841 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5845 var ms = best_candidate as MethodSpec;
5846 if (ms != null && ms.IsGeneric) {
5847 bool constr_ok = true;
5848 if (ms.TypeArguments != null)
5849 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5851 if (ta_count == 0 && ms.TypeArguments == null) {
5852 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5856 rc.Report.Error (411, loc,
5857 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5858 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5865 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5871 // We failed to find any method with correct argument count, report best candidate
5873 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5876 if (best_candidate.Kind == MemberKind.Constructor) {
5877 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5878 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5879 } else if (IsDelegateInvoke) {
5880 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5881 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5882 DelegateType.GetSignatureForError (), arg_count.ToString ());
5884 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5885 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5886 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5887 name, arg_count.ToString ());
5891 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5893 var p = ((IParametersMember)best_candidate).Parameters;
5898 for (int i = p.Count - 1; i != 0; --i) {
5899 var fp = p.FixedParameters [i];
5900 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5910 foreach (var arg in args) {
5911 var na = arg as NamedArgument;
5915 if (na.Name == name) {
5924 return args.Count + 1 == pm.Parameters.Count;
5927 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5929 var pd = pm.Parameters;
5930 var cpd = ((IParametersMember) member).Parameters;
5931 var ptypes = cpd.Types;
5933 Parameter.Modifier p_mod = 0;
5935 int a_idx = 0, a_pos = 0;
5937 ArrayInitializer params_initializers = null;
5938 bool has_unsafe_arg = pm.MemberType.IsPointer;
5939 int arg_count = args == null ? 0 : args.Count;
5941 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5946 if (p_mod != Parameter.Modifier.PARAMS) {
5947 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5949 has_unsafe_arg |= pt.IsPointer;
5951 if (p_mod == Parameter.Modifier.PARAMS) {
5952 if (chose_params_expanded) {
5953 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5954 pt = TypeManager.GetElementType (pt);
5960 // Types have to be identical when ref or out modifer is used
5962 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5963 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5966 var arg_type = a.Type;
5970 if (arg_type == InternalType.VarOutType) {
5972 // Set underlying variable type based on parameter type
5974 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5978 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5982 NamedArgument na = a as NamedArgument;
5984 int name_index = pd.GetParameterIndexByName (na.Name);
5985 if (name_index < 0 || name_index >= pd.Count) {
5986 if (IsDelegateInvoke) {
5987 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5988 ec.Report.Error (1746, na.Location,
5989 "The delegate `{0}' does not contain a parameter named `{1}'",
5990 DelegateType.GetSignatureForError (), na.Name);
5992 ec.Report.SymbolRelatedToPreviousError (member);
5993 ec.Report.Error (1739, na.Location,
5994 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5995 TypeManager.CSharpSignature (member), na.Name);
5997 } else if (args[name_index] != a && args[name_index] != null) {
5998 if (IsDelegateInvoke)
5999 ec.Report.SymbolRelatedToPreviousError (DelegateType);
6001 ec.Report.SymbolRelatedToPreviousError (member);
6003 ec.Report.Error (1744, na.Location,
6004 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
6009 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
6012 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
6013 if (a.IsExtensionType) {
6014 // TODO: Should report better message type, something similar to CS1928/1929 instead of
6015 // CS1061 but that still better than confusing CS0123
6016 var ma = new MemberAccess (a.Expr, member.Name, loc);
6017 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
6019 custom_errors.NoArgumentMatch (ec, member);
6025 if (a.IsExtensionType) {
6026 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6029 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6031 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6034 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6041 // Convert params arguments to an array initializer
6043 if (params_initializers != null) {
6044 // we choose to use 'a.Expr' rather than 'conv' so that
6045 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6046 params_initializers.Add (a.Expr);
6047 args.RemoveAt (a_idx--);
6053 // Update the argument with the implicit conversion
6057 if (a_idx != arg_count) {
6059 // Convert all var out argument to error type for less confusing error reporting
6060 // when no matching overload is found
6062 for (; a_idx < arg_count; a_idx++) {
6063 var arg = args [a_idx];
6067 if (arg.Type == InternalType.VarOutType) {
6068 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6072 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6077 // Fill not provided arguments required by params modifier
6079 if (params_initializers == null && arg_count + 1 == pd.Count) {
6081 args = new Arguments (1);
6083 pt = ptypes[pd.Count - 1];
6084 pt = TypeManager.GetElementType (pt);
6085 has_unsafe_arg |= pt.IsPointer;
6086 params_initializers = new ArrayInitializer (0, loc);
6090 // Append an array argument with all params arguments
6092 if (params_initializers != null) {
6093 args.Add (new Argument (
6094 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6098 if (has_unsafe_arg) {
6099 if (ec.CurrentIterator != null) {
6100 Expression.UnsafeInsideIteratorError (ec, loc);
6101 } else if (!ec.IsUnsafe) {
6102 Expression.UnsafeError (ec, loc);
6107 // We could infer inaccesible type arguments
6109 if (type_arguments == null && member.IsGeneric) {
6110 var ms = (MethodSpec) member;
6111 foreach (var ta in ms.TypeArguments) {
6112 if (!ta.IsAccessible (ec)) {
6113 ec.Report.SymbolRelatedToPreviousError (ta);
6114 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6124 public class ConstantExpr : MemberExpr
6126 readonly ConstSpec constant;
6128 public ConstantExpr (ConstSpec constant, Location loc)
6130 this.constant = constant;
6134 public override string Name {
6135 get { throw new NotImplementedException (); }
6138 public override string KindName {
6139 get { return "constant"; }
6142 public override bool IsInstance {
6143 get { return !IsStatic; }
6146 public override bool IsStatic {
6147 get { return true; }
6150 protected override TypeSpec DeclaringType {
6151 get { return constant.DeclaringType; }
6154 public override Expression CreateExpressionTree (ResolveContext ec)
6156 throw new NotSupportedException ("ET");
6159 protected override Expression DoResolve (ResolveContext rc)
6161 ResolveInstanceExpression (rc, null);
6162 DoBestMemberChecks (rc, constant);
6164 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6165 eclass = ExprClass.Value;
6166 type = constant.MemberType;
6170 var c = constant.GetConstant (rc);
6172 // Creates reference expression to the constant value
6173 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6176 public override void Emit (EmitContext ec)
6178 throw new NotSupportedException ();
6181 public override string GetSignatureForError ()
6183 return constant.GetSignatureForError ();
6186 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6188 constant.CheckObsoleteness (rc, expr.Location);
6191 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6193 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6198 // Fully resolved expression that references a Field
6200 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6202 protected FieldSpec spec;
6203 VariableInfo variable_info;
6205 LocalTemporary temp;
6208 protected FieldExpr (Location l)
6213 public FieldExpr (FieldSpec spec, Location loc)
6218 type = spec.MemberType;
6221 public FieldExpr (FieldBase fi, Location l)
6228 public override string Name {
6234 public bool IsHoisted {
6236 IVariableReference hv = InstanceExpression as IVariableReference;
6237 return hv != null && hv.IsHoisted;
6241 public override bool IsInstance {
6243 return !spec.IsStatic;
6247 public override bool IsStatic {
6249 return spec.IsStatic;
6253 public override string KindName {
6254 get { return "field"; }
6257 public FieldSpec Spec {
6263 protected override TypeSpec DeclaringType {
6265 return spec.DeclaringType;
6269 public VariableInfo VariableInfo {
6271 return variable_info;
6277 public override string GetSignatureForError ()
6279 return spec.GetSignatureForError ();
6282 public bool IsMarshalByRefAccess (ResolveContext rc)
6284 // Checks possible ldflda of field access expression
6285 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6286 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6287 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6290 public void SetHasAddressTaken ()
6292 IVariableReference vr = InstanceExpression as IVariableReference;
6294 vr.SetHasAddressTaken ();
6298 protected override void CloneTo (CloneContext clonectx, Expression target)
6300 var t = (FieldExpr) target;
6302 if (InstanceExpression != null)
6303 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6306 public override Expression CreateExpressionTree (ResolveContext ec)
6308 if (ConditionalAccess) {
6309 Error_NullShortCircuitInsideExpressionTree (ec);
6312 return CreateExpressionTree (ec, true);
6315 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6318 Expression instance;
6320 if (InstanceExpression == null) {
6321 instance = new NullLiteral (loc);
6322 } else if (convertInstance) {
6323 instance = InstanceExpression.CreateExpressionTree (ec);
6325 args = new Arguments (1);
6326 args.Add (new Argument (InstanceExpression));
6327 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6330 args = Arguments.CreateForExpressionTree (ec, null,
6332 CreateTypeOfExpression ());
6334 return CreateExpressionFactoryCall (ec, "Field", args);
6337 public Expression CreateTypeOfExpression ()
6339 return new TypeOfField (spec, loc);
6342 protected override Expression DoResolve (ResolveContext ec)
6344 spec.MemberDefinition.SetIsUsed ();
6346 return DoResolve (ec, null);
6349 Expression DoResolve (ResolveContext ec, Expression rhs)
6351 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6354 ResolveConditionalAccessReceiver (ec);
6356 if (ResolveInstanceExpression (ec, rhs)) {
6357 // Resolve the field's instance expression while flow analysis is turned
6358 // off: when accessing a field "a.b", we must check whether the field
6359 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6361 if (lvalue_instance) {
6362 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6364 Expression right_side =
6365 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6367 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6369 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6372 if (InstanceExpression == null)
6376 DoBestMemberChecks (ec, spec);
6378 if (conditional_access_receiver)
6379 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6382 var fb = spec as FixedFieldSpec;
6383 IVariableReference var = InstanceExpression as IVariableReference;
6386 IFixedExpression fe = InstanceExpression as IFixedExpression;
6387 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6388 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6391 if (InstanceExpression.eclass != ExprClass.Variable) {
6392 ec.Report.SymbolRelatedToPreviousError (spec);
6393 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6394 TypeManager.GetFullNameSignature (spec));
6395 } else if (var != null && var.IsHoisted) {
6396 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6399 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6403 // Set flow-analysis variable info for struct member access. It will be check later
6404 // for precise error reporting
6406 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6407 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6410 if (conditional_access_receiver)
6411 type = LiftMemberType (ec, type);
6413 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6414 return Constant.CreateConstantFromValue (type, null, loc);
6416 eclass = ExprClass.Variable;
6420 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6422 spec.CheckObsoleteness (rc, expr.Location);
6425 public void SetFieldAssigned (FlowAnalysisContext fc)
6430 bool lvalue_instance = spec.DeclaringType.IsStruct;
6431 if (lvalue_instance) {
6432 var var = InstanceExpression as IVariableReference;
6433 if (var != null && var.VariableInfo != null) {
6434 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6438 var fe = InstanceExpression as FieldExpr;
6440 Expression instance;
6443 instance = fe.InstanceExpression;
6444 var fe_instance = instance as FieldExpr;
6445 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6446 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6447 var var = InstanceExpression as IVariableReference;
6448 if (var != null && var.VariableInfo == null) {
6449 var var_inst = instance as IVariableReference;
6450 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6451 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6455 if (fe_instance != null) {
6464 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6465 instance.FlowAnalysis (fc);
6467 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6468 InstanceExpression.FlowAnalysis (fc);
6472 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6474 // The return value is always null. Returning a value simplifies calling code.
6476 if (right_side == EmptyExpression.OutAccess) {
6478 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6479 GetSignatureForError ());
6481 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6482 GetSignatureForError ());
6488 if (right_side == EmptyExpression.LValueMemberAccess) {
6489 // Already reported as CS1648/CS1650
6493 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6495 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6496 GetSignatureForError ());
6498 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6499 GetSignatureForError ());
6505 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6506 GetSignatureForError ());
6508 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6509 GetSignatureForError ());
6515 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6517 if (HasConditionalAccess ())
6518 Error_NullPropagatingLValue (ec);
6520 if (spec is FixedFieldSpec) {
6521 // It could be much better error message but we want to be error compatible
6522 Error_ValueAssignment (ec, right_side);
6525 Expression e = DoResolve (ec, right_side);
6530 spec.MemberDefinition.SetIsAssigned ();
6532 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6533 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6534 ec.Report.Warning (420, 1, loc,
6535 "`{0}': A volatile field references will not be treated as volatile",
6536 spec.GetSignatureForError ());
6539 if (spec.IsReadOnly) {
6540 // InitOnly fields can only be assigned in constructors or initializers
6541 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6542 return Error_AssignToReadonly (ec, right_side);
6544 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6546 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6547 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6548 return Error_AssignToReadonly (ec, right_side);
6549 // static InitOnly fields cannot be assigned-to in an instance constructor
6550 if (IsStatic && !ec.IsStatic)
6551 return Error_AssignToReadonly (ec, right_side);
6552 // instance constructors can't modify InitOnly fields of other instances of the same type
6553 if (!IsStatic && !(InstanceExpression is This))
6554 return Error_AssignToReadonly (ec, right_side);
6558 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6559 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6560 ec.Report.Warning (197, 1, loc,
6561 "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",
6562 GetSignatureForError ());
6565 eclass = ExprClass.Variable;
6569 public override void FlowAnalysis (FlowAnalysisContext fc)
6571 var var = InstanceExpression as IVariableReference;
6573 var vi = var.VariableInfo;
6574 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6575 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6579 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6580 var le = SkipLeftValueTypeAccess (InstanceExpression);
6582 le.FlowAnalysis (fc);
6588 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6590 base.FlowAnalysis (fc);
6592 if (conditional_access_receiver)
6593 fc.DefiniteAssignment = da;
6596 static Expression SkipLeftValueTypeAccess (Expression expr)
6598 if (!TypeSpec.IsValueType (expr.Type))
6601 if (expr is VariableReference)
6604 var fe = expr as FieldExpr;
6608 if (fe.InstanceExpression == null)
6611 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6614 public override int GetHashCode ()
6616 return spec.GetHashCode ();
6619 public bool IsFixed {
6622 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6624 IVariableReference variable = InstanceExpression as IVariableReference;
6625 if (variable != null)
6626 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6628 IFixedExpression fe = InstanceExpression as IFixedExpression;
6629 return fe != null && fe.IsFixed;
6633 public override bool Equals (object obj)
6635 FieldExpr fe = obj as FieldExpr;
6639 if (spec != fe.spec)
6642 if (InstanceExpression == null || fe.InstanceExpression == null)
6645 return InstanceExpression.Equals (fe.InstanceExpression);
6648 public void Emit (EmitContext ec, bool leave_copy)
6650 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6654 ec.Emit (OpCodes.Volatile);
6656 ec.Emit (OpCodes.Ldsfld, spec);
6658 var ca = ec.ConditionalAccess;
6661 if (conditional_access_receiver)
6662 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6664 EmitInstance (ec, false);
6667 // Optimization for build-in types
6668 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6669 ec.EmitLoadFromPtr (type);
6671 var ff = spec as FixedFieldSpec;
6673 ec.Emit (OpCodes.Ldflda, spec);
6674 ec.Emit (OpCodes.Ldflda, ff.Element);
6677 ec.Emit (OpCodes.Volatile);
6679 ec.Emit (OpCodes.Ldfld, spec);
6683 if (conditional_access_receiver) {
6684 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6685 ec.ConditionalAccess = ca;
6690 ec.Emit (OpCodes.Dup);
6692 temp = new LocalTemporary (this.Type);
6698 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6700 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6701 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6706 if (ConditionalAccess)
6707 throw new NotImplementedException ("null operator assignment");
6709 if (has_await_source)
6710 source = source.EmitToField (ec);
6712 EmitInstance (ec, prepared);
6717 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6718 ec.Emit (OpCodes.Dup);
6720 temp = new LocalTemporary (this.Type);
6725 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6726 ec.Emit (OpCodes.Volatile);
6728 spec.MemberDefinition.SetIsAssigned ();
6731 ec.Emit (OpCodes.Stsfld, spec);
6733 ec.Emit (OpCodes.Stfld, spec);
6735 if (ec.NotifyEvaluatorOnStore) {
6737 throw new NotImplementedException ("instance field write");
6740 ec.Emit (OpCodes.Dup);
6742 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6753 // Emits store to field with prepared values on stack
6755 public void EmitAssignFromStack (EmitContext ec)
6758 ec.Emit (OpCodes.Stsfld, spec);
6760 ec.Emit (OpCodes.Stfld, spec);
6764 public override void Emit (EmitContext ec)
6769 public override void EmitSideEffect (EmitContext ec)
6771 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6773 if (is_volatile) // || is_marshal_by_ref ())
6774 base.EmitSideEffect (ec);
6777 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6779 if ((mode & AddressOp.Store) != 0)
6780 spec.MemberDefinition.SetIsAssigned ();
6781 if ((mode & AddressOp.Load) != 0)
6782 spec.MemberDefinition.SetIsUsed ();
6785 // Handle initonly fields specially: make a copy and then
6786 // get the address of the copy.
6789 if (spec.IsReadOnly){
6791 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6803 var temp = ec.GetTemporaryLocal (type);
6804 ec.Emit (OpCodes.Stloc, temp);
6805 ec.Emit (OpCodes.Ldloca, temp);
6811 ec.Emit (OpCodes.Ldsflda, spec);
6814 EmitInstance (ec, false);
6815 ec.Emit (OpCodes.Ldflda, spec);
6819 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6821 return MakeExpression (ctx);
6824 public override SLE.Expression MakeExpression (BuilderContext ctx)
6827 return base.MakeExpression (ctx);
6829 return SLE.Expression.Field (
6830 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6831 spec.GetMetaInfo ());
6835 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6837 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6843 // Expression that evaluates to a Property.
6845 // This is not an LValue because we need to re-write the expression. We
6846 // can not take data from the stack and store it.
6848 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6850 Arguments arguments;
6851 FieldExpr backing_field;
6853 public PropertyExpr (PropertySpec spec, Location l)
6856 best_candidate = spec;
6857 type = spec.MemberType;
6862 protected override Arguments Arguments {
6871 protected override TypeSpec DeclaringType {
6873 return best_candidate.DeclaringType;
6877 public override string Name {
6879 return best_candidate.Name;
6883 public bool IsAutoPropertyAccess {
6885 var prop = best_candidate.MemberDefinition as Property;
6886 return prop != null && prop.BackingField != null;
6890 public override bool IsInstance {
6896 public override bool IsStatic {
6898 return best_candidate.IsStatic;
6902 public override string KindName {
6903 get { return "property"; }
6906 public PropertySpec PropertyInfo {
6908 return best_candidate;
6914 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6916 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6919 var args_count = arguments == null ? 0 : arguments.Count;
6920 if (args_count != body.Parameters.Count && args_count == 0)
6923 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6924 mg.InstanceExpression = InstanceExpression;
6929 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6931 return new PropertyExpr (spec, loc) {
6937 public override Expression CreateExpressionTree (ResolveContext ec)
6939 if (ConditionalAccess) {
6940 Error_NullShortCircuitInsideExpressionTree (ec);
6944 if (IsSingleDimensionalArrayLength ()) {
6945 args = new Arguments (1);
6946 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6947 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6950 args = new Arguments (2);
6951 if (InstanceExpression == null)
6952 args.Add (new Argument (new NullLiteral (loc)));
6954 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6955 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6956 return CreateExpressionFactoryCall (ec, "Property", args);
6959 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6961 DoResolveLValue (rc, null);
6962 return new TypeOfMethod (Setter, loc);
6965 public override string GetSignatureForError ()
6967 return best_candidate.GetSignatureForError ();
6970 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6973 return base.MakeExpression (ctx);
6975 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6979 public override SLE.Expression MakeExpression (BuilderContext ctx)
6982 return base.MakeExpression (ctx);
6984 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6988 void Error_PropertyNotValid (ResolveContext ec)
6990 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6991 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6992 GetSignatureForError ());
6995 bool IsSingleDimensionalArrayLength ()
6997 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
7000 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
7001 return ac != null && ac.Rank == 1;
7004 public override void Emit (EmitContext ec, bool leave_copy)
7007 // Special case: length of single dimension array property is turned into ldlen
7009 if (IsSingleDimensionalArrayLength ()) {
7010 if (conditional_access_receiver) {
7011 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7014 EmitInstance (ec, false);
7016 ec.Emit (OpCodes.Ldlen);
7017 ec.Emit (OpCodes.Conv_I4);
7019 if (conditional_access_receiver) {
7020 ec.CloseConditionalAccess (type);
7026 base.Emit (ec, leave_copy);
7029 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7031 if (backing_field != null) {
7032 backing_field.EmitAssign (ec, source, leave_copy, false);
7037 LocalTemporary await_source_arg = null;
7039 if (isCompound && !(source is DynamicExpressionStatement)) {
7040 emitting_compound_assignment = true;
7043 if (has_await_arguments) {
7044 await_source_arg = new LocalTemporary (Type);
7045 await_source_arg.Store (ec);
7047 args = new Arguments (1);
7048 args.Add (new Argument (await_source_arg));
7051 temp = await_source_arg;
7054 has_await_arguments = false;
7059 ec.Emit (OpCodes.Dup);
7060 temp = new LocalTemporary (this.Type);
7065 args = arguments ?? new Arguments (1);
7069 temp = new LocalTemporary (this.Type);
7071 args.Add (new Argument (temp));
7073 args.Add (new Argument (source));
7077 emitting_compound_assignment = false;
7079 var call = new CallEmitter ();
7080 call.InstanceExpression = InstanceExpression;
7082 call.InstanceExpressionOnStack = true;
7084 if (ConditionalAccess) {
7085 call.ConditionalAccess = true;
7089 call.Emit (ec, Setter, args, loc);
7091 call.EmitStatement (ec, Setter, args, loc);
7098 if (await_source_arg != null) {
7099 await_source_arg.Release (ec);
7103 public override void FlowAnalysis (FlowAnalysisContext fc)
7105 var prop = best_candidate.MemberDefinition as Property;
7106 if (prop != null && prop.BackingField != null) {
7107 var var = InstanceExpression as IVariableReference;
7109 var vi = var.VariableInfo;
7110 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7111 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7115 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7120 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7122 base.FlowAnalysis (fc);
7124 if (conditional_access_receiver)
7125 fc.DefiniteAssignment = da;
7128 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7130 eclass = ExprClass.PropertyAccess;
7132 if (best_candidate.IsNotCSharpCompatible) {
7133 Error_PropertyNotValid (rc);
7136 ResolveInstanceExpression (rc, right_side);
7138 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7139 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7140 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7142 type = p.MemberType;
7146 DoBestMemberChecks (rc, best_candidate);
7148 // Handling of com-imported properties with any number of default property parameters
7149 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7150 var p = best_candidate.Get.Parameters;
7151 arguments = new Arguments (p.Count);
7152 for (int i = 0; i < p.Count; ++i) {
7153 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7155 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7156 var p = best_candidate.Set.Parameters;
7157 arguments = new Arguments (p.Count - 1);
7158 for (int i = 0; i < p.Count - 1; ++i) {
7159 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7166 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7168 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7171 var prop = best_candidate.MemberDefinition as Property;
7172 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7173 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7177 prop = (Property)ps.MemberDefinition;
7180 var spec = prop.BackingField;
7184 if (rc.IsStatic != spec.IsStatic)
7187 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7190 backing_field = new FieldExpr (prop.BackingField, loc);
7191 backing_field.ResolveLValue (rc, rhs);
7195 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7197 if (!best_candidate.IsAccessible (rc))
7198 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7200 best_candidate.CheckObsoleteness (rc, expr.Location);
7203 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7205 if (backing_field != null) {
7206 backing_field.SetFieldAssigned (fc);
7210 if (!IsAutoPropertyAccess)
7213 var prop = best_candidate.MemberDefinition as Property;
7214 if (prop != null && prop.BackingField != null) {
7215 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7216 if (lvalue_instance) {
7217 var var = InstanceExpression as IVariableReference;
7218 if (var != null && var.VariableInfo != null) {
7219 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7225 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7227 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7231 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7233 // getter and setter can be different for base calls
7234 MethodSpec getter, setter;
7235 protected T best_candidate;
7237 protected LocalTemporary temp;
7238 protected bool emitting_compound_assignment;
7239 protected bool has_await_arguments;
7241 protected PropertyOrIndexerExpr (Location l)
7248 protected abstract Arguments Arguments { get; set; }
7250 public MethodSpec Getter {
7259 public MethodSpec Setter {
7270 protected override Expression DoResolve (ResolveContext ec)
7272 if (eclass == ExprClass.Unresolved) {
7273 ResolveConditionalAccessReceiver (ec);
7275 var expr = OverloadResolve (ec, null);
7280 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7281 return expr.Resolve (ec);
7284 if (conditional_access_receiver) {
7285 type = LiftMemberType (ec, type);
7289 if (!ResolveGetter (ec))
7295 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7297 if (HasConditionalAccess ())
7298 Error_NullPropagatingLValue (rc);
7300 if (right_side == EmptyExpression.OutAccess) {
7301 // TODO: best_candidate can be null at this point
7302 INamedBlockVariable variable = null;
7303 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7304 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7305 best_candidate.Name);
7307 right_side.DoResolveLValue (rc, this);
7312 if (eclass == ExprClass.Unresolved) {
7313 var expr = OverloadResolve (rc, right_side);
7318 return expr.ResolveLValue (rc, right_side);
7320 ResolveInstanceExpression (rc, right_side);
7323 if (!best_candidate.HasSet) {
7324 if (ResolveAutopropertyAssignment (rc, right_side))
7327 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7328 GetSignatureForError ());
7332 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7333 if (best_candidate.HasDifferentAccessibility) {
7334 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7335 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7336 GetSignatureForError ());
7338 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7339 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7343 if (best_candidate.HasDifferentAccessibility)
7344 CheckProtectedMemberAccess (rc, best_candidate.Set);
7346 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7350 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7352 var ca = ec.ConditionalAccess;
7353 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7355 call.Emit (ec, method, arguments, loc);
7357 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7358 ec.ConditionalAccess = ca;
7362 // Implements the IAssignMethod interface for assignments
7364 public virtual void Emit (EmitContext ec, bool leave_copy)
7366 var call = new CallEmitter ();
7367 call.ConditionalAccess = ConditionalAccess;
7368 call.InstanceExpression = InstanceExpression;
7369 if (has_await_arguments)
7370 call.HasAwaitArguments = true;
7372 call.DuplicateArguments = emitting_compound_assignment;
7374 if (conditional_access_receiver)
7375 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7377 call.Emit (ec, Getter, Arguments, loc);
7379 if (call.HasAwaitArguments) {
7380 InstanceExpression = call.InstanceExpression;
7381 Arguments = call.EmittedArguments;
7382 has_await_arguments = true;
7386 ec.Emit (OpCodes.Dup);
7387 temp = new LocalTemporary (Type);
7392 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7394 public override void Emit (EmitContext ec)
7399 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7401 has_await_arguments = true;
7406 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7408 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7410 bool ResolveGetter (ResolveContext rc)
7412 if (!best_candidate.HasGet) {
7413 if (InstanceExpression != EmptyExpression.Null) {
7414 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7415 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7416 best_candidate.GetSignatureForError ());
7419 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7420 if (best_candidate.HasDifferentAccessibility) {
7421 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7422 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7423 TypeManager.CSharpSignature (best_candidate));
7425 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7426 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7430 if (best_candidate.HasDifferentAccessibility) {
7431 CheckProtectedMemberAccess (rc, best_candidate.Get);
7434 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7438 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7445 /// Fully resolved expression that evaluates to an Event
7447 public class EventExpr : MemberExpr, IAssignMethod
7449 readonly EventSpec spec;
7452 public EventExpr (EventSpec spec, Location loc)
7460 protected override TypeSpec DeclaringType {
7462 return spec.DeclaringType;
7466 public override string Name {
7472 public override bool IsInstance {
7474 return !spec.IsStatic;
7478 public override bool IsStatic {
7480 return spec.IsStatic;
7484 public override string KindName {
7485 get { return "event"; }
7488 public MethodSpec Operator {
7496 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7499 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7501 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7502 if (spec.BackingField != null &&
7503 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7505 spec.MemberDefinition.SetIsUsed ();
7507 spec.CheckObsoleteness (ec, loc);
7509 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7510 Error_AssignmentEventOnly (ec);
7512 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7514 InstanceExpression = null;
7516 return ml.ResolveMemberAccess (ec, left, original);
7520 return base.ResolveMemberAccess (ec, left, original);
7523 public override Expression CreateExpressionTree (ResolveContext ec)
7525 throw new NotSupportedException ("ET");
7528 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7530 if (right_side == EmptyExpression.EventAddition) {
7531 op = spec.AccessorAdd;
7532 } else if (right_side == EmptyExpression.EventSubtraction) {
7533 op = spec.AccessorRemove;
7537 Error_AssignmentEventOnly (ec);
7541 if (HasConditionalAccess ())
7542 Error_NullPropagatingLValue (ec);
7544 op = CandidateToBaseOverride (ec, op);
7548 protected override Expression DoResolve (ResolveContext ec)
7550 eclass = ExprClass.EventAccess;
7551 type = spec.MemberType;
7553 ResolveInstanceExpression (ec, null);
7555 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7556 Error_AssignmentEventOnly (ec);
7559 DoBestMemberChecks (ec, spec);
7563 public override void Emit (EmitContext ec)
7565 throw new NotSupportedException ();
7566 //Error_CannotAssign ();
7569 #region IAssignMethod Members
7571 public void Emit (EmitContext ec, bool leave_copy)
7573 throw new NotImplementedException ();
7576 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7578 if (leave_copy || !isCompound)
7579 throw new NotImplementedException ("EventExpr::EmitAssign");
7581 Arguments args = new Arguments (1);
7582 args.Add (new Argument (source));
7584 // TODO: Wrong, needs receiver
7585 // if (NullShortCircuit) {
7586 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7589 var call = new CallEmitter ();
7590 call.InstanceExpression = InstanceExpression;
7591 call.ConditionalAccess = ConditionalAccess;
7592 call.EmitStatement (ec, op, args, loc);
7594 // if (NullShortCircuit)
7595 // ec.CloseConditionalAccess (null);
7600 void Error_AssignmentEventOnly (ResolveContext ec)
7602 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7603 ec.Report.Error (79, loc,
7604 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7605 GetSignatureForError ());
7607 ec.Report.Error (70, loc,
7608 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7609 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7613 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7615 name = name.Substring (0, name.LastIndexOf ('.'));
7616 base.Error_CannotCallAbstractBase (rc, name);
7619 public override string GetSignatureForError ()
7621 return TypeManager.CSharpSignature (spec);
7624 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7626 spec.CheckObsoleteness (rc, expr.Location);
7629 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7631 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7635 public class TemporaryVariableReference : VariableReference
7637 public class Declarator : Statement
7639 TemporaryVariableReference variable;
7641 public Declarator (TemporaryVariableReference variable)
7643 this.variable = variable;
7647 protected override void DoEmit (EmitContext ec)
7649 variable.li.CreateBuilder (ec);
7652 public override void Emit (EmitContext ec)
7654 // Don't create sequence point
7658 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7663 protected override void CloneTo (CloneContext clonectx, Statement target)
7671 public TemporaryVariableReference (LocalVariable li, Location loc)
7674 this.type = li.Type;
7678 public override bool IsLockedByStatement {
7686 public LocalVariable LocalInfo {
7692 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7694 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7695 return new TemporaryVariableReference (li, loc);
7698 protected override Expression DoResolve (ResolveContext ec)
7700 eclass = ExprClass.Variable;
7703 // Don't capture temporary variables except when using
7704 // state machine redirection and block yields
7706 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7707 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7708 ec.IsVariableCapturingRequired) {
7709 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7710 storey.CaptureLocalVariable (ec, li);
7716 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7718 return Resolve (ec);
7721 public override void Emit (EmitContext ec)
7723 li.CreateBuilder (ec);
7728 public void EmitAssign (EmitContext ec, Expression source)
7730 li.CreateBuilder (ec);
7732 EmitAssign (ec, source, false, false);
7735 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7737 return li.HoistedVariant;
7740 public override bool IsFixed {
7741 get { return true; }
7744 public override bool IsRef {
7745 get { return false; }
7748 public override string Name {
7749 get { throw new NotImplementedException (); }
7752 public override void SetHasAddressTaken ()
7754 throw new NotImplementedException ();
7757 protected override ILocalVariable Variable {
7761 public override VariableInfo VariableInfo {
7762 get { return null; }
7767 /// Handles `var' contextual keyword; var becomes a keyword only
7768 /// if no type called var exists in a variable scope
7770 class VarExpr : SimpleName
7772 public VarExpr (Location loc)
7777 public bool InferType (ResolveContext ec, Expression right_side)
7780 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7782 type = right_side.Type;
7783 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7784 ec.Report.Error (815, loc,
7785 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7786 type.GetSignatureForError ());
7787 type = InternalType.ErrorType;
7791 eclass = ExprClass.Variable;
7795 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7797 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7798 base.Error_TypeOrNamespaceNotFound (ec);
7800 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");