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");
1134 // Converts `source' to an int, uint, long or ulong.
1136 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1138 var btypes = ec.BuiltinTypes;
1140 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1141 Arguments args = new Arguments (1);
1142 args.Add (new Argument (source));
1143 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1146 Expression converted;
1148 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1149 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1150 if (converted == null)
1151 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1152 if (converted == null)
1153 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1154 if (converted == null)
1155 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1157 if (converted == null) {
1158 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1167 // Only positive constants are allowed at compile time
1169 Constant c = converted as Constant;
1170 if (c != null && c.IsNegative)
1171 Error_NegativeArrayIndex (ec, source.loc);
1173 // No conversion needed to array index
1174 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1177 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1180 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1182 if (args.Count != 1){
1183 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1188 if (arg is NamedArgument)
1189 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1191 var index = arg.Expr.Resolve (rc);
1195 index = ConvertExpressionToArrayIndex (rc, index, true);
1197 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1198 return new Indirection (p, loc);
1202 // Derived classes implement this method by cloning the fields that
1203 // could become altered during the Resolve stage
1205 // Only expressions that are created for the parser need to implement
1208 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1210 throw new NotImplementedException (
1212 "CloneTo not implemented for expression {0}", this.GetType ()));
1216 // Clones an expression created by the parser.
1218 // We only support expressions created by the parser so far, not
1219 // expressions that have been resolved (many more classes would need
1220 // to implement CloneTo).
1222 // This infrastructure is here merely for Lambda expressions which
1223 // compile the same code using different type values for the same
1224 // arguments to find the correct overload
1226 public virtual Expression Clone (CloneContext clonectx)
1228 Expression cloned = (Expression) MemberwiseClone ();
1229 CloneTo (clonectx, cloned);
1235 // Implementation of expression to expression tree conversion
1237 public abstract Expression CreateExpressionTree (ResolveContext ec);
1239 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1241 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1244 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1246 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1249 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1251 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1254 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1256 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1260 return new TypeExpression (t, loc);
1264 // Implemented by all expressions which support conversion from
1265 // compiler expression to invokable runtime expression. Used by
1266 // dynamic C# binder.
1268 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1270 throw new NotImplementedException ("MakeExpression for " + GetType ());
1273 public virtual object Accept (StructuralVisitor visitor)
1275 return visitor.Visit (this);
1280 /// This is just a base class for expressions that can
1281 /// appear on statements (invocations, object creation,
1282 /// assignments, post/pre increment and decrement). The idea
1283 /// being that they would support an extra Emition interface that
1284 /// does not leave a result on the stack.
1286 public abstract class ExpressionStatement : Expression
1288 public virtual void MarkReachable (Reachability rc)
1292 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1294 Expression e = Resolve (ec);
1298 ExpressionStatement es = e as ExpressionStatement;
1299 if (es == null || e is AnonymousMethodBody) {
1300 var reduced = e as IReducedExpressionStatement;
1301 if (reduced != null) {
1302 return EmptyExpressionStatement.Instance;
1305 Error_InvalidExpressionStatement (ec);
1309 // This is quite expensive warning, try to limit the damage
1311 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1312 WarningAsyncWithoutWait (ec, e);
1318 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1320 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1321 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1326 // Need to do full resolve because GetAwaiter can be extension method
1327 // available only in this context
1329 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1333 var arguments = new Arguments (0);
1334 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1339 // Use same check rules as for real await
1341 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1342 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1345 bc.Report.Warning (4014, 1, e.Location,
1346 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1350 var inv = e as Invocation;
1351 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1352 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1353 bc.Report.Warning (4014, 1, e.Location,
1354 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1360 /// Requests the expression to be emitted in a `statement'
1361 /// context. This means that no new value is left on the
1362 /// stack after invoking this method (constrasted with
1363 /// Emit that will always leave a value on the stack).
1365 public abstract void EmitStatement (EmitContext ec);
1367 public override void EmitSideEffect (EmitContext ec)
1373 interface IReducedExpressionStatement
1378 /// This kind of cast is used to encapsulate the child
1379 /// whose type is child.Type into an expression that is
1380 /// reported to return "return_type". This is used to encapsulate
1381 /// expressions which have compatible types, but need to be dealt
1382 /// at higher levels with.
1384 /// For example, a "byte" expression could be encapsulated in one
1385 /// of these as an "unsigned int". The type for the expression
1386 /// would be "unsigned int".
1389 public abstract class TypeCast : Expression
1391 protected readonly Expression child;
1393 protected TypeCast (Expression child, TypeSpec return_type)
1395 eclass = child.eclass;
1396 loc = child.Location;
1401 public Expression Child {
1407 public override bool ContainsEmitWithAwait ()
1409 return child.ContainsEmitWithAwait ();
1412 public override Expression CreateExpressionTree (ResolveContext ec)
1414 Arguments args = new Arguments (2);
1415 args.Add (new Argument (child.CreateExpressionTree (ec)));
1416 args.Add (new Argument (new TypeOf (type, loc)));
1418 if (type.IsPointer || child.Type.IsPointer)
1419 Error_PointerInsideExpressionTree (ec);
1421 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1424 protected override Expression DoResolve (ResolveContext ec)
1426 // This should never be invoked, we are born in fully
1427 // initialized state.
1432 public override void Emit (EmitContext ec)
1437 public override void FlowAnalysis (FlowAnalysisContext fc)
1439 child.FlowAnalysis (fc);
1442 public override SLE.Expression MakeExpression (BuilderContext ctx)
1445 return base.MakeExpression (ctx);
1447 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1448 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1449 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1453 protected override void CloneTo (CloneContext clonectx, Expression t)
1458 public override bool IsNull {
1459 get { return child.IsNull; }
1463 public class EmptyCast : TypeCast {
1464 EmptyCast (Expression child, TypeSpec target_type)
1465 : base (child, target_type)
1469 public static Expression Create (Expression child, TypeSpec type)
1471 Constant c = child as Constant;
1473 var enum_constant = c as EnumConstant;
1474 if (enum_constant != null)
1475 c = enum_constant.Child;
1477 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1481 var res = c.ConvertImplicitly (type);
1487 EmptyCast e = child as EmptyCast;
1489 return new EmptyCast (e.child, type);
1491 return new EmptyCast (child, type);
1494 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1496 child.EmitBranchable (ec, label, on_true);
1499 public override void EmitSideEffect (EmitContext ec)
1501 child.EmitSideEffect (ec);
1506 // Used for predefined type user operator (no obsolete check, etc.)
1508 public class OperatorCast : TypeCast
1510 readonly MethodSpec conversion_operator;
1512 public OperatorCast (Expression expr, TypeSpec target_type)
1513 : this (expr, target_type, target_type, false)
1517 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1518 : this (expr, target_type, target_type, find_explicit)
1522 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1523 : base (expr, returnType)
1525 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1526 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1529 foreach (MethodSpec oper in mi) {
1530 if (oper.ReturnType != returnType)
1533 if (oper.Parameters.Types[0] == expr.Type) {
1534 conversion_operator = oper;
1540 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1541 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1544 public override void Emit (EmitContext ec)
1547 ec.Emit (OpCodes.Call, conversion_operator);
1552 // Constant specialization of EmptyCast.
1553 // We need to special case this since an empty cast of
1554 // a constant is still a constant.
1556 public class EmptyConstantCast : Constant
1558 public readonly Constant child;
1560 public EmptyConstantCast (Constant child, TypeSpec type)
1561 : base (child.Location)
1564 throw new ArgumentNullException ("child");
1567 this.eclass = child.eclass;
1571 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1573 if (child.Type == target_type)
1576 // FIXME: check that 'type' can be converted to 'target_type' first
1577 return child.ConvertExplicitly (in_checked_context, target_type);
1580 public override Expression CreateExpressionTree (ResolveContext ec)
1582 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1583 child.CreateExpressionTree (ec),
1584 new TypeOf (type, loc));
1587 Error_PointerInsideExpressionTree (ec);
1589 return CreateExpressionFactoryCall (ec, "Convert", args);
1592 public override bool IsDefaultValue {
1593 get { return child.IsDefaultValue; }
1596 public override bool IsNegative {
1597 get { return child.IsNegative; }
1600 public override bool IsNull {
1601 get { return child.IsNull; }
1604 public override bool IsOneInteger {
1605 get { return child.IsOneInteger; }
1608 public override bool IsSideEffectFree {
1610 return child.IsSideEffectFree;
1614 public override bool IsZeroInteger {
1615 get { return child.IsZeroInteger; }
1618 public override void Emit (EmitContext ec)
1623 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1625 child.EmitBranchable (ec, label, on_true);
1627 // Only to make verifier happy
1628 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1629 ec.Emit (OpCodes.Unbox_Any, type);
1632 public override void EmitSideEffect (EmitContext ec)
1634 child.EmitSideEffect (ec);
1637 public override object GetValue ()
1639 return child.GetValue ();
1642 public override string GetValueAsLiteral ()
1644 return child.GetValueAsLiteral ();
1647 public override long GetValueAsLong ()
1649 return child.GetValueAsLong ();
1652 public override Constant ConvertImplicitly (TypeSpec target_type)
1654 if (type == target_type)
1657 // FIXME: Do we need to check user conversions?
1658 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1661 return child.ConvertImplicitly (target_type);
1666 /// This class is used to wrap literals which belong inside Enums
1668 public class EnumConstant : Constant
1670 public Constant Child;
1672 public EnumConstant (Constant child, TypeSpec enum_type)
1673 : base (child.Location)
1677 this.eclass = ExprClass.Value;
1678 this.type = enum_type;
1681 protected EnumConstant (Location loc)
1686 public override void Emit (EmitContext ec)
1691 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1693 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1696 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1698 Child.EmitBranchable (ec, label, on_true);
1701 public override void EmitSideEffect (EmitContext ec)
1703 Child.EmitSideEffect (ec);
1706 public override string GetSignatureForError()
1708 return Type.GetSignatureForError ();
1711 public override object GetValue ()
1713 return Child.GetValue ();
1717 public override object GetTypedValue ()
1720 // The method can be used in dynamic context only (on closed types)
1722 // System.Enum.ToObject cannot be called on dynamic types
1723 // EnumBuilder has to be used, but we cannot use EnumBuilder
1724 // because it does not properly support generics
1726 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1730 public override string GetValueAsLiteral ()
1732 return Child.GetValueAsLiteral ();
1735 public override long GetValueAsLong ()
1737 return Child.GetValueAsLong ();
1740 public EnumConstant Increment()
1742 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1745 public override bool IsDefaultValue {
1747 return Child.IsDefaultValue;
1751 public override bool IsSideEffectFree {
1753 return Child.IsSideEffectFree;
1757 public override bool IsZeroInteger {
1758 get { return Child.IsZeroInteger; }
1761 public override bool IsNegative {
1763 return Child.IsNegative;
1767 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1769 if (Child.Type == target_type)
1772 return Child.ConvertExplicitly (in_checked_context, target_type);
1775 public override Constant ConvertImplicitly (TypeSpec type)
1777 if (this.type == type) {
1781 if (!Convert.ImplicitStandardConversionExists (this, type)){
1785 return Child.ConvertImplicitly (type);
1790 /// This kind of cast is used to encapsulate Value Types in objects.
1792 /// The effect of it is to box the value type emitted by the previous
1795 public class BoxedCast : TypeCast {
1797 public BoxedCast (Expression expr, TypeSpec target_type)
1798 : base (expr, target_type)
1800 eclass = ExprClass.Value;
1803 protected override Expression DoResolve (ResolveContext ec)
1805 // This should never be invoked, we are born in fully
1806 // initialized state.
1811 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1813 // Only boxing to object type is supported
1814 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1815 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1819 enc.Encode (child.Type);
1820 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1823 public override void Emit (EmitContext ec)
1827 ec.Emit (OpCodes.Box, child.Type);
1830 public override void EmitSideEffect (EmitContext ec)
1832 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1833 // so, we need to emit the box+pop instructions in most cases
1834 if (child.Type.IsStruct &&
1835 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1836 child.EmitSideEffect (ec);
1838 base.EmitSideEffect (ec);
1842 public class UnboxCast : TypeCast {
1843 public UnboxCast (Expression expr, TypeSpec return_type)
1844 : base (expr, return_type)
1848 protected override Expression DoResolve (ResolveContext ec)
1850 // This should never be invoked, we are born in fully
1851 // initialized state.
1856 public override void Emit (EmitContext ec)
1860 ec.Emit (OpCodes.Unbox_Any, type);
1865 /// This is used to perform explicit numeric conversions.
1867 /// Explicit numeric conversions might trigger exceptions in a checked
1868 /// context, so they should generate the conv.ovf opcodes instead of
1871 public class ConvCast : TypeCast {
1872 public enum Mode : byte {
1873 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1875 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1876 U2_I1, U2_U1, U2_I2, U2_CH,
1877 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1878 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1879 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1880 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1881 CH_I1, CH_U1, CH_I2,
1882 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1883 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1889 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1890 : base (child, return_type)
1895 protected override Expression DoResolve (ResolveContext ec)
1897 // This should never be invoked, we are born in fully
1898 // initialized state.
1903 public override string ToString ()
1905 return String.Format ("ConvCast ({0}, {1})", mode, child);
1908 public override void Emit (EmitContext ec)
1914 public static void Emit (EmitContext ec, Mode mode)
1916 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1918 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1919 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1920 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1921 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1922 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1924 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1925 case Mode.U1_CH: /* nothing */ break;
1927 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1928 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1929 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1930 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1931 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1932 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1935 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1936 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1937 case Mode.U2_CH: /* nothing */ break;
1939 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1940 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1941 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1942 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1943 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1944 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1945 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1947 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1948 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1949 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1950 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1951 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1952 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1954 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1955 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1956 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1957 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1958 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1959 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1960 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1964 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1965 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1966 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1967 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1968 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1969 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1970 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1971 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1972 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1974 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1975 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1976 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1978 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1979 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1980 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1981 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1982 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1983 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1984 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1985 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1986 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1988 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1989 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1990 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1991 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1992 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1993 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1994 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1995 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1996 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1997 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1999 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2003 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2004 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2006 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2007 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2009 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2010 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2012 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U2_CH: /* nothing */ break;
2024 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2025 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2026 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2027 case Mode.I4_U4: /* nothing */ break;
2028 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2029 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2034 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2035 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2036 case Mode.U4_I4: /* nothing */ break;
2037 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2039 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2040 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2041 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2042 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2044 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I8_U8: /* nothing */ break;
2046 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2049 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2050 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2051 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2052 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2053 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2054 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2055 case Mode.U8_I8: /* nothing */ break;
2056 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2057 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2059 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2060 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2061 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2063 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2064 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2065 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2066 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2067 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2068 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2069 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2070 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2071 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2073 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2074 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2075 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2076 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2077 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2078 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2079 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2080 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2081 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2084 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2090 class OpcodeCast : TypeCast
2094 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2095 : base (child, return_type)
2100 protected override Expression DoResolve (ResolveContext ec)
2102 // This should never be invoked, we are born in fully
2103 // initialized state.
2108 public override void Emit (EmitContext ec)
2114 public TypeSpec UnderlyingType {
2115 get { return child.Type; }
2120 // Opcode casts expression with 2 opcodes but only
2121 // single expression tree node
2123 class OpcodeCastDuplex : OpcodeCast
2125 readonly OpCode second;
2127 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2128 : base (child, returnType, first)
2130 this.second = second;
2133 public override void Emit (EmitContext ec)
2141 /// This kind of cast is used to encapsulate a child and cast it
2142 /// to the class requested
2144 public sealed class ClassCast : TypeCast {
2145 readonly bool forced;
2147 public ClassCast (Expression child, TypeSpec return_type)
2148 : base (child, return_type)
2152 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2153 : base (child, return_type)
2155 this.forced = forced;
2158 public override void Emit (EmitContext ec)
2162 bool gen = TypeManager.IsGenericParameter (child.Type);
2164 ec.Emit (OpCodes.Box, child.Type);
2166 if (type.IsGenericParameter) {
2167 ec.Emit (OpCodes.Unbox_Any, type);
2174 ec.Emit (OpCodes.Castclass, type);
2179 // Created during resolving pahse when an expression is wrapped or constantified
2180 // and original expression can be used later (e.g. for expression trees)
2182 public class ReducedExpression : Expression
2184 public class ReducedConstantExpression : EmptyConstantCast
2186 readonly Expression orig_expr;
2188 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2189 : base (expr, expr.Type)
2191 this.orig_expr = orig_expr;
2194 public Expression OriginalExpression {
2200 public override Constant ConvertImplicitly (TypeSpec target_type)
2202 Constant c = base.ConvertImplicitly (target_type);
2204 c = new ReducedConstantExpression (c, orig_expr);
2209 public override Expression CreateExpressionTree (ResolveContext ec)
2211 return orig_expr.CreateExpressionTree (ec);
2214 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2216 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2218 c = new ReducedConstantExpression (c, orig_expr);
2222 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2225 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2227 if (orig_expr is Conditional)
2228 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2230 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2234 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2236 public ReducedConstantStatement (Constant expr, Expression origExpr)
2237 : base (expr, origExpr)
2242 sealed class ReducedExpressionStatement : ExpressionStatement
2244 readonly Expression orig_expr;
2245 readonly ExpressionStatement stm;
2247 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2249 this.orig_expr = orig;
2251 this.eclass = stm.eclass;
2252 this.type = stm.Type;
2254 this.loc = orig.Location;
2257 public override bool ContainsEmitWithAwait ()
2259 return stm.ContainsEmitWithAwait ();
2262 public override Expression CreateExpressionTree (ResolveContext ec)
2264 return orig_expr.CreateExpressionTree (ec);
2267 protected override Expression DoResolve (ResolveContext ec)
2272 public override void Emit (EmitContext ec)
2277 public override void EmitStatement (EmitContext ec)
2279 stm.EmitStatement (ec);
2282 public override void FlowAnalysis (FlowAnalysisContext fc)
2284 stm.FlowAnalysis (fc);
2288 readonly Expression expr, orig_expr;
2290 private ReducedExpression (Expression expr, Expression orig_expr)
2293 this.eclass = expr.eclass;
2294 this.type = expr.Type;
2295 this.orig_expr = orig_expr;
2296 this.loc = orig_expr.Location;
2301 public override bool IsSideEffectFree {
2303 return expr.IsSideEffectFree;
2307 public Expression OriginalExpression {
2315 public override bool ContainsEmitWithAwait ()
2317 return expr.ContainsEmitWithAwait ();
2321 // Creates fully resolved expression switcher
2323 public static Constant Create (Constant expr, Expression originalExpr)
2325 if (expr.eclass == ExprClass.Unresolved)
2326 throw new ArgumentException ("Unresolved expression");
2328 if (originalExpr is ExpressionStatement)
2329 return new ReducedConstantStatement (expr, originalExpr);
2331 return new ReducedConstantExpression (expr, originalExpr);
2334 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2336 return new ReducedExpressionStatement (s, orig);
2339 public static Expression Create (Expression expr, Expression original_expr)
2341 return Create (expr, original_expr, true);
2345 // Creates unresolved reduce expression. The original expression has to be
2346 // already resolved. Created expression is constant based based on `expr'
2347 // value unless canBeConstant is used
2349 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2351 if (canBeConstant) {
2352 Constant c = expr as Constant;
2354 return Create (c, original_expr);
2357 ExpressionStatement s = expr as ExpressionStatement;
2359 return Create (s, original_expr);
2361 if (expr.eclass == ExprClass.Unresolved)
2362 throw new ArgumentException ("Unresolved expression");
2364 return new ReducedExpression (expr, original_expr);
2367 public override Expression CreateExpressionTree (ResolveContext ec)
2369 return orig_expr.CreateExpressionTree (ec);
2372 protected override Expression DoResolve (ResolveContext ec)
2377 public override void Emit (EmitContext ec)
2382 public override Expression EmitToField (EmitContext ec)
2384 return expr.EmitToField(ec);
2387 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2389 expr.EmitBranchable (ec, target, on_true);
2392 public override void FlowAnalysis (FlowAnalysisContext fc)
2394 expr.FlowAnalysis (fc);
2397 public override SLE.Expression MakeExpression (BuilderContext ctx)
2399 return orig_expr.MakeExpression (ctx);
2404 // Standard composite pattern
2406 public abstract class CompositeExpression : Expression
2408 protected Expression expr;
2410 protected CompositeExpression (Expression expr)
2413 this.loc = expr.Location;
2416 public override bool ContainsEmitWithAwait ()
2418 return expr.ContainsEmitWithAwait ();
2421 public override Expression CreateExpressionTree (ResolveContext rc)
2423 return expr.CreateExpressionTree (rc);
2426 public Expression Child {
2427 get { return expr; }
2430 protected override Expression DoResolve (ResolveContext rc)
2432 expr = expr.Resolve (rc);
2437 eclass = expr.eclass;
2441 public override void Emit (EmitContext ec)
2446 public override bool IsNull {
2447 get { return expr.IsNull; }
2452 // Base of expressions used only to narrow resolve flow
2454 public abstract class ShimExpression : Expression
2456 protected Expression expr;
2458 protected ShimExpression (Expression expr)
2463 public Expression Expr {
2469 protected override void CloneTo (CloneContext clonectx, Expression t)
2474 ShimExpression target = (ShimExpression) t;
2475 target.expr = expr.Clone (clonectx);
2478 public override bool ContainsEmitWithAwait ()
2480 return expr.ContainsEmitWithAwait ();
2483 public override Expression CreateExpressionTree (ResolveContext ec)
2485 throw new NotSupportedException ("ET");
2488 public override void Emit (EmitContext ec)
2490 throw new InternalErrorException ("Missing Resolve call");
2494 public class UnreachableExpression : Expression
2496 public UnreachableExpression (Expression expr)
2498 this.loc = expr.Location;
2501 public override Expression CreateExpressionTree (ResolveContext ec)
2504 throw new NotImplementedException ();
2507 protected override Expression DoResolve (ResolveContext rc)
2509 throw new NotSupportedException ();
2512 public override void FlowAnalysis (FlowAnalysisContext fc)
2514 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2517 public override void Emit (EmitContext ec)
2521 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2527 // Unresolved type name expressions
2529 public abstract class ATypeNameExpression : FullNamedExpression
2532 protected TypeArguments targs;
2534 protected ATypeNameExpression (string name, Location l)
2540 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2547 protected ATypeNameExpression (string name, int arity, Location l)
2548 : this (name, new UnboundTypeArguments (arity, l), l)
2556 return targs == null ? 0 : targs.Count;
2560 public bool HasTypeArguments {
2562 return targs != null && !targs.IsEmpty;
2566 public string Name {
2575 public TypeArguments TypeArguments {
2583 public override bool Equals (object obj)
2585 ATypeNameExpression atne = obj as ATypeNameExpression;
2586 return atne != null && atne.Name == Name &&
2587 (targs == null || targs.Equals (atne.targs));
2590 public override int GetHashCode ()
2592 return Name.GetHashCode ();
2595 // TODO: Move it to MemberCore
2596 public static string GetMemberType (MemberCore mc)
2602 if (mc is FieldBase)
2604 if (mc is MethodCore)
2606 if (mc is EnumMember)
2614 public override string GetSignatureForError ()
2616 if (targs != null) {
2617 return Name + "<" + targs.GetSignatureForError () + ">";
2623 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2627 /// SimpleName expressions are formed of a single word and only happen at the beginning
2628 /// of a dotted-name.
2630 public class SimpleName : ATypeNameExpression
2632 public SimpleName (string name, Location l)
2637 public SimpleName (string name, TypeArguments args, Location l)
2638 : base (name, args, l)
2642 public SimpleName (string name, int arity, Location l)
2643 : base (name, arity, l)
2647 public SimpleName GetMethodGroup ()
2649 return new SimpleName (Name, targs, loc);
2652 protected override Expression DoResolve (ResolveContext rc)
2654 return SimpleNameResolve (rc, null);
2657 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2659 return SimpleNameResolve (ec, right_side);
2662 public void Error_NameDoesNotExist (ResolveContext rc)
2664 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2667 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2669 if (ctx.CurrentType != null) {
2670 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2671 if (member != null) {
2672 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2677 var report = ctx.Module.Compiler.Report;
2679 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2680 if (retval != null) {
2681 report.SymbolRelatedToPreviousError (retval.Type);
2682 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2686 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2687 if (retval != null) {
2688 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2692 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2693 if (ns_candidates != null) {
2694 if (ctx is UsingAliasNamespace.AliasContext) {
2695 report.Error (246, loc,
2696 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2697 ns_candidates[0], Name);
2699 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2700 report.Error (246, loc,
2701 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2705 report.Error (246, loc,
2706 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2711 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2713 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2716 if (fne.Type != null && Arity > 0) {
2717 if (HasTypeArguments) {
2718 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2719 if (ct.ResolveAsType (mc) == null)
2725 targs.Resolve (mc, allowUnboundTypeArguments);
2727 return new GenericOpenTypeExpr (fne.Type, loc);
2731 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2733 if (!(fne is NamespaceExpression))
2737 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2738 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2739 mc.Module.Compiler.Report.Error (1980, Location,
2740 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2741 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2744 fne = new DynamicTypeExpr (loc);
2745 fne.ResolveAsType (mc);
2751 Error_TypeOrNamespaceNotFound (mc);
2755 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2757 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2760 public bool IsPossibleType (IMemberContext mc)
2762 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2765 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2767 int lookup_arity = Arity;
2768 bool errorMode = false;
2770 Block current_block = rc.CurrentBlock;
2771 INamedBlockVariable variable = null;
2772 bool variable_found = false;
2776 // Stage 1: binding to local variables or parameters
2778 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2780 if (current_block != null && lookup_arity == 0) {
2781 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2782 if (!variable.IsDeclared) {
2783 // We found local name in accessible block but it's not
2784 // initialized yet, maybe the user wanted to bind to something else
2786 variable_found = true;
2788 e = variable.CreateReferenceExpression (rc, loc);
2791 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2800 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2802 TypeSpec member_type = rc.CurrentType;
2803 for (; member_type != null; member_type = member_type.DeclaringType) {
2804 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2808 var me = e as MemberExpr;
2810 // The name matches a type, defer to ResolveAsTypeStep
2818 if (variable != null) {
2819 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2820 rc.Report.Error (844, loc,
2821 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2822 Name, me.GetSignatureForError ());
2826 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2827 // Leave it to overload resolution to report correct error
2829 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2830 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2834 // MemberLookup does not check accessors availability, this is actually needed for properties only
2836 var pe = me as PropertyExpr;
2839 // Break as there is no other overload available anyway
2840 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2841 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2844 pe.Getter = pe.PropertyInfo.Get;
2846 if (!pe.PropertyInfo.HasSet) {
2847 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2848 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2849 var p = (Property) pe.PropertyInfo.MemberDefinition;
2850 return new FieldExpr (p.BackingField, loc);
2853 variable_found = true;
2857 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2858 variable_found = true;
2862 pe.Setter = pe.PropertyInfo.Set;
2867 // TODO: It's used by EventExpr -> FieldExpr transformation only
2868 // TODO: Should go to MemberAccess
2869 me = me.ResolveMemberAccess (rc, null, null);
2872 targs.Resolve (rc, false);
2873 me.SetTypeArguments (rc, targs);
2879 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2882 targs.Resolve (rc, false);
2884 var me = expr as MemberExpr;
2886 me.SetTypeArguments (rc, targs);
2892 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2894 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2895 if (IsPossibleTypeOrNamespace (rc)) {
2896 return ResolveAsTypeOrNamespace (rc, false);
2900 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2901 return new NameOf (this);
2904 if (variable_found) {
2905 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2908 var tparams = rc.CurrentTypeParameters;
2909 if (tparams != null) {
2910 if (tparams.Find (Name) != null) {
2911 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2916 var ct = rc.CurrentType;
2918 if (ct.MemberDefinition.TypeParametersCount > 0) {
2919 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2920 if (ctp.Name == Name) {
2921 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2927 ct = ct.DeclaringType;
2928 } while (ct != null);
2931 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2932 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2934 rc.Report.SymbolRelatedToPreviousError (e.Type);
2935 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2939 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2941 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2942 return ErrorExpression.Instance;
2946 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2948 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2949 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2953 if (e is TypeExpr) {
2954 // TypeExpression does not have correct location
2955 if (e is TypeExpression)
2956 e = new TypeExpression (e.Type, loc);
2962 Error_NameDoesNotExist (rc);
2965 return ErrorExpression.Instance;
2968 if (rc.Module.Evaluator != null) {
2969 var fi = rc.Module.Evaluator.LookupField (Name);
2971 return new FieldExpr (fi.Item1, loc);
2979 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2981 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2986 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2987 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2991 if (right_side != null) {
2992 e = e.ResolveLValue (ec, right_side);
3000 public override object Accept (StructuralVisitor visitor)
3002 return visitor.Visit (this);
3007 /// Represents a namespace or a type. The name of the class was inspired by
3008 /// section 10.8.1 (Fully Qualified Names).
3010 public abstract class FullNamedExpression : Expression
3012 protected override void CloneTo (CloneContext clonectx, Expression target)
3014 // Do nothing, most unresolved type expressions cannot be
3015 // resolved to different type
3018 public override bool ContainsEmitWithAwait ()
3023 public override Expression CreateExpressionTree (ResolveContext ec)
3025 throw new NotSupportedException ("ET");
3028 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3031 // This is used to resolve the expression as a type, a null
3032 // value will be returned if the expression is not a type
3035 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3037 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3042 TypeExpr te = fne as TypeExpr;
3044 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3052 var dep = type.GetMissingDependencies ();
3054 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3057 if (type.Kind == MemberKind.Void) {
3058 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3062 // Obsolete checks cannot be done when resolving base context as they
3063 // require type dependencies to be set but we are in process of resolving them
3065 if (mc is ResolveContext) {
3066 var oa = type.GetAttributeObsolete ();
3067 if (oa != null && !mc.IsObsolete)
3068 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3075 public override void Emit (EmitContext ec)
3077 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3078 GetSignatureForError ());
3083 /// Expression that evaluates to a type
3085 public abstract class TypeExpr : FullNamedExpression
3087 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3093 protected sealed override Expression DoResolve (ResolveContext ec)
3099 public override bool Equals (object obj)
3101 TypeExpr tobj = obj as TypeExpr;
3105 return Type == tobj.Type;
3108 public override int GetHashCode ()
3110 return Type.GetHashCode ();
3115 /// Fully resolved Expression that already evaluated to a type
3117 public class TypeExpression : TypeExpr
3119 public TypeExpression (TypeSpec t, Location l)
3122 eclass = ExprClass.Type;
3126 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3132 public class NamespaceExpression : FullNamedExpression
3134 readonly Namespace ns;
3136 public NamespaceExpression (Namespace ns, Location loc)
3139 this.Type = InternalType.Namespace;
3140 this.eclass = ExprClass.Namespace;
3144 public Namespace Namespace {
3150 protected override Expression DoResolve (ResolveContext rc)
3152 throw new NotImplementedException ();
3155 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3160 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3162 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3163 if (retval != null) {
3164 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3165 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3169 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3170 if (retval != null) {
3171 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3176 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3177 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3181 string assembly = null;
3182 string possible_name = Namespace.GetSignatureForError () + "." + name;
3184 // Only assembly unique name should be added
3185 switch (possible_name) {
3186 case "System.Drawing":
3187 case "System.Web.Services":
3190 case "System.Configuration":
3191 case "System.Data.Services":
3192 case "System.DirectoryServices":
3194 case "System.Net.Http":
3195 case "System.Numerics":
3196 case "System.Runtime.Caching":
3197 case "System.ServiceModel":
3198 case "System.Transactions":
3199 case "System.Web.Routing":
3200 case "System.Xml.Linq":
3202 assembly = possible_name;
3206 case "System.Linq.Expressions":
3207 assembly = "System.Core";
3210 case "System.Windows.Forms":
3211 case "System.Windows.Forms.Layout":
3212 assembly = "System.Windows.Forms";
3216 assembly = assembly == null ? "an" : "`" + assembly + "'";
3218 if (Namespace is GlobalRootNamespace) {
3219 ctx.Module.Compiler.Report.Error (400, loc,
3220 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3223 ctx.Module.Compiler.Report.Error (234, loc,
3224 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3225 name, GetSignatureForError (), assembly);
3229 public override string GetSignatureForError ()
3231 return ns.GetSignatureForError ();
3234 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3236 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3239 public override string ToString ()
3241 return Namespace.Name;
3246 /// This class denotes an expression which evaluates to a member
3247 /// of a struct or a class.
3249 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3251 protected bool conditional_access_receiver;
3254 // An instance expression associated with this member, if it's a
3255 // non-static member
3257 public Expression InstanceExpression;
3260 /// The name of this member.
3262 public abstract string Name {
3267 // When base.member is used
3269 public bool IsBase {
3270 get { return InstanceExpression is BaseThis; }
3274 /// Whether this is an instance member.
3276 public abstract bool IsInstance {
3281 /// Whether this is a static member.
3283 public abstract bool IsStatic {
3287 public abstract string KindName {
3291 public bool ConditionalAccess { get; set; }
3293 protected abstract TypeSpec DeclaringType {
3297 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3299 return InstanceExpression.Type;
3304 // Converts best base candidate for virtual method starting from QueriedBaseType
3306 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3309 // Only when base.member is used and method is virtual
3315 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3316 // means for base.member access we have to find the closest match after we found best candidate
3318 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3320 // The method could already be what we are looking for
3322 TypeSpec[] targs = null;
3323 if (method.DeclaringType != InstanceExpression.Type) {
3325 // Candidate can have inflated MVAR parameters and we need to find
3326 // base match for original definition not inflated parameter types
3328 var parameters = method.Parameters;
3329 if (method.Arity > 0) {
3330 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3331 var inflated = method.DeclaringType as InflatedTypeSpec;
3332 if (inflated != null) {
3333 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3337 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3338 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3339 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3340 if (base_override.IsGeneric)
3341 targs = method.TypeArguments;
3343 method = base_override;
3348 // When base access is used inside anonymous method/iterator/etc we need to
3349 // get back to the context of original type. We do it by emiting proxy
3350 // method in original class and rewriting base call to this compiler
3351 // generated method call which does the actual base invocation. This may
3352 // introduce redundant storey but with `this' only but it's tricky to avoid
3353 // at this stage as we don't know what expressions follow base
3355 // TODO: It's needed only when the method with base call is moved to a storey
3357 if (rc.CurrentAnonymousMethod != null) {
3358 if (targs == null && method.IsGeneric) {
3359 targs = method.TypeArguments;
3360 method = method.GetGenericMethodDefinition ();
3363 if (method.Parameters.HasArglist)
3364 throw new NotImplementedException ("__arglist base call proxy");
3366 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3368 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3369 // get/set member expressions second call would fail to proxy because left expression
3370 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3371 // FIXME: The async check is another hack but will probably fail with mutators
3372 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3373 InstanceExpression = new This (loc).Resolve (rc);
3377 method = method.MakeGenericMethod (rc, targs);
3381 // Only base will allow this invocation to happen.
3383 if (method.IsAbstract) {
3384 rc.Report.SymbolRelatedToPreviousError (method);
3385 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3391 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3393 if (InstanceExpression == null)
3396 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3397 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3398 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3403 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3405 if (InstanceExpression == null)
3408 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3411 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3413 var ct = rc.CurrentType;
3414 if (ct == qualifier)
3417 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3420 qualifier = qualifier.GetDefinition ();
3421 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3428 public override bool ContainsEmitWithAwait ()
3430 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3433 public override bool HasConditionalAccess ()
3435 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3438 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3441 type = type.GetDefinition ();
3443 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3446 type = type.DeclaringType;
3447 } while (type != null);
3452 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3454 if (InstanceExpression != null) {
3455 InstanceExpression = InstanceExpression.Resolve (rc);
3456 CheckProtectedMemberAccess (rc, member);
3459 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3460 UnsafeError (rc, loc);
3463 var dep = member.GetMissingDependencies ();
3465 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3468 member.CheckObsoleteness (rc, loc);
3470 if (!(member is FieldSpec))
3471 member.MemberDefinition.SetIsUsed ();
3474 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3476 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3479 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3481 rc.Report.SymbolRelatedToPreviousError (member);
3482 rc.Report.Error (1540, loc,
3483 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3484 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3487 public override void FlowAnalysis (FlowAnalysisContext fc)
3489 if (InstanceExpression != null) {
3490 InstanceExpression.FlowAnalysis (fc);
3494 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3496 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3497 conditional_access_receiver = true;
3501 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3503 if (!ResolveInstanceExpressionCore (rc, rhs))
3507 // Check intermediate value modification which won't have any effect
3509 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3510 var fexpr = InstanceExpression as FieldExpr;
3511 if (fexpr != null) {
3512 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3515 if (fexpr.IsStatic) {
3516 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3517 fexpr.GetSignatureForError ());
3519 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3520 fexpr.GetSignatureForError ());
3526 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3527 if (rc.CurrentInitializerVariable != null) {
3528 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3529 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3531 rc.Report.Error (1612, loc,
3532 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3533 InstanceExpression.GetSignatureForError ());
3539 var lvr = InstanceExpression as LocalVariableReference;
3542 if (!lvr.local_info.IsReadonly)
3545 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3546 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3553 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3556 if (InstanceExpression != null) {
3557 if (InstanceExpression is TypeExpr) {
3558 var t = InstanceExpression.Type;
3560 t.CheckObsoleteness (rc, loc);
3562 t = t.DeclaringType;
3563 } while (t != null);
3565 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3566 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3567 rc.Report.Error (176, loc,
3568 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3569 GetSignatureForError ());
3573 InstanceExpression = null;
3579 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3580 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3581 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3582 rc.Report.Error (236, loc,
3583 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3584 GetSignatureForError ());
3586 var fe = this as FieldExpr;
3587 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3588 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3589 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3591 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3595 rc.Report.Error (120, loc,
3596 "An object reference is required to access non-static member `{0}'",
3597 GetSignatureForError ());
3601 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3605 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3606 rc.Report.Error (38, loc,
3607 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3608 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3611 InstanceExpression = new This (loc).Resolve (rc);
3615 var me = InstanceExpression as MemberExpr;
3617 me.ResolveInstanceExpressionCore (rc, rhs);
3619 var fe = me as FieldExpr;
3620 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3621 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3622 rc.Report.Warning (1690, 1, loc,
3623 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3624 me.GetSignatureForError ());
3631 // Additional checks for l-value member access
3634 if (InstanceExpression is UnboxCast) {
3635 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3642 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3644 if (left != null && !ConditionalAccess && !ec.HasSet (ResolveContext.Options.NameOfScope) && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3645 ec.Report.Warning (1720, 1, left.Location,
3646 "Expression will always cause a `{0}'", "System.NullReferenceException");
3649 InstanceExpression = left;
3653 public virtual void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3658 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3660 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3661 inst.Emit (ec, ConditionalAccess);
3663 if (prepare_for_load)
3664 ec.Emit (OpCodes.Dup);
3667 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3670 public class ExtensionMethodCandidates
3672 readonly NamespaceContainer container;
3673 readonly IList<MethodSpec> methods;
3675 readonly IMemberContext context;
3677 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3679 this.context = context;
3680 this.methods = methods;
3681 this.container = nsContainer;
3682 this.index = lookupIndex;
3685 public NamespaceContainer Container {
3691 public IMemberContext Context {
3697 public int LookupIndex {
3703 public IList<MethodSpec> Methods {
3711 // Represents a group of extension method candidates for whole namespace
3713 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3715 ExtensionMethodCandidates candidates;
3716 public Expression ExtensionExpression;
3718 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3719 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3721 this.candidates = candidates;
3722 this.ExtensionExpression = extensionExpr;
3725 public override bool IsStatic {
3726 get { return true; }
3730 // For extension methodgroup we are not looking for base members but parent
3731 // namespace extension methods
3733 public override IList<MemberSpec> GetBaseMembers (TypeSpec type)
3735 // TODO: candidates are null only when doing error reporting, that's
3736 // incorrect. We have to discover same extension methods in error mode
3737 if (candidates == null)
3740 int arity = type_arguments == null ? 0 : type_arguments.Count;
3742 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3743 if (candidates == null)
3746 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3749 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3752 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3754 // LAMESPEC: or implicit type parameter conversion
3756 return argType == extensionType ||
3757 TypeSpecComparer.IsEqual (argType, extensionType) ||
3758 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3759 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3762 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
3764 rc.Report.Error (8093, expr.Location, "An argument to nameof operator cannot be extension method group");
3767 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3769 // We are already here
3773 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3775 if (arguments == null)
3776 arguments = new Arguments (1);
3778 ExtensionExpression = ExtensionExpression.Resolve (ec);
3779 if (ExtensionExpression == null)
3782 var cand = candidates;
3783 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3784 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3785 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3787 // Restore candidates in case we are running in probing mode
3790 // Store resolved argument and restore original arguments
3792 // Clean-up modified arguments for error reporting
3793 arguments.RemoveAt (0);
3797 var me = ExtensionExpression as MemberExpr;
3799 me.ResolveInstanceExpression (ec, null);
3800 var fe = me as FieldExpr;
3802 fe.Spec.MemberDefinition.SetIsUsed ();
3805 InstanceExpression = null;
3809 #region IErrorHandler Members
3811 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3816 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3818 rc.Report.SymbolRelatedToPreviousError (best);
3821 rc.Report.Error (1929, loc,
3822 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3823 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3825 rc.Report.Error (1928, loc,
3826 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3827 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3833 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3838 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3847 /// MethodGroupExpr represents a group of method candidates which
3848 /// can be resolved to the best method overload
3850 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3852 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3854 protected IList<MemberSpec> Methods;
3855 MethodSpec best_candidate;
3856 TypeSpec best_candidate_return;
3857 protected TypeArguments type_arguments;
3859 SimpleName simple_name;
3860 protected TypeSpec queried_type;
3862 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3866 this.type = InternalType.MethodGroup;
3868 eclass = ExprClass.MethodGroup;
3869 queried_type = type;
3872 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3873 : this (new MemberSpec[] { m }, type, loc)
3879 public MethodSpec BestCandidate {
3881 return best_candidate;
3885 public TypeSpec BestCandidateReturnType {
3887 return best_candidate_return;
3891 public IList<MemberSpec> Candidates {
3897 protected override TypeSpec DeclaringType {
3899 return queried_type;
3903 public bool IsConditionallyExcluded {
3905 return Methods == Excluded;
3909 public override bool IsInstance {
3911 if (best_candidate != null)
3912 return !best_candidate.IsStatic;
3918 public override bool IsSideEffectFree {
3920 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3924 public override bool IsStatic {
3926 if (best_candidate != null)
3927 return best_candidate.IsStatic;
3933 public override string KindName {
3934 get { return "method"; }
3937 public override string Name {
3939 if (best_candidate != null)
3940 return best_candidate.Name;
3943 return Methods.First ().Name;
3950 // When best candidate is already know this factory can be used
3951 // to avoid expensive overload resolution to be called
3953 // NOTE: InstanceExpression has to be set manually
3955 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3957 return new MethodGroupExpr (best, queriedType, loc) {
3958 best_candidate = best,
3959 best_candidate_return = best.ReturnType
3963 public override string GetSignatureForError ()
3965 if (best_candidate != null)
3966 return best_candidate.GetSignatureForError ();
3968 return Methods.First ().GetSignatureForError ();
3971 public override Expression CreateExpressionTree (ResolveContext ec)
3973 if (best_candidate == null) {
3974 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3978 if (IsConditionallyExcluded)
3979 ec.Report.Error (765, loc,
3980 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3982 if (ConditionalAccess)
3983 Error_NullShortCircuitInsideExpressionTree (ec);
3985 return new TypeOfMethod (best_candidate, loc);
3988 protected override Expression DoResolve (ResolveContext ec)
3990 this.eclass = ExprClass.MethodGroup;
3992 if (InstanceExpression != null) {
3993 InstanceExpression = InstanceExpression.Resolve (ec);
3994 if (InstanceExpression == null)
4001 public override void Emit (EmitContext ec)
4003 throw new NotSupportedException ();
4006 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4008 var call = new CallEmitter ();
4009 call.InstanceExpression = InstanceExpression;
4010 call.ConditionalAccess = ConditionalAccess;
4013 call.EmitStatement (ec, best_candidate, arguments, loc);
4015 call.Emit (ec, best_candidate, arguments, loc);
4018 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4020 var ca = ec.ConditionalAccess;
4021 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4022 Statement = statement
4025 EmitCall (ec, arguments, statement);
4027 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4028 ec.ConditionalAccess = ca;
4031 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4033 if (target != InternalType.ErrorType) {
4034 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4035 Name, target.GetSignatureForError ());
4039 public bool HasAccessibleCandidate (ResolveContext rc)
4041 foreach (var candidate in Candidates) {
4042 if (candidate.IsAccessible (rc))
4049 public static bool IsExtensionMethodArgument (Expression expr)
4052 // LAMESPEC: No details about which expressions are not allowed
4054 return !(expr is TypeExpr) && !(expr is BaseThis);
4058 /// Find the Applicable Function Members (7.4.2.1)
4060 /// me: Method Group expression with the members to select.
4061 /// it might contain constructors or methods (or anything
4062 /// that maps to a method).
4064 /// Arguments: ArrayList containing resolved Argument objects.
4066 /// loc: The location if we want an error to be reported, or a Null
4067 /// location for "probing" purposes.
4069 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4070 /// that is the best match of me on Arguments.
4073 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4075 // TODO: causes issues with probing mode, remove explicit Kind check
4076 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4079 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4080 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4081 r.BaseMembersProvider = this;
4082 r.InstanceQualifier = this;
4085 if (cerrors != null)
4086 r.CustomErrors = cerrors;
4088 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4089 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4090 if (best_candidate == null) {
4091 if (!r.BestCandidateIsDynamic)
4094 if (simple_name != null && ec.IsStatic)
4095 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4100 // Overload resolver had to create a new method group, all checks bellow have already been executed
4101 if (r.BestCandidateNewMethodGroup != null)
4102 return r.BestCandidateNewMethodGroup;
4104 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4105 if (InstanceExpression != null) {
4106 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4107 InstanceExpression = null;
4109 if (simple_name != null && best_candidate.IsStatic) {
4110 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4113 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4117 ResolveInstanceExpression (ec, null);
4120 var base_override = CandidateToBaseOverride (ec, best_candidate);
4121 if (base_override == best_candidate) {
4122 best_candidate_return = r.BestCandidateReturnType;
4124 best_candidate = base_override;
4125 best_candidate_return = best_candidate.ReturnType;
4128 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4129 ConstraintChecker cc = new ConstraintChecker (ec);
4130 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4134 // Additional check for possible imported base override method which
4135 // could not be done during IsOverrideMethodBaseTypeAccessible
4137 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4138 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4139 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4140 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4143 // Speed up the check by not doing it on disallowed targets
4144 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4150 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4152 var fe = left as FieldExpr;
4155 // Using method-group on struct fields makes the struct assigned. I am not sure
4156 // why but that's what .net does
4158 fe.Spec.MemberDefinition.SetIsAssigned ();
4161 simple_name = original;
4162 return base.ResolveMemberAccess (ec, left, original);
4165 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
4167 if (!HasAccessibleCandidate (rc)) {
4168 ErrorIsInaccesible (rc, expr.GetSignatureForError (), loc);
4171 if (expr.HasTypeArguments) {
4172 rc.Report.Error (8084, expr.Location, "An argument to nameof operator cannot be method group with type arguments");
4176 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4178 type_arguments = ta;
4181 #region IBaseMembersProvider Members
4183 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec type)
4185 var baseType = type.BaseType;
4187 IList<MemberSpec> members = baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4189 if (members == null && !type.IsInterface) {
4190 var tps = queried_type as TypeParameterSpec;
4192 members = MemberCache.FindInterfaceMembers (tps, Methods [0].Name);
4198 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4200 if (queried_type == member.DeclaringType)
4203 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4204 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4208 // Extension methods lookup after ordinary methods candidates failed to apply
4210 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4212 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4215 if (!IsExtensionMethodArgument (InstanceExpression))
4218 int arity = type_arguments == null ? 0 : type_arguments.Count;
4219 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4220 if (methods == null)
4223 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4224 emg.SetTypeArguments (rc, type_arguments);
4225 emg.ConditionalAccess = ConditionalAccess;
4232 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4234 public ConstructorInstanceQualifier (TypeSpec type)
4237 InstanceType = type;
4240 public TypeSpec InstanceType { get; private set; }
4242 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4244 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4248 public struct OverloadResolver
4251 public enum Restrictions
4255 ProbingOnly = 1 << 1,
4256 CovariantDelegate = 1 << 2,
4257 NoBaseMembers = 1 << 3,
4258 BaseMembersIncluded = 1 << 4,
4259 GetEnumeratorLookup = 1 << 5
4262 public interface IBaseMembersProvider
4264 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4265 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4266 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4269 public interface IErrorHandler
4271 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4272 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4273 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4274 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4277 public interface IInstanceQualifier
4279 TypeSpec InstanceType { get; }
4280 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4283 sealed class NoBaseMembers : IBaseMembersProvider
4285 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4287 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4292 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4297 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4303 struct AmbiguousCandidate
4305 public readonly MemberSpec Member;
4306 public readonly bool Expanded;
4307 public readonly AParametersCollection Parameters;
4309 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4312 Parameters = parameters;
4313 Expanded = expanded;
4318 IList<MemberSpec> members;
4319 TypeArguments type_arguments;
4320 IBaseMembersProvider base_provider;
4321 IErrorHandler custom_errors;
4322 IInstanceQualifier instance_qualifier;
4323 Restrictions restrictions;
4324 MethodGroupExpr best_candidate_extension_group;
4325 TypeSpec best_candidate_return_type;
4327 SessionReportPrinter lambda_conv_msgs;
4329 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4330 : this (members, null, restrictions, loc)
4334 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4337 if (members == null || members.Count == 0)
4338 throw new ArgumentException ("empty members set");
4340 this.members = members;
4342 type_arguments = targs;
4343 this.restrictions = restrictions;
4344 if (IsDelegateInvoke)
4345 this.restrictions |= Restrictions.NoBaseMembers;
4347 base_provider = NoBaseMembers.Instance;
4352 public IBaseMembersProvider BaseMembersProvider {
4354 return base_provider;
4357 base_provider = value;
4361 public bool BestCandidateIsDynamic { get; set; }
4364 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4366 public MethodGroupExpr BestCandidateNewMethodGroup {
4368 return best_candidate_extension_group;
4373 // Return type can be different between best candidate and closest override
4375 public TypeSpec BestCandidateReturnType {
4377 return best_candidate_return_type;
4381 public IErrorHandler CustomErrors {
4383 return custom_errors;
4386 custom_errors = value;
4390 TypeSpec DelegateType {
4392 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4393 throw new InternalErrorException ("Not running in delegate mode", loc);
4395 return members [0].DeclaringType;
4399 public IInstanceQualifier InstanceQualifier {
4401 return instance_qualifier;
4404 instance_qualifier = value;
4408 bool IsProbingOnly {
4410 return (restrictions & Restrictions.ProbingOnly) != 0;
4414 bool IsDelegateInvoke {
4416 return (restrictions & Restrictions.DelegateInvoke) != 0;
4423 // 7.4.3.3 Better conversion from expression
4424 // Returns : 1 if a->p is better,
4425 // 2 if a->q is better,
4426 // 0 if neither is better
4428 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4430 TypeSpec argument_type = a.Type;
4433 // Exactly matching Expression phase
4437 // If argument is an anonymous function
4439 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4441 // p and q are delegate types or expression tree types
4443 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4444 if (q.MemberDefinition != p.MemberDefinition) {
4449 // Uwrap delegate from Expression<T>
4451 q = TypeManager.GetTypeArguments (q) [0];
4452 p = TypeManager.GetTypeArguments (p) [0];
4455 var p_m = Delegate.GetInvokeMethod (p);
4456 var q_m = Delegate.GetInvokeMethod (q);
4459 // With identical parameter lists
4461 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4469 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4471 if (p.Kind == MemberKind.Void) {
4472 return q.Kind != MemberKind.Void ? 2 : 0;
4476 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4478 if (q.Kind == MemberKind.Void) {
4479 return p.Kind != MemberKind.Void ? 1 : 0;
4482 var am = (AnonymousMethodExpression)a.Expr;
4485 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4486 // better conversion is performed between underlying types Y1 and Y2
4488 if (p.IsGenericTask || q.IsGenericTask) {
4489 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4490 q = q.TypeArguments [0];
4491 p = p.TypeArguments [0];
4497 // An inferred return type X exists for E in the context of the parameter list, and
4498 // an identity conversion exists from X to the return type of D
4500 var inferred_type = am.InferReturnType (ec, null, orig_q);
4501 if (inferred_type != null) {
4502 if (inferred_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4503 inferred_type = ec.BuiltinTypes.Object;
4505 if (inferred_type == p)
4508 if (inferred_type == q)
4514 if (argument_type == p)
4517 if (argument_type == q)
4520 return IsBetterConversionTarget (ec, p, q);
4523 static int IsBetterConversionTarget (ResolveContext rc, TypeSpec p, TypeSpec q)
4525 if ((p.Kind == MemberKind.Delegate || p.IsExpressionTreeType) && (q.Kind == MemberKind.Delegate || q.IsExpressionTreeType)) {
4527 if (p.Kind != MemberKind.Delegate) {
4528 p = TypeManager.GetTypeArguments (p) [0];
4531 if (q.Kind != MemberKind.Delegate) {
4532 q = TypeManager.GetTypeArguments (q) [0];
4535 var p_m = Delegate.GetInvokeMethod (p);
4536 var q_m = Delegate.GetInvokeMethod (q);
4542 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4544 if (p.Kind == MemberKind.Void) {
4545 return q.Kind != MemberKind.Void ? 2 : 0;
4549 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4551 if (q.Kind == MemberKind.Void) {
4552 return p.Kind != MemberKind.Void ? 1 : 0;
4555 return IsBetterConversionTarget (rc, p, q);
4558 if (p.IsGenericTask && q.IsGenericTask) {
4559 q = q.TypeArguments [0];
4560 p = p.TypeArguments [0];
4561 return IsBetterConversionTarget (rc, p, q);
4565 if (p.IsNullableType) {
4566 p = Nullable.NullableInfo.GetUnderlyingType (p);
4567 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (p))
4568 return BetterTypeConversionImplicitConversion (rc, p_orig, q);
4571 // Spec expects implicit conversion check between p and q, q and p
4572 // to be done before nullable unwrapping but that's expensive operation.
4574 // Extra manual tweak is needed because BetterTypeConversion works on
4582 if (q.IsNullableType) {
4583 q = Nullable.NullableInfo.GetUnderlyingType (q);
4584 if (!BuiltinTypeSpec.IsPrimitiveTypeOrDecimal (q))
4585 return BetterTypeConversionImplicitConversion (rc, p_orig, q_orig);
4591 return BetterTypeConversion (rc, p, q);
4595 // 7.4.3.4 Better conversion from type
4597 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4599 if (p == null || q == null)
4600 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4602 switch (p.BuiltinType) {
4603 case BuiltinTypeSpec.Type.Int:
4604 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4607 case BuiltinTypeSpec.Type.Long:
4608 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4611 case BuiltinTypeSpec.Type.SByte:
4612 switch (q.BuiltinType) {
4613 case BuiltinTypeSpec.Type.Byte:
4614 case BuiltinTypeSpec.Type.UShort:
4615 case BuiltinTypeSpec.Type.UInt:
4616 case BuiltinTypeSpec.Type.ULong:
4620 case BuiltinTypeSpec.Type.Short:
4621 switch (q.BuiltinType) {
4622 case BuiltinTypeSpec.Type.UShort:
4623 case BuiltinTypeSpec.Type.UInt:
4624 case BuiltinTypeSpec.Type.ULong:
4628 case BuiltinTypeSpec.Type.Dynamic:
4629 // LAMESPEC: Dynamic conversions is not considered
4630 p = ec.Module.Compiler.BuiltinTypes.Object;
4634 switch (q.BuiltinType) {
4635 case BuiltinTypeSpec.Type.Int:
4636 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4639 case BuiltinTypeSpec.Type.Long:
4640 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4643 case BuiltinTypeSpec.Type.SByte:
4644 switch (p.BuiltinType) {
4645 case BuiltinTypeSpec.Type.Byte:
4646 case BuiltinTypeSpec.Type.UShort:
4647 case BuiltinTypeSpec.Type.UInt:
4648 case BuiltinTypeSpec.Type.ULong:
4652 case BuiltinTypeSpec.Type.Short:
4653 switch (p.BuiltinType) {
4654 case BuiltinTypeSpec.Type.UShort:
4655 case BuiltinTypeSpec.Type.UInt:
4656 case BuiltinTypeSpec.Type.ULong:
4660 case BuiltinTypeSpec.Type.Dynamic:
4661 // LAMESPEC: Dynamic conversions is not considered
4662 q = ec.Module.Compiler.BuiltinTypes.Object;
4666 return BetterTypeConversionImplicitConversion (ec, p, q);
4669 static int BetterTypeConversionImplicitConversion (ResolveContext rc, TypeSpec p, TypeSpec q)
4671 // TODO: this is expensive
4672 Expression p_tmp = new EmptyExpression (p);
4673 Expression q_tmp = new EmptyExpression (q);
4675 bool p_to_q = Convert.ImplicitConversionExists (rc, p_tmp, q);
4676 bool q_to_p = Convert.ImplicitConversionExists (rc, q_tmp, p);
4678 if (p_to_q && !q_to_p)
4681 if (q_to_p && !p_to_q)
4688 /// Determines "Better function" between candidate
4689 /// and the current best match
4692 /// Returns a boolean indicating :
4693 /// false if candidate ain't better
4694 /// true if candidate is better than the current best match
4696 bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4697 MemberSpec best, AParametersCollection bparam, bool best_params)
4699 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4700 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4702 int candidate_better_count = 0;
4703 int best_better_count = 0;
4705 bool are_equivalent = true;
4706 int args_count = args == null ? 0 : args.Count;
4710 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4713 // Default arguments are ignored for better decision
4714 if (a.IsDefaultArgument)
4718 // When comparing named argument the parameter type index has to be looked up
4719 // in original parameter set (override version for virtual members)
4721 NamedArgument na = a as NamedArgument;
4723 int idx = cparam.GetParameterIndexByName (na.Name);
4724 ct = candidate_pd.Types[idx];
4725 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4726 ct = TypeManager.GetElementType (ct);
4728 idx = bparam.GetParameterIndexByName (na.Name);
4729 bt = best_pd.Types[idx];
4730 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4731 bt = TypeManager.GetElementType (bt);
4733 ct = candidate_pd.Types[c_idx];
4734 bt = best_pd.Types[b_idx];
4736 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4737 ct = TypeManager.GetElementType (ct);
4741 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4742 bt = TypeManager.GetElementType (bt);
4747 if (TypeSpecComparer.IsEqual (ct, bt))
4750 are_equivalent = false;
4751 int result = BetterExpressionConversion (ec, a, ct, bt);
4753 // for each argument, the conversion to 'ct' should be no worse than
4754 // the conversion to 'bt'.
4757 // No optional parameters tie breaking rules for delegates overload resolution
4759 if ((restrictions & Restrictions.CovariantDelegate) != 0)
4762 ++best_better_count;
4766 // for at least one argument, the conversion to 'ct' should be better than
4767 // the conversion to 'bt'.
4769 ++candidate_better_count;
4772 if (candidate_better_count != 0 && best_better_count == 0)
4775 if (best_better_count > 0 && candidate_better_count == 0)
4779 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4781 if (!are_equivalent) {
4782 while (j < args_count && !args [j++].IsDefaultArgument) ;
4785 // A candidate with no default parameters is still better when there
4786 // is no better expression conversion and does not have more parameters
4788 if (candidate_pd.Count < best_pd.Count) {
4789 if (candidate_params)
4792 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue)
4795 if (best_pd.FixedParameters [j].HasDefaultValue)
4798 } else if (candidate_pd.Count == best_pd.Count) {
4799 if (candidate_params)
4802 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4805 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4813 // If candidate is applicable in its normal form and best has a params array and is applicable
4814 // only in its expanded form, then candidate is better
4816 if (candidate_params != best_params)
4817 return !candidate_params;
4820 // We have not reached end of parameters list due to params or used default parameters
4822 bool defaults_ambiguity = false;
4823 while (j < candidate_pd.Count && j < best_pd.Count) {
4824 var cand_param = candidate_pd.FixedParameters [j];
4825 var best_param = best_pd.FixedParameters [j];
4827 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4828 return cand_param.HasDefaultValue;
4830 defaults_ambiguity = true;
4831 if (candidate_pd.Count == best_pd.Count) {
4835 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4836 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4838 if (cand_param.HasDefaultValue) {
4847 // Neither is better when not all arguments are provided
4849 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4850 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4851 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4856 if (candidate_pd.Count != best_pd.Count) {
4857 if (defaults_ambiguity && best_pd.Count - 1 == j)
4858 return best_pd.HasParams;
4860 return candidate_pd.Count < best_pd.Count;
4864 // One is a non-generic method and second is a generic method, then non-generic is better
4866 if (best.IsGeneric != candidate.IsGeneric)
4867 return best.IsGeneric;
4870 // Both methods have the same number of parameters, and the parameters have equal types
4871 // Pick the "more specific" signature using rules over original (non-inflated) types
4873 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4874 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4876 bool specific_at_least_once = false;
4877 for (j = 0; j < args_count; ++j) {
4878 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4880 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4881 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4883 ct = candidate_def_pd.Types[j];
4884 bt = best_def_pd.Types[j];
4889 TypeSpec specific = MoreSpecific (ct, bt);
4893 specific_at_least_once = true;
4896 if (specific_at_least_once)
4902 static bool CheckInflatedArguments (MethodSpec ms)
4904 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4907 // Setup constraint checker for probing only
4908 ConstraintChecker cc = new ConstraintChecker (null);
4910 var mp = ms.Parameters.Types;
4911 for (int i = 0; i < mp.Length; ++i) {
4912 var type = mp[i] as InflatedTypeSpec;
4916 var targs = type.TypeArguments;
4917 if (targs.Length == 0)
4920 // TODO: Checking inflated MVAR arguments should be enough
4921 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4928 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4930 rc.Report.Error (1729, loc,
4931 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4932 type.GetSignatureForError (), argCount.ToString ());
4936 // Determines if the candidate method is applicable to the given set of arguments
4937 // There could be two different set of parameters for same candidate where one
4938 // is the closest override for default values and named arguments checks and second
4939 // one being the virtual base for the parameter types and modifiers.
4941 // A return value rates candidate method compatibility,
4943 // 0 = the best, int.MaxValue = the worst
4945 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)
4948 // Each step has allocated 10 values, it can overflow for
4949 // more than 10 arguments but that's ok as it's used for
4950 // better error reporting only
4952 const int ArgumentCountMismatch = 1000000000;
4953 const int NamedArgumentsMismatch = 100000000;
4954 const int DefaultArgumentMismatch = 10000000;
4955 const int UnexpectedTypeArguments = 1000000;
4956 const int TypeArgumentsMismatch = 100000;
4957 const int InflatedTypesMismatch = 10000;
4959 // Parameters of most-derived type used mainly for named and optional parameters
4960 var pd = pm.Parameters;
4962 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4963 // params modifier instead of most-derived type
4964 var cpd = ((IParametersMember) candidate).Parameters;
4965 int param_count = pd.Count;
4966 int optional_count = 0;
4968 Arguments orig_args = arguments;
4970 if (arg_count != param_count) {
4972 // No arguments expansion when doing exact match for delegates
4974 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4975 for (int i = 0; i < pd.Count; ++i) {
4976 if (pd.FixedParameters[i].HasDefaultValue) {
4977 optional_count = pd.Count - i;
4983 if (optional_count != 0) {
4984 // Readjust expected number when params used
4985 if (cpd.HasParams) {
4987 if (arg_count < param_count)
4989 } else if (arg_count > param_count) {
4990 int args_gap = System.Math.Abs (arg_count - param_count);
4991 return ArgumentCountMismatch + args_gap;
4992 } else if (arg_count < param_count - optional_count) {
4993 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4994 return ArgumentCountMismatch + args_gap;
4996 } else if (arg_count != param_count) {
4997 int args_gap = System.Math.Abs (arg_count - param_count);
4999 return ArgumentCountMismatch + args_gap;
5000 if (arg_count < param_count - 1)
5001 return ArgumentCountMismatch + args_gap;
5004 // Resize to fit optional arguments
5005 if (optional_count != 0) {
5006 if (arguments == null) {
5007 arguments = new Arguments (optional_count);
5009 // Have to create a new container, so the next run can do same
5010 var resized = new Arguments (param_count);
5011 resized.AddRange (arguments);
5012 arguments = resized;
5015 for (int i = arg_count; i < param_count; ++i)
5016 arguments.Add (null);
5020 if (arg_count > 0) {
5022 // Shuffle named arguments to the right positions if there are any
5024 if (arguments[arg_count - 1] is NamedArgument) {
5025 arg_count = arguments.Count;
5027 for (int i = 0; i < arg_count; ++i) {
5028 bool arg_moved = false;
5030 NamedArgument na = arguments[i] as NamedArgument;
5034 int index = pd.GetParameterIndexByName (na.Name);
5036 // Named parameter not found
5038 return NamedArgumentsMismatch - i;
5040 // already reordered
5045 if (index >= param_count) {
5046 // When using parameters which should not be available to the user
5047 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
5050 arguments.Add (null);
5054 if (index == arg_count)
5055 return NamedArgumentsMismatch - i - 1;
5057 temp = arguments [index];
5059 // The slot has been taken by positional argument
5060 if (temp != null && !(temp is NamedArgument))
5061 return NamedArgumentsMismatch - i - 1;
5065 arguments = arguments.MarkOrderedArgument (na);
5069 if (arguments == orig_args) {
5070 arguments = new Arguments (orig_args.Count);
5071 arguments.AddRange (orig_args);
5074 arguments[index] = arguments[i];
5075 arguments[i] = temp;
5082 arg_count = arguments.Count;
5084 } else if (arguments != null) {
5085 arg_count = arguments.Count;
5089 // Don't do any expensive checks when the candidate cannot succeed
5091 if (arg_count != param_count && !cpd.HasParams)
5092 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5094 var dep = candidate.GetMissingDependencies ();
5096 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5101 // 1. Handle generic method using type arguments when specified or type inference
5104 var ms = candidate as MethodSpec;
5105 if (ms != null && ms.IsGeneric) {
5106 if (type_arguments != null) {
5107 var g_args_count = ms.Arity;
5108 if (g_args_count != type_arguments.Count)
5109 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5111 if (type_arguments.Arguments != null)
5112 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5115 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5116 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5117 // candidate was found use the set to report more details about what was wrong with lambda body.
5118 // The general idea is to distinguish between code errors and errors caused by
5119 // trial-and-error type inference
5121 if (lambda_conv_msgs == null) {
5122 for (int i = 0; i < arg_count; i++) {
5123 Argument a = arguments[i];
5127 var am = a.Expr as AnonymousMethodExpression;
5129 if (lambda_conv_msgs == null)
5130 lambda_conv_msgs = new SessionReportPrinter ();
5132 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5137 var ti = new TypeInference (arguments);
5138 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5141 return TypeArgumentsMismatch - ti.InferenceScore;
5144 // Clear any error messages when the result was success
5146 if (lambda_conv_msgs != null)
5147 lambda_conv_msgs.ClearSession ();
5149 if (i_args.Length != 0) {
5151 for (int i = 0; i < i_args.Length; ++i) {
5152 var ta = i_args [i];
5153 if (!ta.IsAccessible (ec))
5154 return TypeArgumentsMismatch - i;
5158 ms = ms.MakeGenericMethod (ec, i_args);
5163 // Type arguments constraints have to match for the method to be applicable
5165 if (!CheckInflatedArguments (ms)) {
5167 return InflatedTypesMismatch;
5171 // We have a generic return type and at same time the method is override which
5172 // means we have to also inflate override return type in case the candidate is
5173 // best candidate and override return type is different to base return type.
5175 // virtual Foo<T, object> with override Foo<T, dynamic>
5177 if (candidate != pm) {
5178 MethodSpec override_ms = (MethodSpec) pm;
5179 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5180 returnType = inflator.Inflate (returnType);
5182 returnType = ms.ReturnType;
5189 if (type_arguments != null)
5190 return UnexpectedTypeArguments;
5196 // 2. Each argument has to be implicitly convertible to method parameter
5198 Parameter.Modifier p_mod = 0;
5201 for (int i = 0; i < arg_count; i++) {
5202 Argument a = arguments[i];
5204 var fp = pd.FixedParameters[i];
5205 if (!fp.HasDefaultValue) {
5206 arguments = orig_args;
5207 return arg_count * 2 + 2;
5211 // Get the default value expression, we can use the same expression
5212 // if the type matches
5214 Expression e = fp.DefaultValue;
5216 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5218 // Restore for possible error reporting
5219 for (int ii = i; ii < arg_count; ++ii)
5220 arguments.RemoveAt (i);
5222 return (arg_count - i) * 2 + 1;
5226 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5228 // LAMESPEC: Attributes can be mixed together with build-in priority
5230 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5231 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5232 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5233 e = new StringLiteral (ec.BuiltinTypes, loc.SourceFile.GetFullPathName (ec.Module.Compiler.Settings.PathMap), loc);
5234 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5235 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5239 arguments[i] = new Argument (e, Argument.AType.Default);
5243 if (p_mod != Parameter.Modifier.PARAMS) {
5244 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5246 } else if (!params_expanded_form) {
5247 params_expanded_form = true;
5248 pt = ((ElementTypeSpec) pt).Element;
5254 if (!params_expanded_form) {
5255 if (a.IsExtensionType) {
5256 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5261 score = IsArgumentCompatible (ec, a, p_mod, pt);
5264 dynamicArgument = true;
5269 // It can be applicable in expanded form (when not doing exact match like for delegates)
5271 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5272 if (!params_expanded_form) {
5273 pt = ((ElementTypeSpec) pt).Element;
5277 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5280 params_expanded_form = true;
5281 dynamicArgument = true;
5282 } else if (score == 0 || arg_count > pd.Count) {
5283 params_expanded_form = true;
5288 if (params_expanded_form)
5290 return (arg_count - i) * 2 + score;
5295 // Restore original arguments for dynamic binder to keep the intention of original source code
5297 if (dynamicArgument)
5298 arguments = orig_args;
5303 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5305 if (e is Constant && e.Type == ptype)
5309 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5311 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5312 e = new MemberAccess (new MemberAccess (new MemberAccess (
5313 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5314 } else if (e is Constant) {
5316 // Handles int to int? conversions, DefaultParameterValue check
5318 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5322 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5325 return e.Resolve (ec);
5329 // Tests argument compatibility with the parameter
5330 // The possible return values are
5332 // 1 - modifier mismatch
5333 // 2 - type mismatch
5334 // -1 - dynamic binding required
5336 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5339 // Types have to be identical when ref or out modifer
5340 // is used and argument is not of dynamic type
5342 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5343 var arg_type = argument.Type;
5345 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5347 // Using dynamic for ref/out parameter can still succeed at runtime
5349 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5355 if (arg_type != parameter) {
5356 if (arg_type == InternalType.VarOutType)
5360 // Do full equality check after quick path
5362 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5364 // Using dynamic for ref/out parameter can still succeed at runtime
5366 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5374 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5378 // Use implicit conversion in all modes to return same candidates when the expression
5379 // is used as argument or delegate conversion
5381 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5382 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5389 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5391 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5393 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5396 var ac_p = p as ArrayContainer;
5398 var ac_q = q as ArrayContainer;
5402 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5403 if (specific == ac_p.Element)
5405 if (specific == ac_q.Element)
5407 } else if (p.IsGeneric && q.IsGeneric) {
5408 var pargs = TypeManager.GetTypeArguments (p);
5409 var qargs = TypeManager.GetTypeArguments (q);
5411 bool p_specific_at_least_once = false;
5412 bool q_specific_at_least_once = false;
5414 for (int i = 0; i < pargs.Length; i++) {
5415 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5416 if (specific == pargs[i])
5417 p_specific_at_least_once = true;
5418 if (specific == qargs[i])
5419 q_specific_at_least_once = true;
5422 if (p_specific_at_least_once && !q_specific_at_least_once)
5424 if (!p_specific_at_least_once && q_specific_at_least_once)
5432 // Find the best method from candidate list
5434 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5436 List<AmbiguousCandidate> ambiguous_candidates = null;
5438 MemberSpec best_candidate;
5439 Arguments best_candidate_args = null;
5440 bool best_candidate_params = false;
5441 bool best_candidate_dynamic = false;
5442 int best_candidate_rate;
5443 IParametersMember best_parameter_member = null;
5445 int args_count = args != null ? args.Count : 0;
5447 Arguments candidate_args = args;
5448 bool error_mode = false;
5449 MemberSpec invocable_member = null;
5450 int applicable_candidates = 0;
5453 best_candidate = null;
5454 best_candidate_rate = int.MaxValue;
5456 var type_members = members;
5458 for (int i = 0; i < type_members.Count; ++i) {
5459 var member = type_members[i];
5462 // Methods in a base class are not candidates if any method in a derived
5463 // class is applicable
5465 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5469 if (!member.IsAccessible (rc))
5472 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5475 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5476 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5481 IParametersMember pm = member as IParametersMember;
5484 // Will use it later to report ambiguity between best method and invocable member
5486 if (Invocation.IsMemberInvocable (member))
5487 invocable_member = member;
5493 // Overload resolution is looking for base member but using parameter names
5494 // and default values from the closest member. That means to do expensive lookup
5495 // for the closest override for virtual or abstract members
5497 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5498 var override_params = base_provider.GetOverrideMemberParameters (member);
5499 if (override_params != null)
5500 pm = override_params;
5504 // Check if the member candidate is applicable
5506 bool params_expanded_form = false;
5507 bool dynamic_argument = false;
5508 TypeSpec rt = pm.MemberType;
5509 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5511 if (lambda_conv_msgs != null)
5512 lambda_conv_msgs.EndSession ();
5515 // How does it score compare to others
5517 if (candidate_rate < best_candidate_rate) {
5519 // Fatal error (missing dependency), cannot continue
5520 if (candidate_rate < 0)
5523 applicable_candidates = 1;
5524 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5525 // Only parameterless methods are considered
5527 best_candidate_rate = candidate_rate;
5528 best_candidate = member;
5529 best_candidate_args = candidate_args;
5530 best_candidate_params = params_expanded_form;
5531 best_candidate_dynamic = dynamic_argument;
5532 best_parameter_member = pm;
5533 best_candidate_return_type = rt;
5535 } else if (candidate_rate == 0) {
5537 // The member look is done per type for most operations but sometimes
5538 // it's not possible like for binary operators overload because they
5539 // are unioned between 2 sides
5541 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5542 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5546 ++applicable_candidates;
5548 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5550 // We pack all interface members into top level type which makes the overload resolution
5551 // more complicated for interfaces. We compensate it by removing methods with same
5552 // signature when building the cache hence this path should not really be hit often
5555 // interface IA { void Foo (int arg); }
5556 // interface IB : IA { void Foo (params int[] args); }
5558 // IB::Foo is the best overload when calling IB.Foo (1)
5561 if (ambiguous_candidates != null) {
5562 foreach (var amb_cand in ambiguous_candidates) {
5563 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5572 ambiguous_candidates = null;
5575 // Is the new candidate better
5576 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5580 best_candidate = member;
5581 best_candidate_args = candidate_args;
5582 best_candidate_params = params_expanded_form;
5583 best_candidate_dynamic = dynamic_argument;
5584 best_parameter_member = pm;
5585 best_candidate_return_type = rt;
5587 // It's not better but any other found later could be but we are not sure yet
5588 if (ambiguous_candidates == null)
5589 ambiguous_candidates = new List<AmbiguousCandidate> ();
5591 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5595 // Restore expanded arguments
5596 candidate_args = args;
5598 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType)) != null);
5601 // We've found exact match
5603 if (best_candidate_rate == 0)
5607 // Try extension methods lookup when no ordinary method match was found and provider enables it
5610 var emg = base_provider.LookupExtensionMethod (rc);
5612 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5614 best_candidate_extension_group = emg;
5615 return (T) (MemberSpec) emg.BestCandidate;
5620 // Don't run expensive error reporting mode for probing
5627 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5630 lambda_conv_msgs = null;
5635 // No best member match found, report an error
5637 if (best_candidate_rate != 0 || error_mode) {
5638 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5642 if (best_candidate_dynamic) {
5643 if (args[0].IsExtensionType) {
5644 rc.Report.Error (1973, loc,
5645 "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",
5646 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5650 // Check type constraints only when explicit type arguments are used
5652 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5653 MethodSpec bc = best_candidate as MethodSpec;
5654 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5655 ConstraintChecker cc = new ConstraintChecker (rc);
5656 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5660 BestCandidateIsDynamic = true;
5665 // These flags indicates we are running delegate probing conversion. No need to
5666 // do more expensive checks
5668 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5669 return (T) best_candidate;
5671 if (ambiguous_candidates != null) {
5673 // Now check that there are no ambiguities i.e the selected method
5674 // should be better than all the others
5676 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5677 var candidate = ambiguous_candidates [ix];
5679 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5680 var ambiguous = candidate.Member;
5681 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5682 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5683 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5684 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5685 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5688 return (T) best_candidate;
5693 if (invocable_member != null && !IsProbingOnly) {
5694 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5695 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5696 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5697 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5701 // And now check if the arguments are all
5702 // compatible, perform conversions if
5703 // necessary etc. and return if everything is
5706 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5709 if (best_candidate == null)
5713 // Don't run possibly expensive checks in probing mode
5715 if (!IsProbingOnly && !rc.IsInProbingMode) {
5717 // Check ObsoleteAttribute on the best method
5719 best_candidate.CheckObsoleteness (rc, loc);
5721 best_candidate.MemberDefinition.SetIsUsed ();
5724 args = best_candidate_args;
5725 return (T) best_candidate;
5728 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5730 return ResolveMember<MethodSpec> (rc, ref args);
5733 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5734 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5736 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5739 if (a.Type == InternalType.ErrorType)
5742 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5743 ec.Report.SymbolRelatedToPreviousError (method);
5744 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5745 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5746 TypeManager.CSharpSignature (method));
5749 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5750 TypeManager.CSharpSignature (method));
5751 } else if (IsDelegateInvoke) {
5752 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5753 DelegateType.GetSignatureForError ());
5755 ec.Report.SymbolRelatedToPreviousError (method);
5756 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5757 method.GetSignatureForError ());
5760 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5762 string index = (idx + 1).ToString ();
5763 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5764 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5765 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5766 index, Parameter.GetModifierSignature (a.Modifier));
5768 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5769 index, Parameter.GetModifierSignature (mod));
5771 string p1 = a.GetSignatureForError ();
5772 string p2 = paramType.GetSignatureForError ();
5775 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5776 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5779 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5780 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5781 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5784 ec.Report.Error (1503, a.Expr.Location,
5785 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5790 // We have failed to find exact match so we return error info about the closest match
5792 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5794 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5795 int arg_count = args == null ? 0 : args.Count;
5797 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5798 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5799 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5803 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5808 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5809 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5810 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5814 // For candidates which match on parameters count report more details about incorrect arguments
5817 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5818 // Reject any inaccessible member
5819 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5820 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5821 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5825 var ms = best_candidate as MethodSpec;
5826 if (ms != null && ms.IsGeneric) {
5827 bool constr_ok = true;
5828 if (ms.TypeArguments != null)
5829 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5831 if (ta_count == 0 && ms.TypeArguments == null) {
5832 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5836 rc.Report.Error (411, loc,
5837 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5838 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5845 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5851 // We failed to find any method with correct argument count, report best candidate
5853 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5856 if (best_candidate.Kind == MemberKind.Constructor) {
5857 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5858 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5859 } else if (IsDelegateInvoke) {
5860 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5861 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5862 DelegateType.GetSignatureForError (), arg_count.ToString ());
5864 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5865 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5866 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5867 name, arg_count.ToString ());
5871 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5873 var p = ((IParametersMember)best_candidate).Parameters;
5878 for (int i = p.Count - 1; i != 0; --i) {
5879 var fp = p.FixedParameters [i];
5880 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5890 foreach (var arg in args) {
5891 var na = arg as NamedArgument;
5895 if (na.Name == name) {
5904 return args.Count + 1 == pm.Parameters.Count;
5907 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5909 var pd = pm.Parameters;
5910 var cpd = ((IParametersMember) member).Parameters;
5911 var ptypes = cpd.Types;
5913 Parameter.Modifier p_mod = 0;
5915 int a_idx = 0, a_pos = 0;
5917 ArrayInitializer params_initializers = null;
5918 bool has_unsafe_arg = pm.MemberType.IsPointer;
5919 int arg_count = args == null ? 0 : args.Count;
5921 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5926 if (p_mod != Parameter.Modifier.PARAMS) {
5927 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5929 has_unsafe_arg |= pt.IsPointer;
5931 if (p_mod == Parameter.Modifier.PARAMS) {
5932 if (chose_params_expanded) {
5933 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5934 pt = TypeManager.GetElementType (pt);
5940 // Types have to be identical when ref or out modifer is used
5942 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5943 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5946 var arg_type = a.Type;
5950 if (arg_type == InternalType.VarOutType) {
5952 // Set underlying variable type based on parameter type
5954 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5958 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5962 NamedArgument na = a as NamedArgument;
5964 int name_index = pd.GetParameterIndexByName (na.Name);
5965 if (name_index < 0 || name_index >= pd.Count) {
5966 if (IsDelegateInvoke) {
5967 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5968 ec.Report.Error (1746, na.Location,
5969 "The delegate `{0}' does not contain a parameter named `{1}'",
5970 DelegateType.GetSignatureForError (), na.Name);
5972 ec.Report.SymbolRelatedToPreviousError (member);
5973 ec.Report.Error (1739, na.Location,
5974 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5975 TypeManager.CSharpSignature (member), na.Name);
5977 } else if (args[name_index] != a && args[name_index] != null) {
5978 if (IsDelegateInvoke)
5979 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5981 ec.Report.SymbolRelatedToPreviousError (member);
5983 ec.Report.Error (1744, na.Location,
5984 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5989 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5992 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5993 if (a.IsExtensionType) {
5994 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5995 // CS1061 but that still better than confusing CS0123
5996 var ma = new MemberAccess (a.Expr, member.Name, loc);
5997 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5999 custom_errors.NoArgumentMatch (ec, member);
6005 if (a.IsExtensionType) {
6006 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
6009 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
6011 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
6014 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
6021 // Convert params arguments to an array initializer
6023 if (params_initializers != null) {
6024 // we choose to use 'a.Expr' rather than 'conv' so that
6025 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
6026 params_initializers.Add (a.Expr);
6027 args.RemoveAt (a_idx--);
6033 // Update the argument with the implicit conversion
6037 if (a_idx != arg_count) {
6039 // Convert all var out argument to error type for less confusing error reporting
6040 // when no matching overload is found
6042 for (; a_idx < arg_count; a_idx++) {
6043 var arg = args [a_idx];
6047 if (arg.Type == InternalType.VarOutType) {
6048 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
6052 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
6057 // Fill not provided arguments required by params modifier
6059 if (params_initializers == null && arg_count + 1 == pd.Count) {
6061 args = new Arguments (1);
6063 pt = ptypes[pd.Count - 1];
6064 pt = TypeManager.GetElementType (pt);
6065 has_unsafe_arg |= pt.IsPointer;
6066 params_initializers = new ArrayInitializer (0, loc);
6070 // Append an array argument with all params arguments
6072 if (params_initializers != null) {
6073 args.Add (new Argument (
6074 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6078 if (has_unsafe_arg && !ec.IsUnsafe) {
6079 Expression.UnsafeError (ec, loc);
6083 // We could infer inaccesible type arguments
6085 if (type_arguments == null && member.IsGeneric) {
6086 var ms = (MethodSpec) member;
6087 foreach (var ta in ms.TypeArguments) {
6088 if (!ta.IsAccessible (ec)) {
6089 ec.Report.SymbolRelatedToPreviousError (ta);
6090 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6100 public class ConstantExpr : MemberExpr
6102 readonly ConstSpec constant;
6104 public ConstantExpr (ConstSpec constant, Location loc)
6106 this.constant = constant;
6110 public override string Name {
6111 get { throw new NotImplementedException (); }
6114 public override string KindName {
6115 get { return "constant"; }
6118 public override bool IsInstance {
6119 get { return !IsStatic; }
6122 public override bool IsStatic {
6123 get { return true; }
6126 protected override TypeSpec DeclaringType {
6127 get { return constant.DeclaringType; }
6130 public override Expression CreateExpressionTree (ResolveContext ec)
6132 throw new NotSupportedException ("ET");
6135 protected override Expression DoResolve (ResolveContext rc)
6137 ResolveInstanceExpression (rc, null);
6138 DoBestMemberChecks (rc, constant);
6140 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6141 eclass = ExprClass.Value;
6142 type = constant.MemberType;
6146 var c = constant.GetConstant (rc);
6148 // Creates reference expression to the constant value
6149 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6152 public override void Emit (EmitContext ec)
6154 throw new NotSupportedException ();
6157 public override string GetSignatureForError ()
6159 return constant.GetSignatureForError ();
6162 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6164 constant.CheckObsoleteness (rc, expr.Location);
6167 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6169 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6174 // Fully resolved expression that references a Field
6176 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6178 protected FieldSpec spec;
6179 VariableInfo variable_info;
6181 LocalTemporary temp;
6184 protected FieldExpr (Location l)
6189 public FieldExpr (FieldSpec spec, Location loc)
6194 type = spec.MemberType;
6197 public FieldExpr (FieldBase fi, Location l)
6204 public override string Name {
6210 public bool IsHoisted {
6212 IVariableReference hv = InstanceExpression as IVariableReference;
6213 return hv != null && hv.IsHoisted;
6217 public override bool IsInstance {
6219 return !spec.IsStatic;
6223 public override bool IsStatic {
6225 return spec.IsStatic;
6229 public override string KindName {
6230 get { return "field"; }
6233 public FieldSpec Spec {
6239 protected override TypeSpec DeclaringType {
6241 return spec.DeclaringType;
6245 public VariableInfo VariableInfo {
6247 return variable_info;
6253 public override string GetSignatureForError ()
6255 return spec.GetSignatureForError ();
6258 public bool IsMarshalByRefAccess (ResolveContext rc)
6260 // Checks possible ldflda of field access expression
6261 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6262 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6263 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6266 public void SetHasAddressTaken ()
6268 IVariableReference vr = InstanceExpression as IVariableReference;
6270 vr.SetHasAddressTaken ();
6274 protected override void CloneTo (CloneContext clonectx, Expression target)
6276 var t = (FieldExpr) target;
6278 if (InstanceExpression != null)
6279 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6282 public override Expression CreateExpressionTree (ResolveContext ec)
6284 if (ConditionalAccess) {
6285 Error_NullShortCircuitInsideExpressionTree (ec);
6288 return CreateExpressionTree (ec, true);
6291 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6294 Expression instance;
6296 if (InstanceExpression == null) {
6297 instance = new NullLiteral (loc);
6298 } else if (convertInstance) {
6299 instance = InstanceExpression.CreateExpressionTree (ec);
6301 args = new Arguments (1);
6302 args.Add (new Argument (InstanceExpression));
6303 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6306 args = Arguments.CreateForExpressionTree (ec, null,
6308 CreateTypeOfExpression ());
6310 return CreateExpressionFactoryCall (ec, "Field", args);
6313 public Expression CreateTypeOfExpression ()
6315 return new TypeOfField (spec, loc);
6318 protected override Expression DoResolve (ResolveContext ec)
6320 spec.MemberDefinition.SetIsUsed ();
6322 return DoResolve (ec, null);
6325 Expression DoResolve (ResolveContext ec, Expression rhs)
6327 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6330 ResolveConditionalAccessReceiver (ec);
6332 if (ResolveInstanceExpression (ec, rhs)) {
6333 // Resolve the field's instance expression while flow analysis is turned
6334 // off: when accessing a field "a.b", we must check whether the field
6335 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6337 if (lvalue_instance) {
6338 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6340 Expression right_side =
6341 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6343 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6345 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6348 if (InstanceExpression == null)
6352 DoBestMemberChecks (ec, spec);
6354 if (conditional_access_receiver)
6355 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6358 var fb = spec as FixedFieldSpec;
6359 IVariableReference var = InstanceExpression as IVariableReference;
6362 IFixedExpression fe = InstanceExpression as IFixedExpression;
6363 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6364 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6367 if (InstanceExpression.eclass != ExprClass.Variable) {
6368 ec.Report.SymbolRelatedToPreviousError (spec);
6369 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6370 TypeManager.GetFullNameSignature (spec));
6371 } else if (var != null && var.IsHoisted) {
6372 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6375 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6379 // Set flow-analysis variable info for struct member access. It will be check later
6380 // for precise error reporting
6382 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6383 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6386 if (conditional_access_receiver)
6387 type = LiftMemberType (ec, type);
6389 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6390 return Constant.CreateConstantFromValue (type, null, loc);
6392 eclass = ExprClass.Variable;
6396 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
6398 spec.CheckObsoleteness (rc, expr.Location);
6401 public void SetFieldAssigned (FlowAnalysisContext fc)
6406 bool lvalue_instance = spec.DeclaringType.IsStruct;
6407 if (lvalue_instance) {
6408 var var = InstanceExpression as IVariableReference;
6409 if (var != null && var.VariableInfo != null) {
6410 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6414 var fe = InstanceExpression as FieldExpr;
6416 Expression instance;
6419 instance = fe.InstanceExpression;
6420 var fe_instance = instance as FieldExpr;
6421 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6422 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6423 var var = InstanceExpression as IVariableReference;
6424 if (var != null && var.VariableInfo == null) {
6425 var var_inst = instance as IVariableReference;
6426 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6427 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6431 if (fe_instance != null) {
6440 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6441 instance.FlowAnalysis (fc);
6443 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6444 InstanceExpression.FlowAnalysis (fc);
6448 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6450 // The return value is always null. Returning a value simplifies calling code.
6452 if (right_side == EmptyExpression.OutAccess) {
6454 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6455 GetSignatureForError ());
6457 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6458 GetSignatureForError ());
6464 if (right_side == EmptyExpression.LValueMemberAccess) {
6465 // Already reported as CS1648/CS1650
6469 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6471 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6472 GetSignatureForError ());
6474 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6475 GetSignatureForError ());
6481 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6482 GetSignatureForError ());
6484 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6485 GetSignatureForError ());
6491 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6493 if (HasConditionalAccess ())
6494 Error_NullPropagatingLValue (ec);
6496 if (spec is FixedFieldSpec) {
6497 // It could be much better error message but we want to be error compatible
6498 Error_ValueAssignment (ec, right_side);
6501 Expression e = DoResolve (ec, right_side);
6506 spec.MemberDefinition.SetIsAssigned ();
6508 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6509 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6510 ec.Report.Warning (420, 1, loc,
6511 "`{0}': A volatile field references will not be treated as volatile",
6512 spec.GetSignatureForError ());
6515 if (spec.IsReadOnly) {
6516 // InitOnly fields can only be assigned in constructors or initializers
6517 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6518 return Error_AssignToReadonly (ec, right_side);
6520 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6522 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6523 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6524 return Error_AssignToReadonly (ec, right_side);
6525 // static InitOnly fields cannot be assigned-to in an instance constructor
6526 if (IsStatic && !ec.IsStatic)
6527 return Error_AssignToReadonly (ec, right_side);
6528 // instance constructors can't modify InitOnly fields of other instances of the same type
6529 if (!IsStatic && !(InstanceExpression is This))
6530 return Error_AssignToReadonly (ec, right_side);
6534 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6535 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6536 ec.Report.Warning (197, 1, loc,
6537 "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",
6538 GetSignatureForError ());
6541 eclass = ExprClass.Variable;
6545 public override void FlowAnalysis (FlowAnalysisContext fc)
6547 var var = InstanceExpression as IVariableReference;
6549 var vi = var.VariableInfo;
6550 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6551 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6555 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6556 var le = SkipLeftValueTypeAccess (InstanceExpression);
6558 le.FlowAnalysis (fc);
6564 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6566 base.FlowAnalysis (fc);
6568 if (conditional_access_receiver)
6569 fc.DefiniteAssignment = da;
6572 static Expression SkipLeftValueTypeAccess (Expression expr)
6574 if (!TypeSpec.IsValueType (expr.Type))
6577 if (expr is VariableReference)
6580 var fe = expr as FieldExpr;
6584 if (fe.InstanceExpression == null)
6587 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6590 public override int GetHashCode ()
6592 return spec.GetHashCode ();
6595 public bool IsFixed {
6598 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6600 IVariableReference variable = InstanceExpression as IVariableReference;
6601 if (variable != null)
6602 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6604 IFixedExpression fe = InstanceExpression as IFixedExpression;
6605 return fe != null && fe.IsFixed;
6609 public override bool Equals (object obj)
6611 FieldExpr fe = obj as FieldExpr;
6615 if (spec != fe.spec)
6618 if (InstanceExpression == null || fe.InstanceExpression == null)
6621 return InstanceExpression.Equals (fe.InstanceExpression);
6624 public void Emit (EmitContext ec, bool leave_copy)
6626 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6630 ec.Emit (OpCodes.Volatile);
6632 ec.Emit (OpCodes.Ldsfld, spec);
6634 var ca = ec.ConditionalAccess;
6637 if (conditional_access_receiver)
6638 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6640 EmitInstance (ec, false);
6643 // Optimization for build-in types
6644 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6645 ec.EmitLoadFromPtr (type);
6647 var ff = spec as FixedFieldSpec;
6649 ec.Emit (OpCodes.Ldflda, spec);
6650 ec.Emit (OpCodes.Ldflda, ff.Element);
6653 ec.Emit (OpCodes.Volatile);
6655 ec.Emit (OpCodes.Ldfld, spec);
6659 if (conditional_access_receiver) {
6660 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6661 ec.ConditionalAccess = ca;
6666 ec.Emit (OpCodes.Dup);
6668 temp = new LocalTemporary (this.Type);
6674 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6676 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6677 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6682 if (ConditionalAccess)
6683 throw new NotImplementedException ("null operator assignment");
6685 if (has_await_source)
6686 source = source.EmitToField (ec);
6688 EmitInstance (ec, prepared);
6693 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6694 ec.Emit (OpCodes.Dup);
6696 temp = new LocalTemporary (this.Type);
6701 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6702 ec.Emit (OpCodes.Volatile);
6704 spec.MemberDefinition.SetIsAssigned ();
6707 ec.Emit (OpCodes.Stsfld, spec);
6709 ec.Emit (OpCodes.Stfld, spec);
6711 if (ec.NotifyEvaluatorOnStore) {
6713 throw new NotImplementedException ("instance field write");
6716 ec.Emit (OpCodes.Dup);
6718 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6729 // Emits store to field with prepared values on stack
6731 public void EmitAssignFromStack (EmitContext ec)
6734 ec.Emit (OpCodes.Stsfld, spec);
6736 ec.Emit (OpCodes.Stfld, spec);
6740 public override void Emit (EmitContext ec)
6745 public override void EmitSideEffect (EmitContext ec)
6747 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6749 if (is_volatile) // || is_marshal_by_ref ())
6750 base.EmitSideEffect (ec);
6753 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6755 if ((mode & AddressOp.Store) != 0)
6756 spec.MemberDefinition.SetIsAssigned ();
6757 if ((mode & AddressOp.Load) != 0)
6758 spec.MemberDefinition.SetIsUsed ();
6761 // Handle initonly fields specially: make a copy and then
6762 // get the address of the copy.
6765 if (spec.IsReadOnly){
6767 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6779 var temp = ec.GetTemporaryLocal (type);
6780 ec.Emit (OpCodes.Stloc, temp);
6781 ec.Emit (OpCodes.Ldloca, temp);
6787 ec.Emit (OpCodes.Ldsflda, spec);
6790 EmitInstance (ec, false);
6791 ec.Emit (OpCodes.Ldflda, spec);
6795 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6797 return MakeExpression (ctx);
6800 public override SLE.Expression MakeExpression (BuilderContext ctx)
6803 return base.MakeExpression (ctx);
6805 return SLE.Expression.Field (
6806 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6807 spec.GetMetaInfo ());
6811 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6813 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6819 // Expression that evaluates to a Property.
6821 // This is not an LValue because we need to re-write the expression. We
6822 // can not take data from the stack and store it.
6824 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6826 Arguments arguments;
6827 FieldExpr backing_field;
6829 public PropertyExpr (PropertySpec spec, Location l)
6832 best_candidate = spec;
6833 type = spec.MemberType;
6838 protected override Arguments Arguments {
6847 protected override TypeSpec DeclaringType {
6849 return best_candidate.DeclaringType;
6853 public override string Name {
6855 return best_candidate.Name;
6859 public bool IsAutoPropertyAccess {
6861 var prop = best_candidate.MemberDefinition as Property;
6862 return prop != null && prop.BackingField != null;
6866 public override bool IsInstance {
6872 public override bool IsStatic {
6874 return best_candidate.IsStatic;
6878 public override string KindName {
6879 get { return "property"; }
6882 public PropertySpec PropertyInfo {
6884 return best_candidate;
6890 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6892 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6895 var args_count = arguments == null ? 0 : arguments.Count;
6896 if (args_count != body.Parameters.Count && args_count == 0)
6899 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6900 mg.InstanceExpression = InstanceExpression;
6905 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6907 return new PropertyExpr (spec, loc) {
6913 public override Expression CreateExpressionTree (ResolveContext ec)
6915 if (ConditionalAccess) {
6916 Error_NullShortCircuitInsideExpressionTree (ec);
6920 if (IsSingleDimensionalArrayLength ()) {
6921 args = new Arguments (1);
6922 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6923 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6926 args = new Arguments (2);
6927 if (InstanceExpression == null)
6928 args.Add (new Argument (new NullLiteral (loc)));
6930 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6931 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6932 return CreateExpressionFactoryCall (ec, "Property", args);
6935 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6937 DoResolveLValue (rc, null);
6938 return new TypeOfMethod (Setter, loc);
6941 public override string GetSignatureForError ()
6943 return best_candidate.GetSignatureForError ();
6946 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6949 return base.MakeExpression (ctx);
6951 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6955 public override SLE.Expression MakeExpression (BuilderContext ctx)
6958 return base.MakeExpression (ctx);
6960 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6964 void Error_PropertyNotValid (ResolveContext ec)
6966 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6967 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6968 GetSignatureForError ());
6971 bool IsSingleDimensionalArrayLength ()
6973 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6976 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6977 return ac != null && ac.Rank == 1;
6980 public override void Emit (EmitContext ec, bool leave_copy)
6983 // Special case: length of single dimension array property is turned into ldlen
6985 if (IsSingleDimensionalArrayLength ()) {
6986 if (conditional_access_receiver) {
6987 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6990 EmitInstance (ec, false);
6992 ec.Emit (OpCodes.Ldlen);
6993 ec.Emit (OpCodes.Conv_I4);
6995 if (conditional_access_receiver) {
6996 ec.CloseConditionalAccess (type);
7002 base.Emit (ec, leave_copy);
7005 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7007 if (backing_field != null) {
7008 backing_field.EmitAssign (ec, source, false, false);
7013 LocalTemporary await_source_arg = null;
7015 if (isCompound && !(source is DynamicExpressionStatement)) {
7016 emitting_compound_assignment = true;
7019 if (has_await_arguments) {
7020 await_source_arg = new LocalTemporary (Type);
7021 await_source_arg.Store (ec);
7023 args = new Arguments (1);
7024 args.Add (new Argument (await_source_arg));
7027 temp = await_source_arg;
7030 has_await_arguments = false;
7035 ec.Emit (OpCodes.Dup);
7036 temp = new LocalTemporary (this.Type);
7041 args = arguments ?? new Arguments (1);
7045 temp = new LocalTemporary (this.Type);
7047 args.Add (new Argument (temp));
7049 args.Add (new Argument (source));
7053 emitting_compound_assignment = false;
7055 var call = new CallEmitter ();
7056 call.InstanceExpression = InstanceExpression;
7058 call.InstanceExpressionOnStack = true;
7060 if (ConditionalAccess) {
7061 call.ConditionalAccess = true;
7065 call.Emit (ec, Setter, args, loc);
7067 call.EmitStatement (ec, Setter, args, loc);
7074 if (await_source_arg != null) {
7075 await_source_arg.Release (ec);
7079 public override void FlowAnalysis (FlowAnalysisContext fc)
7081 var prop = best_candidate.MemberDefinition as Property;
7082 if (prop != null && prop.BackingField != null) {
7083 var var = InstanceExpression as IVariableReference;
7085 var vi = var.VariableInfo;
7086 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7087 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7091 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7096 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7098 base.FlowAnalysis (fc);
7100 if (conditional_access_receiver)
7101 fc.DefiniteAssignment = da;
7104 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7106 eclass = ExprClass.PropertyAccess;
7108 if (best_candidate.IsNotCSharpCompatible) {
7109 Error_PropertyNotValid (rc);
7112 ResolveInstanceExpression (rc, right_side);
7114 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7115 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7116 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7118 type = p.MemberType;
7122 DoBestMemberChecks (rc, best_candidate);
7124 // Handling of com-imported properties with any number of default property parameters
7125 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7126 var p = best_candidate.Get.Parameters;
7127 arguments = new Arguments (p.Count);
7128 for (int i = 0; i < p.Count; ++i) {
7129 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7131 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7132 var p = best_candidate.Set.Parameters;
7133 arguments = new Arguments (p.Count - 1);
7134 for (int i = 0; i < p.Count - 1; ++i) {
7135 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7142 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7144 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7147 var prop = best_candidate.MemberDefinition as Property;
7148 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7149 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7153 prop = (Property)ps.MemberDefinition;
7156 var spec = prop.BackingField;
7160 if (rc.IsStatic != spec.IsStatic)
7163 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7166 backing_field = new FieldExpr (prop.BackingField, loc);
7167 backing_field.ResolveLValue (rc, rhs);
7171 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7173 if (!best_candidate.IsAccessible (rc))
7174 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), expr.Location);
7176 best_candidate.CheckObsoleteness (rc, expr.Location);
7179 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7181 if (backing_field != null) {
7182 backing_field.SetFieldAssigned (fc);
7186 if (!IsAutoPropertyAccess)
7189 var prop = best_candidate.MemberDefinition as Property;
7190 if (prop != null && prop.BackingField != null) {
7191 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7192 if (lvalue_instance) {
7193 var var = InstanceExpression as IVariableReference;
7194 if (var != null && var.VariableInfo != null) {
7195 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7201 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7203 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7207 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7209 // getter and setter can be different for base calls
7210 MethodSpec getter, setter;
7211 protected T best_candidate;
7213 protected LocalTemporary temp;
7214 protected bool emitting_compound_assignment;
7215 protected bool has_await_arguments;
7217 protected PropertyOrIndexerExpr (Location l)
7224 protected abstract Arguments Arguments { get; set; }
7226 public MethodSpec Getter {
7235 public MethodSpec Setter {
7246 protected override Expression DoResolve (ResolveContext ec)
7248 if (eclass == ExprClass.Unresolved) {
7249 ResolveConditionalAccessReceiver (ec);
7251 var expr = OverloadResolve (ec, null);
7256 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7257 return expr.Resolve (ec);
7260 if (conditional_access_receiver) {
7261 type = LiftMemberType (ec, type);
7265 if (!ResolveGetter (ec))
7271 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7273 if (HasConditionalAccess ())
7274 Error_NullPropagatingLValue (rc);
7276 if (right_side == EmptyExpression.OutAccess) {
7277 // TODO: best_candidate can be null at this point
7278 INamedBlockVariable variable = null;
7279 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7280 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7281 best_candidate.Name);
7283 right_side.DoResolveLValue (rc, this);
7288 if (eclass == ExprClass.Unresolved) {
7289 var expr = OverloadResolve (rc, right_side);
7294 return expr.ResolveLValue (rc, right_side);
7296 ResolveInstanceExpression (rc, right_side);
7299 if (!best_candidate.HasSet) {
7300 if (ResolveAutopropertyAssignment (rc, right_side))
7303 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7304 GetSignatureForError ());
7308 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7309 if (best_candidate.HasDifferentAccessibility) {
7310 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7311 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7312 GetSignatureForError ());
7314 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7315 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7319 if (best_candidate.HasDifferentAccessibility)
7320 CheckProtectedMemberAccess (rc, best_candidate.Set);
7322 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7326 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7328 var ca = ec.ConditionalAccess;
7329 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7331 call.Emit (ec, method, arguments, loc);
7333 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7334 ec.ConditionalAccess = ca;
7338 // Implements the IAssignMethod interface for assignments
7340 public virtual void Emit (EmitContext ec, bool leave_copy)
7342 var call = new CallEmitter ();
7343 call.ConditionalAccess = ConditionalAccess;
7344 call.InstanceExpression = InstanceExpression;
7345 if (has_await_arguments)
7346 call.HasAwaitArguments = true;
7348 call.DuplicateArguments = emitting_compound_assignment;
7350 if (conditional_access_receiver)
7351 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7353 call.Emit (ec, Getter, Arguments, loc);
7355 if (call.HasAwaitArguments) {
7356 InstanceExpression = call.InstanceExpression;
7357 Arguments = call.EmittedArguments;
7358 has_await_arguments = true;
7362 ec.Emit (OpCodes.Dup);
7363 temp = new LocalTemporary (Type);
7368 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7370 public override void Emit (EmitContext ec)
7375 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7377 has_await_arguments = true;
7382 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7384 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7386 bool ResolveGetter (ResolveContext rc)
7388 if (!best_candidate.HasGet) {
7389 if (InstanceExpression != EmptyExpression.Null) {
7390 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7391 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7392 best_candidate.GetSignatureForError ());
7395 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7396 if (best_candidate.HasDifferentAccessibility) {
7397 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7398 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7399 TypeManager.CSharpSignature (best_candidate));
7401 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7402 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7406 if (best_candidate.HasDifferentAccessibility) {
7407 CheckProtectedMemberAccess (rc, best_candidate.Get);
7410 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7414 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7421 /// Fully resolved expression that evaluates to an Event
7423 public class EventExpr : MemberExpr, IAssignMethod
7425 readonly EventSpec spec;
7428 public EventExpr (EventSpec spec, Location loc)
7436 protected override TypeSpec DeclaringType {
7438 return spec.DeclaringType;
7442 public override string Name {
7448 public override bool IsInstance {
7450 return !spec.IsStatic;
7454 public override bool IsStatic {
7456 return spec.IsStatic;
7460 public override string KindName {
7461 get { return "event"; }
7464 public MethodSpec Operator {
7472 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7475 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7477 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7478 if (spec.BackingField != null &&
7479 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7481 spec.MemberDefinition.SetIsUsed ();
7483 spec.CheckObsoleteness (ec, loc);
7485 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7486 Error_AssignmentEventOnly (ec);
7488 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7490 InstanceExpression = null;
7492 return ml.ResolveMemberAccess (ec, left, original);
7496 return base.ResolveMemberAccess (ec, left, original);
7499 public override Expression CreateExpressionTree (ResolveContext ec)
7501 throw new NotSupportedException ("ET");
7504 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7506 if (right_side == EmptyExpression.EventAddition) {
7507 op = spec.AccessorAdd;
7508 } else if (right_side == EmptyExpression.EventSubtraction) {
7509 op = spec.AccessorRemove;
7513 Error_AssignmentEventOnly (ec);
7517 if (HasConditionalAccess ())
7518 Error_NullPropagatingLValue (ec);
7520 op = CandidateToBaseOverride (ec, op);
7524 protected override Expression DoResolve (ResolveContext ec)
7526 eclass = ExprClass.EventAccess;
7527 type = spec.MemberType;
7529 ResolveInstanceExpression (ec, null);
7531 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7532 Error_AssignmentEventOnly (ec);
7535 DoBestMemberChecks (ec, spec);
7539 public override void Emit (EmitContext ec)
7541 throw new NotSupportedException ();
7542 //Error_CannotAssign ();
7545 #region IAssignMethod Members
7547 public void Emit (EmitContext ec, bool leave_copy)
7549 throw new NotImplementedException ();
7552 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7554 if (leave_copy || !isCompound)
7555 throw new NotImplementedException ("EventExpr::EmitAssign");
7557 Arguments args = new Arguments (1);
7558 args.Add (new Argument (source));
7560 // TODO: Wrong, needs receiver
7561 // if (NullShortCircuit) {
7562 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7565 var call = new CallEmitter ();
7566 call.InstanceExpression = InstanceExpression;
7567 call.ConditionalAccess = ConditionalAccess;
7568 call.EmitStatement (ec, op, args, loc);
7570 // if (NullShortCircuit)
7571 // ec.CloseConditionalAccess (null);
7576 void Error_AssignmentEventOnly (ResolveContext ec)
7578 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7579 ec.Report.Error (79, loc,
7580 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7581 GetSignatureForError ());
7583 ec.Report.Error (70, loc,
7584 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7585 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7589 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7591 name = name.Substring (0, name.LastIndexOf ('.'));
7592 base.Error_CannotCallAbstractBase (rc, name);
7595 public override string GetSignatureForError ()
7597 return TypeManager.CSharpSignature (spec);
7600 public override void ResolveNameOf (ResolveContext rc, ATypeNameExpression expr)
7602 spec.CheckObsoleteness (rc, expr.Location);
7605 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7607 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7611 public class TemporaryVariableReference : VariableReference
7613 public class Declarator : Statement
7615 TemporaryVariableReference variable;
7617 public Declarator (TemporaryVariableReference variable)
7619 this.variable = variable;
7623 protected override void DoEmit (EmitContext ec)
7625 variable.li.CreateBuilder (ec);
7628 public override void Emit (EmitContext ec)
7630 // Don't create sequence point
7634 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7639 protected override void CloneTo (CloneContext clonectx, Statement target)
7647 public TemporaryVariableReference (LocalVariable li, Location loc)
7650 this.type = li.Type;
7654 public override bool IsLockedByStatement {
7662 public LocalVariable LocalInfo {
7668 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7670 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7671 return new TemporaryVariableReference (li, loc);
7674 protected override Expression DoResolve (ResolveContext ec)
7676 eclass = ExprClass.Variable;
7679 // Don't capture temporary variables except when using
7680 // state machine redirection and block yields
7682 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7683 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7684 ec.IsVariableCapturingRequired) {
7685 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7686 storey.CaptureLocalVariable (ec, li);
7692 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7694 return Resolve (ec);
7697 public override void Emit (EmitContext ec)
7699 li.CreateBuilder (ec);
7704 public void EmitAssign (EmitContext ec, Expression source)
7706 li.CreateBuilder (ec);
7708 EmitAssign (ec, source, false, false);
7711 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7713 return li.HoistedVariant;
7716 public override bool IsFixed {
7717 get { return true; }
7720 public override bool IsRef {
7721 get { return false; }
7724 public override string Name {
7725 get { throw new NotImplementedException (); }
7728 public override void SetHasAddressTaken ()
7730 throw new NotImplementedException ();
7733 protected override ILocalVariable Variable {
7737 public override VariableInfo VariableInfo {
7738 get { return null; }
7743 /// Handles `var' contextual keyword; var becomes a keyword only
7744 /// if no type called var exists in a variable scope
7746 class VarExpr : SimpleName
7748 public VarExpr (Location loc)
7753 public bool InferType (ResolveContext ec, Expression right_side)
7756 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7758 type = right_side.Type;
7759 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7760 ec.Report.Error (815, loc,
7761 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7762 type.GetSignatureForError ());
7763 type = InternalType.ErrorType;
7767 eclass = ExprClass.Variable;
7771 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7773 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7774 base.Error_TypeOrNamespaceNotFound (ec);
7776 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");