2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
233 var rc = mc as ResolveContext ?? new ResolveContext (mc);
234 Expression e = Resolve (rc);
236 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 public static bool IsNeverNull (Expression expr)
435 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
438 var c = expr as Constant;
442 var tc = expr as TypeCast;
444 return IsNeverNull (tc.Child);
449 protected static bool IsNullPropagatingValid (TypeSpec type)
452 case MemberKind.Struct:
453 return type.IsNullableType;
454 case MemberKind.Enum:
455 case MemberKind.Void:
456 case MemberKind.PointerType:
458 case MemberKind.InternalCompilerType:
459 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
460 case MemberKind.TypeParameter:
461 return !((TypeParameterSpec) type).IsValueType;
467 public virtual bool HasConditionalAccess ()
472 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
474 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
475 Nullable.NullableInfo.MakeType (rc.Module, type) :
480 /// Resolves an expression and performs semantic analysis on it.
484 /// Currently Resolve wraps DoResolve to perform sanity
485 /// checking and assertion checking on what we expect from Resolve.
487 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
489 if (eclass != ExprClass.Unresolved) {
490 if ((flags & ExprClassToResolveFlags) == 0) {
491 Error_UnexpectedKind (ec, flags, loc);
505 if ((flags & e.ExprClassToResolveFlags) == 0) {
506 e.Error_UnexpectedKind (ec, flags, loc);
511 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
514 } catch (Exception ex) {
515 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
516 ec.Report.Printer is NullReportPrinter)
519 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
520 return ErrorExpression.Instance; // TODO: Add location
525 /// Resolves an expression and performs semantic analysis on it.
527 public Expression Resolve (ResolveContext rc)
529 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
533 /// Resolves an expression for LValue assignment
537 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
538 /// checking and assertion checking on what we expect from Resolve
540 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
542 int errors = ec.Report.Errors;
543 bool out_access = right_side == EmptyExpression.OutAccess;
545 Expression e = DoResolveLValue (ec, right_side);
547 if (e != null && out_access && !(e is IMemoryLocation)) {
548 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
549 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
551 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
552 // e.GetType () + " " + e.GetSignatureForError ());
557 if (errors == ec.Report.Errors) {
558 Error_ValueAssignment (ec, right_side);
563 if (e.eclass == ExprClass.Unresolved)
564 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
566 if ((e.type == null) && !(e is GenericTypeExpr))
567 throw new Exception ("Expression " + e + " did not set its type after Resolve");
572 public Constant ResolveLabelConstant (ResolveContext rc)
574 var expr = Resolve (rc);
578 Constant c = expr as Constant;
580 if (expr.type != InternalType.ErrorType)
581 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
589 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
591 if (Attribute.IsValidArgumentType (parameterType)) {
592 rc.Module.Compiler.Report.Error (182, loc,
593 "An attribute argument must be a constant expression, typeof expression or array creation expression");
595 rc.Module.Compiler.Report.Error (181, loc,
596 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
597 targetType.GetSignatureForError ());
602 /// Emits the code for the expression
606 /// The Emit method is invoked to generate the code
607 /// for the expression.
609 public abstract void Emit (EmitContext ec);
612 // Emit code to branch to @target if this expression is equivalent to @on_true.
613 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
614 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
615 // including the use of conditional branches. Note also that a branch MUST be emitted
616 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
619 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
622 // Emit this expression for its side effects, not for its value.
623 // The default implementation is to emit the value, and then throw it away.
624 // Subclasses can provide more efficient implementations, but those MUST be equivalent
625 public virtual void EmitSideEffect (EmitContext ec)
628 ec.Emit (OpCodes.Pop);
632 // Emits the expression into temporary field variable. The method
633 // should be used for await expressions only
635 public virtual Expression EmitToField (EmitContext ec)
638 // This is the await prepare Emit method. When emitting code like
639 // a + b we emit code like
645 // For await a + await b we have to interfere the flow to keep the
646 // stack clean because await yields from the expression. The emit
649 // a = a.EmitToField () // a is changed to temporary field access
650 // b = b.EmitToField ()
656 // The idea is to emit expression and leave the stack empty with
657 // result value still available.
659 // Expressions should override this default implementation when
660 // optimized version can be provided (e.g. FieldExpr)
663 // We can optimize for side-effect free expressions, they can be
664 // emitted out of order
666 if (IsSideEffectFree)
669 bool needs_temporary = ContainsEmitWithAwait ();
670 if (!needs_temporary)
673 // Emit original code
674 var field = EmitToFieldSource (ec);
677 // Store the result to temporary field when we
678 // cannot load `this' directly
680 field = ec.GetTemporaryField (type);
681 if (needs_temporary) {
683 // Create temporary local (we cannot load `this' before Emit)
685 var temp = ec.GetTemporaryLocal (type);
686 ec.Emit (OpCodes.Stloc, temp);
689 ec.Emit (OpCodes.Ldloc, temp);
690 field.EmitAssignFromStack (ec);
692 ec.FreeTemporaryLocal (temp, type);
694 field.EmitAssignFromStack (ec);
701 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
704 // Default implementation calls Emit method
710 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
712 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
713 bool contains_await = false;
715 for (int i = 1; i < expressions.Count; ++i) {
716 if (expressions[i].ContainsEmitWithAwait ()) {
717 contains_await = true;
722 if (contains_await) {
723 for (int i = 0; i < expressions.Count; ++i) {
724 expressions[i] = expressions[i].EmitToField (ec);
729 for (int i = 0; i < expressions.Count; ++i) {
730 expressions[i].Emit (ec);
735 /// Protected constructor. Only derivate types should
736 /// be able to be created
739 protected Expression ()
744 /// Returns a fully formed expression after a MemberLookup
747 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
749 if (spec is EventSpec)
750 return new EventExpr ((EventSpec) spec, loc);
751 if (spec is ConstSpec)
752 return new ConstantExpr ((ConstSpec) spec, loc);
753 if (spec is FieldSpec)
754 return new FieldExpr ((FieldSpec) spec, loc);
755 if (spec is PropertySpec)
756 return new PropertyExpr ((PropertySpec) spec, loc);
757 if (spec is TypeSpec)
758 return new TypeExpression (((TypeSpec) spec), loc);
763 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
765 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
768 case MemberKind.Struct:
769 // Every struct has implicit default constructor if not provided by user
773 rc.Report.SymbolRelatedToPreviousError (type);
774 // Report meaningful error for struct as they always have default ctor in C# context
775 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
777 case MemberKind.MissingType:
778 case MemberKind.InternalCompilerType:
779 // LAMESPEC: dynamic is not really object
780 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
784 rc.Report.SymbolRelatedToPreviousError (type);
785 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
786 type.GetSignatureForError ());
793 if (args == null && type.IsStruct) {
794 bool includes_empty = false;
795 foreach (MethodSpec ctor in ctors) {
796 if (ctor.Parameters.IsEmpty) {
797 includes_empty = true;
805 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
806 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
807 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
810 return r.ResolveMember<MethodSpec> (rc, ref args);
814 public enum MemberLookupRestrictions
820 EmptyArguments = 1 << 4,
821 IgnoreArity = 1 << 5,
822 IgnoreAmbiguity = 1 << 6,
823 NameOfExcluded = 1 << 7,
824 DontSetConditionalAccess = 1 << 8
828 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
829 // `qualifier_type' or null to lookup members in the current class.
831 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
833 var members = MemberCache.FindMembers (queried_type, name, false);
839 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
843 if (members [0].DeclaringType.BaseType == null)
846 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
847 } while (members != null);
852 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
854 MemberSpec non_method = null;
855 MemberSpec ambig_non_method = null;
857 for (int i = 0; i < members.Count; ++i) {
858 var member = members [i];
860 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
861 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
864 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
867 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
871 if (!member.IsAccessible (rc))
875 // With runtime binder we can have a situation where queried type is inaccessible
876 // because it came via dynamic object, the check about inconsisted accessibility
877 // had no effect as the type was unknown during compilation
880 // private class N { }
882 // public dynamic Foo ()
888 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
892 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
893 if (member is MethodSpec) {
895 // Interface members that are hidden by class members are removed from the set. This
896 // step only has an effect if T is a type parameter and T has both an effective base
897 // class other than object and a non-empty effective interface set
899 var tps = queried_type as TypeParameterSpec;
900 if (tps != null && tps.HasTypeConstraint)
901 members = RemoveHiddenTypeParameterMethods (members);
903 return new MethodGroupExpr (members, queried_type, loc);
906 if (!Invocation.IsMemberInvocable (member))
910 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
912 } else if (!errorMode && !member.IsNotCSharpCompatible) {
914 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
915 // T has both an effective base class other than object and a non-empty effective interface set.
917 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
919 var tps = queried_type as TypeParameterSpec;
920 if (tps != null && tps.HasTypeConstraint) {
921 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
924 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
930 ambig_non_method = member;
934 if (non_method != null) {
935 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
936 var report = rc.Module.Compiler.Report;
937 report.SymbolRelatedToPreviousError (non_method);
938 report.SymbolRelatedToPreviousError (ambig_non_method);
939 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
940 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
943 if (non_method is MethodSpec)
944 return new MethodGroupExpr (members, queried_type, loc);
946 return ExprClassFromMemberInfo (non_method, loc);
952 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
954 if (members.Count < 2)
958 // If M is a method, then all non-method members declared in an interface declaration
959 // are removed from the set, and all methods with the same signature as M declared in
960 // an interface declaration are removed from the set
964 for (int i = 0; i < members.Count; ++i) {
965 var method = members[i] as MethodSpec;
966 if (method == null) {
969 members = new List<MemberSpec> (members);
972 members.RemoveAt (i--);
976 if (!method.DeclaringType.IsInterface)
979 for (int ii = 0; ii < members.Count; ++ii) {
980 var candidate = members[ii] as MethodSpec;
981 if (candidate == null || !candidate.DeclaringType.IsClass)
984 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
987 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
992 members = new List<MemberSpec> (members);
995 members.RemoveAt (i--);
1003 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1005 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1008 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1010 throw new NotImplementedException ();
1013 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1015 if (t == InternalType.ErrorType)
1018 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1019 oper, t.GetSignatureForError ());
1022 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1024 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1027 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1029 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1032 protected void Error_NullPropagatingLValue (ResolveContext rc)
1034 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1037 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1042 // Special version of flow analysis for expressions which can return different
1043 // on-true and on-false result. Used by &&, ||, ?: expressions
1045 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1048 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1052 /// Returns an expression that can be used to invoke operator true
1053 /// on the expression if it exists.
1055 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1057 return GetOperatorTrueOrFalse (ec, e, true, loc);
1061 /// Returns an expression that can be used to invoke operator false
1062 /// on the expression if it exists.
1064 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1066 return GetOperatorTrueOrFalse (ec, e, false, loc);
1069 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1071 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1073 if (type.IsNullableType)
1074 type = Nullable.NullableInfo.GetUnderlyingType (type);
1076 var methods = MemberCache.GetUserOperator (type, op, false);
1077 if (methods == null)
1080 Arguments arguments = new Arguments (1);
1081 arguments.Add (new Argument (e));
1083 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1084 var oper = res.ResolveOperator (ec, ref arguments);
1089 return new UserOperatorCall (oper, arguments, null, loc);
1092 public virtual string ExprClassName
1096 case ExprClass.Unresolved:
1097 return "Unresolved";
1098 case ExprClass.Value:
1100 case ExprClass.Variable:
1102 case ExprClass.Namespace:
1104 case ExprClass.Type:
1106 case ExprClass.MethodGroup:
1107 return "method group";
1108 case ExprClass.PropertyAccess:
1109 return "property access";
1110 case ExprClass.EventAccess:
1111 return "event access";
1112 case ExprClass.IndexerAccess:
1113 return "indexer access";
1114 case ExprClass.Nothing:
1116 case ExprClass.TypeParameter:
1117 return "type parameter";
1119 throw new Exception ("Should not happen");
1124 /// Reports that we were expecting `expr' to be of class `expected'
1126 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1128 var name = memberExpr.GetSignatureForError ();
1130 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1133 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1135 string [] valid = new string [4];
1138 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1139 valid [count++] = "variable";
1140 valid [count++] = "value";
1143 if ((flags & ResolveFlags.Type) != 0)
1144 valid [count++] = "type";
1146 if ((flags & ResolveFlags.MethodGroup) != 0)
1147 valid [count++] = "method group";
1150 valid [count++] = "unknown";
1152 StringBuilder sb = new StringBuilder (valid [0]);
1153 for (int i = 1; i < count - 1; i++) {
1155 sb.Append (valid [i]);
1158 sb.Append ("' or `");
1159 sb.Append (valid [count - 1]);
1162 ec.Report.Error (119, loc,
1163 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1166 public static void UnsafeError (ResolveContext ec, Location loc)
1168 UnsafeError (ec.Report, loc);
1171 public static void UnsafeError (Report Report, Location loc)
1173 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1177 // Converts `source' to an int, uint, long or ulong.
1179 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1181 var btypes = ec.BuiltinTypes;
1183 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1184 Arguments args = new Arguments (1);
1185 args.Add (new Argument (source));
1186 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1189 Expression converted;
1191 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1192 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1193 if (converted == null)
1194 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1195 if (converted == null)
1196 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1197 if (converted == null)
1198 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1200 if (converted == null) {
1201 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1210 // Only positive constants are allowed at compile time
1212 Constant c = converted as Constant;
1213 if (c != null && c.IsNegative)
1214 Error_NegativeArrayIndex (ec, source.loc);
1216 // No conversion needed to array index
1217 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1220 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1223 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1225 if (args.Count != 1){
1226 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1231 if (arg is NamedArgument)
1232 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1234 var index = arg.Expr.Resolve (rc);
1238 index = ConvertExpressionToArrayIndex (rc, index, true);
1240 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1241 return new Indirection (p, loc);
1245 // Derived classes implement this method by cloning the fields that
1246 // could become altered during the Resolve stage
1248 // Only expressions that are created for the parser need to implement
1251 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1253 throw new NotImplementedException (
1255 "CloneTo not implemented for expression {0}", this.GetType ()));
1259 // Clones an expression created by the parser.
1261 // We only support expressions created by the parser so far, not
1262 // expressions that have been resolved (many more classes would need
1263 // to implement CloneTo).
1265 // This infrastructure is here merely for Lambda expressions which
1266 // compile the same code using different type values for the same
1267 // arguments to find the correct overload
1269 public virtual Expression Clone (CloneContext clonectx)
1271 Expression cloned = (Expression) MemberwiseClone ();
1272 CloneTo (clonectx, cloned);
1278 // Implementation of expression to expression tree conversion
1280 public abstract Expression CreateExpressionTree (ResolveContext ec);
1282 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1284 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1287 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1289 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1292 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1294 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1297 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1299 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1303 return new TypeExpression (t, loc);
1307 // Implemented by all expressions which support conversion from
1308 // compiler expression to invokable runtime expression. Used by
1309 // dynamic C# binder.
1311 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1313 throw new NotImplementedException ("MakeExpression for " + GetType ());
1316 public virtual object Accept (StructuralVisitor visitor)
1318 return visitor.Visit (this);
1323 /// This is just a base class for expressions that can
1324 /// appear on statements (invocations, object creation,
1325 /// assignments, post/pre increment and decrement). The idea
1326 /// being that they would support an extra Emition interface that
1327 /// does not leave a result on the stack.
1329 public abstract class ExpressionStatement : Expression
1331 public virtual void MarkReachable (Reachability rc)
1335 public ExpressionStatement ResolveStatement (BlockContext ec)
1337 Expression e = Resolve (ec);
1341 ExpressionStatement es = e as ExpressionStatement;
1342 if (es == null || e is AnonymousMethodBody) {
1343 var reduced = e as IReducedExpressionStatement;
1344 if (reduced != null) {
1345 return EmptyExpressionStatement.Instance;
1348 Error_InvalidExpressionStatement (ec);
1352 // This is quite expensive warning, try to limit the damage
1354 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1355 WarningAsyncWithoutWait (ec, e);
1361 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1363 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1364 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1369 // Need to do full resolve because GetAwaiter can be extension method
1370 // available only in this context
1372 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1376 var arguments = new Arguments (0);
1377 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1382 // Use same check rules as for real await
1384 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1385 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1388 bc.Report.Warning (4014, 1, e.Location,
1389 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1393 var inv = e as Invocation;
1394 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1395 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1396 bc.Report.Warning (4014, 1, e.Location,
1397 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1403 /// Requests the expression to be emitted in a `statement'
1404 /// context. This means that no new value is left on the
1405 /// stack after invoking this method (constrasted with
1406 /// Emit that will always leave a value on the stack).
1408 public abstract void EmitStatement (EmitContext ec);
1410 public override void EmitSideEffect (EmitContext ec)
1416 interface IReducedExpressionStatement
1421 /// This kind of cast is used to encapsulate the child
1422 /// whose type is child.Type into an expression that is
1423 /// reported to return "return_type". This is used to encapsulate
1424 /// expressions which have compatible types, but need to be dealt
1425 /// at higher levels with.
1427 /// For example, a "byte" expression could be encapsulated in one
1428 /// of these as an "unsigned int". The type for the expression
1429 /// would be "unsigned int".
1432 public abstract class TypeCast : Expression
1434 protected readonly Expression child;
1436 protected TypeCast (Expression child, TypeSpec return_type)
1438 eclass = child.eclass;
1439 loc = child.Location;
1444 public Expression Child {
1450 public override bool ContainsEmitWithAwait ()
1452 return child.ContainsEmitWithAwait ();
1455 public override Expression CreateExpressionTree (ResolveContext ec)
1457 Arguments args = new Arguments (2);
1458 args.Add (new Argument (child.CreateExpressionTree (ec)));
1459 args.Add (new Argument (new TypeOf (type, loc)));
1461 if (type.IsPointer || child.Type.IsPointer)
1462 Error_PointerInsideExpressionTree (ec);
1464 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1467 protected override Expression DoResolve (ResolveContext ec)
1469 // This should never be invoked, we are born in fully
1470 // initialized state.
1475 public override void Emit (EmitContext ec)
1480 public override void FlowAnalysis (FlowAnalysisContext fc)
1482 child.FlowAnalysis (fc);
1485 public override SLE.Expression MakeExpression (BuilderContext ctx)
1488 return base.MakeExpression (ctx);
1490 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1491 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1492 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1496 protected override void CloneTo (CloneContext clonectx, Expression t)
1501 public override bool IsNull {
1502 get { return child.IsNull; }
1506 public class EmptyCast : TypeCast {
1507 EmptyCast (Expression child, TypeSpec target_type)
1508 : base (child, target_type)
1512 public static Expression Create (Expression child, TypeSpec type)
1514 Constant c = child as Constant;
1516 var enum_constant = c as EnumConstant;
1517 if (enum_constant != null)
1518 c = enum_constant.Child;
1520 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1524 var res = c.ConvertImplicitly (type);
1530 EmptyCast e = child as EmptyCast;
1532 return new EmptyCast (e.child, type);
1534 return new EmptyCast (child, type);
1537 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1539 child.EmitBranchable (ec, label, on_true);
1542 public override void EmitSideEffect (EmitContext ec)
1544 child.EmitSideEffect (ec);
1549 // Used for predefined type user operator (no obsolete check, etc.)
1551 public class OperatorCast : TypeCast
1553 readonly MethodSpec conversion_operator;
1555 public OperatorCast (Expression expr, TypeSpec target_type)
1556 : this (expr, target_type, target_type, false)
1560 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1561 : this (expr, target_type, target_type, find_explicit)
1565 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1566 : base (expr, returnType)
1568 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1569 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1572 foreach (MethodSpec oper in mi) {
1573 if (oper.ReturnType != returnType)
1576 if (oper.Parameters.Types[0] == expr.Type) {
1577 conversion_operator = oper;
1583 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1584 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1587 public override void Emit (EmitContext ec)
1590 ec.Emit (OpCodes.Call, conversion_operator);
1595 // Constant specialization of EmptyCast.
1596 // We need to special case this since an empty cast of
1597 // a constant is still a constant.
1599 public class EmptyConstantCast : Constant
1601 public readonly Constant child;
1603 public EmptyConstantCast (Constant child, TypeSpec type)
1604 : base (child.Location)
1607 throw new ArgumentNullException ("child");
1610 this.eclass = child.eclass;
1614 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1616 if (child.Type == target_type)
1619 // FIXME: check that 'type' can be converted to 'target_type' first
1620 return child.ConvertExplicitly (in_checked_context, target_type);
1623 public override Expression CreateExpressionTree (ResolveContext ec)
1625 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1626 child.CreateExpressionTree (ec),
1627 new TypeOf (type, loc));
1630 Error_PointerInsideExpressionTree (ec);
1632 return CreateExpressionFactoryCall (ec, "Convert", args);
1635 public override bool IsDefaultValue {
1636 get { return child.IsDefaultValue; }
1639 public override bool IsNegative {
1640 get { return child.IsNegative; }
1643 public override bool IsNull {
1644 get { return child.IsNull; }
1647 public override bool IsOneInteger {
1648 get { return child.IsOneInteger; }
1651 public override bool IsSideEffectFree {
1653 return child.IsSideEffectFree;
1657 public override bool IsZeroInteger {
1658 get { return child.IsZeroInteger; }
1661 public override void Emit (EmitContext ec)
1666 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1668 child.EmitBranchable (ec, label, on_true);
1670 // Only to make verifier happy
1671 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1672 ec.Emit (OpCodes.Unbox_Any, type);
1675 public override void EmitSideEffect (EmitContext ec)
1677 child.EmitSideEffect (ec);
1680 public override object GetValue ()
1682 return child.GetValue ();
1685 public override string GetValueAsLiteral ()
1687 return child.GetValueAsLiteral ();
1690 public override long GetValueAsLong ()
1692 return child.GetValueAsLong ();
1695 public override Constant ConvertImplicitly (TypeSpec target_type)
1697 if (type == target_type)
1700 // FIXME: Do we need to check user conversions?
1701 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1704 return child.ConvertImplicitly (target_type);
1709 /// This class is used to wrap literals which belong inside Enums
1711 public class EnumConstant : Constant
1713 public Constant Child;
1715 public EnumConstant (Constant child, TypeSpec enum_type)
1716 : base (child.Location)
1720 this.eclass = ExprClass.Value;
1721 this.type = enum_type;
1724 protected EnumConstant (Location loc)
1729 public override void Emit (EmitContext ec)
1734 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1736 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1739 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1741 Child.EmitBranchable (ec, label, on_true);
1744 public override void EmitSideEffect (EmitContext ec)
1746 Child.EmitSideEffect (ec);
1749 public override string GetSignatureForError()
1751 return Type.GetSignatureForError ();
1754 public override object GetValue ()
1756 return Child.GetValue ();
1760 public override object GetTypedValue ()
1763 // The method can be used in dynamic context only (on closed types)
1765 // System.Enum.ToObject cannot be called on dynamic types
1766 // EnumBuilder has to be used, but we cannot use EnumBuilder
1767 // because it does not properly support generics
1769 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1773 public override string GetValueAsLiteral ()
1775 return Child.GetValueAsLiteral ();
1778 public override long GetValueAsLong ()
1780 return Child.GetValueAsLong ();
1783 public EnumConstant Increment()
1785 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1788 public override bool IsDefaultValue {
1790 return Child.IsDefaultValue;
1794 public override bool IsSideEffectFree {
1796 return Child.IsSideEffectFree;
1800 public override bool IsZeroInteger {
1801 get { return Child.IsZeroInteger; }
1804 public override bool IsNegative {
1806 return Child.IsNegative;
1810 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1812 if (Child.Type == target_type)
1815 return Child.ConvertExplicitly (in_checked_context, target_type);
1818 public override Constant ConvertImplicitly (TypeSpec type)
1820 if (this.type == type) {
1824 if (!Convert.ImplicitStandardConversionExists (this, type)){
1828 return Child.ConvertImplicitly (type);
1833 /// This kind of cast is used to encapsulate Value Types in objects.
1835 /// The effect of it is to box the value type emitted by the previous
1838 public class BoxedCast : TypeCast {
1840 public BoxedCast (Expression expr, TypeSpec target_type)
1841 : base (expr, target_type)
1843 eclass = ExprClass.Value;
1846 protected override Expression DoResolve (ResolveContext ec)
1848 // This should never be invoked, we are born in fully
1849 // initialized state.
1854 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1856 // Only boxing to object type is supported
1857 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1858 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1862 enc.Encode (child.Type);
1863 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1866 public override void Emit (EmitContext ec)
1870 ec.Emit (OpCodes.Box, child.Type);
1873 public override void EmitSideEffect (EmitContext ec)
1875 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1876 // so, we need to emit the box+pop instructions in most cases
1877 if (child.Type.IsStruct &&
1878 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1879 child.EmitSideEffect (ec);
1881 base.EmitSideEffect (ec);
1885 public class UnboxCast : TypeCast {
1886 public UnboxCast (Expression expr, TypeSpec return_type)
1887 : base (expr, return_type)
1891 protected override Expression DoResolve (ResolveContext ec)
1893 // This should never be invoked, we are born in fully
1894 // initialized state.
1899 public override void Emit (EmitContext ec)
1903 ec.Emit (OpCodes.Unbox_Any, type);
1908 /// This is used to perform explicit numeric conversions.
1910 /// Explicit numeric conversions might trigger exceptions in a checked
1911 /// context, so they should generate the conv.ovf opcodes instead of
1914 public class ConvCast : TypeCast {
1915 public enum Mode : byte {
1916 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1918 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1919 U2_I1, U2_U1, U2_I2, U2_CH,
1920 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1921 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1922 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1923 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1924 CH_I1, CH_U1, CH_I2,
1925 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1926 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1932 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1933 : base (child, return_type)
1938 protected override Expression DoResolve (ResolveContext ec)
1940 // This should never be invoked, we are born in fully
1941 // initialized state.
1946 public override string ToString ()
1948 return String.Format ("ConvCast ({0}, {1})", mode, child);
1951 public override void Emit (EmitContext ec)
1957 public static void Emit (EmitContext ec, Mode mode)
1959 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1961 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1962 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U1_CH: /* nothing */ break;
1970 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1971 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1972 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1974 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1975 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1977 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1978 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1979 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.U2_CH: /* nothing */ break;
1982 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1983 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1984 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1985 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1991 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1992 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1993 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1994 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1995 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1997 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1998 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1999 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2000 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2001 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2002 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2003 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2004 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
2007 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2008 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2009 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2010 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2011 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2012 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2013 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2014 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2015 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2017 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2018 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2019 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2021 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2022 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2023 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2024 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2025 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2026 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2027 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2028 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2029 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2031 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2032 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2033 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2034 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2035 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2036 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2037 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2038 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2039 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2040 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2042 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2046 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2047 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2049 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2050 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2053 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2055 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2056 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2057 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2059 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2060 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2062 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2063 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2064 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2065 case Mode.U2_CH: /* nothing */ break;
2067 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2068 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2069 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2070 case Mode.I4_U4: /* nothing */ break;
2071 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2073 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2076 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2077 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2078 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2079 case Mode.U4_I4: /* nothing */ break;
2080 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2083 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2084 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2085 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2086 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2087 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2088 case Mode.I8_U8: /* nothing */ break;
2089 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2090 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2092 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.U8_I8: /* nothing */ break;
2099 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2100 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2102 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2106 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2107 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2108 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2109 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2110 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2111 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2112 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2113 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2114 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2116 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2117 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2118 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2119 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2120 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2121 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2122 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2123 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2124 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2125 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2127 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2133 class OpcodeCast : TypeCast
2137 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2138 : base (child, return_type)
2143 protected override Expression DoResolve (ResolveContext ec)
2145 // This should never be invoked, we are born in fully
2146 // initialized state.
2151 public override void Emit (EmitContext ec)
2157 public TypeSpec UnderlyingType {
2158 get { return child.Type; }
2163 // Opcode casts expression with 2 opcodes but only
2164 // single expression tree node
2166 class OpcodeCastDuplex : OpcodeCast
2168 readonly OpCode second;
2170 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2171 : base (child, returnType, first)
2173 this.second = second;
2176 public override void Emit (EmitContext ec)
2184 /// This kind of cast is used to encapsulate a child and cast it
2185 /// to the class requested
2187 public sealed class ClassCast : TypeCast {
2188 readonly bool forced;
2190 public ClassCast (Expression child, TypeSpec return_type)
2191 : base (child, return_type)
2195 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2196 : base (child, return_type)
2198 this.forced = forced;
2201 public override void Emit (EmitContext ec)
2205 bool gen = TypeManager.IsGenericParameter (child.Type);
2207 ec.Emit (OpCodes.Box, child.Type);
2209 if (type.IsGenericParameter) {
2210 ec.Emit (OpCodes.Unbox_Any, type);
2217 ec.Emit (OpCodes.Castclass, type);
2222 // Created during resolving pahse when an expression is wrapped or constantified
2223 // and original expression can be used later (e.g. for expression trees)
2225 public class ReducedExpression : Expression
2227 public class ReducedConstantExpression : EmptyConstantCast
2229 readonly Expression orig_expr;
2231 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2232 : base (expr, expr.Type)
2234 this.orig_expr = orig_expr;
2237 public Expression OriginalExpression {
2243 public override Constant ConvertImplicitly (TypeSpec target_type)
2245 Constant c = base.ConvertImplicitly (target_type);
2247 c = new ReducedConstantExpression (c, orig_expr);
2252 public override Expression CreateExpressionTree (ResolveContext ec)
2254 return orig_expr.CreateExpressionTree (ec);
2257 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2259 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2261 c = new ReducedConstantExpression (c, orig_expr);
2265 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2268 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2270 if (orig_expr is Conditional)
2271 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2273 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2277 sealed class ReducedConstantStatement : ReducedConstantExpression, IReducedExpressionStatement
2279 public ReducedConstantStatement (Constant expr, Expression origExpr)
2280 : base (expr, origExpr)
2285 sealed class ReducedExpressionStatement : ExpressionStatement
2287 readonly Expression orig_expr;
2288 readonly ExpressionStatement stm;
2290 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2292 this.orig_expr = orig;
2294 this.eclass = stm.eclass;
2295 this.type = stm.Type;
2297 this.loc = orig.Location;
2300 public override bool ContainsEmitWithAwait ()
2302 return stm.ContainsEmitWithAwait ();
2305 public override Expression CreateExpressionTree (ResolveContext ec)
2307 return orig_expr.CreateExpressionTree (ec);
2310 protected override Expression DoResolve (ResolveContext ec)
2315 public override void Emit (EmitContext ec)
2320 public override void EmitStatement (EmitContext ec)
2322 stm.EmitStatement (ec);
2325 public override void FlowAnalysis (FlowAnalysisContext fc)
2327 stm.FlowAnalysis (fc);
2331 readonly Expression expr, orig_expr;
2333 private ReducedExpression (Expression expr, Expression orig_expr)
2336 this.eclass = expr.eclass;
2337 this.type = expr.Type;
2338 this.orig_expr = orig_expr;
2339 this.loc = orig_expr.Location;
2344 public override bool IsSideEffectFree {
2346 return expr.IsSideEffectFree;
2350 public Expression OriginalExpression {
2358 public override bool ContainsEmitWithAwait ()
2360 return expr.ContainsEmitWithAwait ();
2364 // Creates fully resolved expression switcher
2366 public static Constant Create (Constant expr, Expression originalExpr)
2368 if (expr.eclass == ExprClass.Unresolved)
2369 throw new ArgumentException ("Unresolved expression");
2371 if (originalExpr is ExpressionStatement)
2372 return new ReducedConstantStatement (expr, originalExpr);
2374 return new ReducedConstantExpression (expr, originalExpr);
2377 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2379 return new ReducedExpressionStatement (s, orig);
2382 public static Expression Create (Expression expr, Expression original_expr)
2384 return Create (expr, original_expr, true);
2388 // Creates unresolved reduce expression. The original expression has to be
2389 // already resolved. Created expression is constant based based on `expr'
2390 // value unless canBeConstant is used
2392 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2394 if (canBeConstant) {
2395 Constant c = expr as Constant;
2397 return Create (c, original_expr);
2400 ExpressionStatement s = expr as ExpressionStatement;
2402 return Create (s, original_expr);
2404 if (expr.eclass == ExprClass.Unresolved)
2405 throw new ArgumentException ("Unresolved expression");
2407 return new ReducedExpression (expr, original_expr);
2410 public override Expression CreateExpressionTree (ResolveContext ec)
2412 return orig_expr.CreateExpressionTree (ec);
2415 protected override Expression DoResolve (ResolveContext ec)
2420 public override void Emit (EmitContext ec)
2425 public override Expression EmitToField (EmitContext ec)
2427 return expr.EmitToField(ec);
2430 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2432 expr.EmitBranchable (ec, target, on_true);
2435 public override void FlowAnalysis (FlowAnalysisContext fc)
2437 expr.FlowAnalysis (fc);
2440 public override SLE.Expression MakeExpression (BuilderContext ctx)
2442 return orig_expr.MakeExpression (ctx);
2447 // Standard composite pattern
2449 public abstract class CompositeExpression : Expression
2451 protected Expression expr;
2453 protected CompositeExpression (Expression expr)
2456 this.loc = expr.Location;
2459 public override bool ContainsEmitWithAwait ()
2461 return expr.ContainsEmitWithAwait ();
2464 public override Expression CreateExpressionTree (ResolveContext rc)
2466 return expr.CreateExpressionTree (rc);
2469 public Expression Child {
2470 get { return expr; }
2473 protected override Expression DoResolve (ResolveContext rc)
2475 expr = expr.Resolve (rc);
2480 eclass = expr.eclass;
2484 public override void Emit (EmitContext ec)
2489 public override bool IsNull {
2490 get { return expr.IsNull; }
2495 // Base of expressions used only to narrow resolve flow
2497 public abstract class ShimExpression : Expression
2499 protected Expression expr;
2501 protected ShimExpression (Expression expr)
2506 public Expression Expr {
2512 protected override void CloneTo (CloneContext clonectx, Expression t)
2517 ShimExpression target = (ShimExpression) t;
2518 target.expr = expr.Clone (clonectx);
2521 public override bool ContainsEmitWithAwait ()
2523 return expr.ContainsEmitWithAwait ();
2526 public override Expression CreateExpressionTree (ResolveContext ec)
2528 throw new NotSupportedException ("ET");
2531 public override void Emit (EmitContext ec)
2533 throw new InternalErrorException ("Missing Resolve call");
2537 public class UnreachableExpression : Expression
2539 public UnreachableExpression (Expression expr)
2541 this.loc = expr.Location;
2544 public override Expression CreateExpressionTree (ResolveContext ec)
2547 throw new NotImplementedException ();
2550 protected override Expression DoResolve (ResolveContext rc)
2552 throw new NotSupportedException ();
2555 public override void FlowAnalysis (FlowAnalysisContext fc)
2557 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2560 public override void Emit (EmitContext ec)
2564 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2570 // Unresolved type name expressions
2572 public abstract class ATypeNameExpression : FullNamedExpression
2575 protected TypeArguments targs;
2577 protected ATypeNameExpression (string name, Location l)
2583 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2590 protected ATypeNameExpression (string name, int arity, Location l)
2591 : this (name, new UnboundTypeArguments (arity, l), l)
2599 return targs == null ? 0 : targs.Count;
2603 public bool HasTypeArguments {
2605 return targs != null && !targs.IsEmpty;
2609 public string Name {
2618 public TypeArguments TypeArguments {
2626 public override bool Equals (object obj)
2628 ATypeNameExpression atne = obj as ATypeNameExpression;
2629 return atne != null && atne.Name == Name &&
2630 (targs == null || targs.Equals (atne.targs));
2633 public override int GetHashCode ()
2635 return Name.GetHashCode ();
2638 // TODO: Move it to MemberCore
2639 public static string GetMemberType (MemberCore mc)
2645 if (mc is FieldBase)
2647 if (mc is MethodCore)
2649 if (mc is EnumMember)
2657 public override string GetSignatureForError ()
2659 if (targs != null) {
2660 return Name + "<" + targs.GetSignatureForError () + ">";
2666 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2670 /// SimpleName expressions are formed of a single word and only happen at the beginning
2671 /// of a dotted-name.
2673 public class SimpleName : ATypeNameExpression
2675 public SimpleName (string name, Location l)
2680 public SimpleName (string name, TypeArguments args, Location l)
2681 : base (name, args, l)
2685 public SimpleName (string name, int arity, Location l)
2686 : base (name, arity, l)
2690 public SimpleName GetMethodGroup ()
2692 return new SimpleName (Name, targs, loc);
2695 protected override Expression DoResolve (ResolveContext rc)
2697 return SimpleNameResolve (rc, null);
2700 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2702 return SimpleNameResolve (ec, right_side);
2705 public void Error_NameDoesNotExist (ResolveContext rc)
2707 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2710 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2712 if (ctx.CurrentType != null) {
2713 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2714 if (member != null) {
2715 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2720 var report = ctx.Module.Compiler.Report;
2722 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2723 if (retval != null) {
2724 report.SymbolRelatedToPreviousError (retval.Type);
2725 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2729 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2730 if (retval != null) {
2731 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2735 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2736 if (ns_candidates != null) {
2737 if (ctx is UsingAliasNamespace.AliasContext) {
2738 report.Error (246, loc,
2739 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2740 ns_candidates[0], Name);
2742 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2743 report.Error (246, loc,
2744 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2748 report.Error (246, loc,
2749 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2754 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2756 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2759 if (fne.Type != null && Arity > 0) {
2760 if (HasTypeArguments) {
2761 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2762 if (ct.ResolveAsType (mc) == null)
2768 targs.Resolve (mc, allowUnboundTypeArguments);
2770 return new GenericOpenTypeExpr (fne.Type, loc);
2774 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2776 if (!(fne is NamespaceExpression))
2780 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2781 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2782 mc.Module.Compiler.Report.Error (1980, Location,
2783 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2784 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2787 fne = new DynamicTypeExpr (loc);
2788 fne.ResolveAsType (mc);
2794 Error_TypeOrNamespaceNotFound (mc);
2798 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2800 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2803 public bool IsPossibleType (IMemberContext mc)
2805 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2808 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2810 int lookup_arity = Arity;
2811 bool errorMode = false;
2813 Block current_block = rc.CurrentBlock;
2814 INamedBlockVariable variable = null;
2815 bool variable_found = false;
2819 // Stage 1: binding to local variables or parameters
2821 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2823 if (current_block != null && lookup_arity == 0) {
2824 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2825 if (!variable.IsDeclared) {
2826 // We found local name in accessible block but it's not
2827 // initialized yet, maybe the user wanted to bind to something else
2829 variable_found = true;
2831 e = variable.CreateReferenceExpression (rc, loc);
2834 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2843 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2845 TypeSpec member_type = rc.CurrentType;
2846 for (; member_type != null; member_type = member_type.DeclaringType) {
2847 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2851 var me = e as MemberExpr;
2853 // The name matches a type, defer to ResolveAsTypeStep
2861 if (variable != null) {
2862 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2863 rc.Report.Error (844, loc,
2864 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2865 Name, me.GetSignatureForError ());
2869 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2870 // Leave it to overload resolution to report correct error
2872 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2873 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2877 // MemberLookup does not check accessors availability, this is actually needed for properties only
2879 var pe = me as PropertyExpr;
2882 // Break as there is no other overload available anyway
2883 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2884 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2887 pe.Getter = pe.PropertyInfo.Get;
2889 if (!pe.PropertyInfo.HasSet) {
2890 if (rc.HasSet (ResolveContext.Options.ConstructorScope) && pe.IsAutoPropertyAccess &&
2891 pe.PropertyInfo.DeclaringType == rc.CurrentType && pe.IsStatic == rc.IsStatic) {
2892 var p = (Property) pe.PropertyInfo.MemberDefinition;
2893 return new FieldExpr (p.BackingField, loc);
2896 variable_found = true;
2900 if (!pe.PropertyInfo.Set.IsAccessible (rc)) {
2901 variable_found = true;
2905 pe.Setter = pe.PropertyInfo.Set;
2910 // TODO: It's used by EventExpr -> FieldExpr transformation only
2911 // TODO: Should go to MemberAccess
2912 me = me.ResolveMemberAccess (rc, null, null);
2915 targs.Resolve (rc, false);
2916 me.SetTypeArguments (rc, targs);
2923 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2925 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2926 if (IsPossibleTypeOrNamespace (rc)) {
2927 return ResolveAsTypeOrNamespace (rc, false);
2931 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2934 targs.Resolve (rc, false);
2936 var me = expr as MemberExpr;
2938 me.SetTypeArguments (rc, targs);
2943 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2944 return new NameOf (this);
2947 if (variable_found) {
2948 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2951 var tparams = rc.CurrentTypeParameters;
2952 if (tparams != null) {
2953 if (tparams.Find (Name) != null) {
2954 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2959 var ct = rc.CurrentType;
2961 if (ct.MemberDefinition.TypeParametersCount > 0) {
2962 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2963 if (ctp.Name == Name) {
2964 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2970 ct = ct.DeclaringType;
2971 } while (ct != null);
2974 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2975 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2977 rc.Report.SymbolRelatedToPreviousError (e.Type);
2978 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2982 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2984 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2985 return ErrorExpression.Instance;
2989 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2991 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2992 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2996 if (e is TypeExpr) {
2997 // TypeExpression does not have correct location
2998 if (e is TypeExpression)
2999 e = new TypeExpression (e.Type, loc);
3005 Error_NameDoesNotExist (rc);
3008 return ErrorExpression.Instance;
3011 if (rc.Module.Evaluator != null) {
3012 var fi = rc.Module.Evaluator.LookupField (Name);
3014 return new FieldExpr (fi.Item1, loc);
3022 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
3024 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
3029 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
3030 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
3034 if (right_side != null) {
3035 e = e.ResolveLValue (ec, right_side);
3043 public override object Accept (StructuralVisitor visitor)
3045 return visitor.Visit (this);
3050 /// Represents a namespace or a type. The name of the class was inspired by
3051 /// section 10.8.1 (Fully Qualified Names).
3053 public abstract class FullNamedExpression : Expression
3055 protected override void CloneTo (CloneContext clonectx, Expression target)
3057 // Do nothing, most unresolved type expressions cannot be
3058 // resolved to different type
3061 public override bool ContainsEmitWithAwait ()
3066 public override Expression CreateExpressionTree (ResolveContext ec)
3068 throw new NotSupportedException ("ET");
3071 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3074 // This is used to resolve the expression as a type, a null
3075 // value will be returned if the expression is not a type
3078 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3080 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3085 TypeExpr te = fne as TypeExpr;
3087 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3095 var dep = type.GetMissingDependencies ();
3097 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3100 if (type.Kind == MemberKind.Void) {
3101 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3105 // Obsolete checks cannot be done when resolving base context as they
3106 // require type dependencies to be set but we are in process of resolving them
3108 if (mc is ResolveContext) {
3109 var oa = type.GetAttributeObsolete ();
3110 if (oa != null && !mc.IsObsolete)
3111 AttributeTester.Report_ObsoleteMessage (oa, type.GetSignatureForError (), fne.Location, mc.Module.Compiler.Report);
3118 public override void Emit (EmitContext ec)
3120 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3121 GetSignatureForError ());
3126 /// Expression that evaluates to a type
3128 public abstract class TypeExpr : FullNamedExpression
3130 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3136 protected sealed override Expression DoResolve (ResolveContext ec)
3142 public override bool Equals (object obj)
3144 TypeExpr tobj = obj as TypeExpr;
3148 return Type == tobj.Type;
3151 public override int GetHashCode ()
3153 return Type.GetHashCode ();
3158 /// Fully resolved Expression that already evaluated to a type
3160 public class TypeExpression : TypeExpr
3162 public TypeExpression (TypeSpec t, Location l)
3165 eclass = ExprClass.Type;
3169 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3175 public class NamespaceExpression : FullNamedExpression
3177 readonly Namespace ns;
3179 public NamespaceExpression (Namespace ns, Location loc)
3182 this.Type = InternalType.Namespace;
3183 this.eclass = ExprClass.Namespace;
3187 public Namespace Namespace {
3193 protected override Expression DoResolve (ResolveContext rc)
3195 throw new NotImplementedException ();
3198 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3203 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3205 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3206 if (retval != null) {
3207 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3208 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3212 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3213 if (retval != null) {
3214 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3219 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3220 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3224 string assembly = null;
3225 string possible_name = Namespace.GetSignatureForError () + "." + name;
3227 // Only assembly unique name should be added
3228 switch (possible_name) {
3229 case "System.Drawing":
3230 case "System.Web.Services":
3233 case "System.Configuration":
3234 case "System.Data.Services":
3235 case "System.DirectoryServices":
3237 case "System.Net.Http":
3238 case "System.Numerics":
3239 case "System.Runtime.Caching":
3240 case "System.ServiceModel":
3241 case "System.Transactions":
3242 case "System.Web.Routing":
3243 case "System.Xml.Linq":
3245 assembly = possible_name;
3249 case "System.Linq.Expressions":
3250 assembly = "System.Core";
3253 case "System.Windows.Forms":
3254 case "System.Windows.Forms.Layout":
3255 assembly = "System.Windows.Forms";
3259 assembly = assembly == null ? "an" : "`" + assembly + "'";
3261 if (Namespace is GlobalRootNamespace) {
3262 ctx.Module.Compiler.Report.Error (400, loc,
3263 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3266 ctx.Module.Compiler.Report.Error (234, loc,
3267 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3268 name, GetSignatureForError (), assembly);
3272 public override string GetSignatureForError ()
3274 return ns.GetSignatureForError ();
3277 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3279 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3282 public override string ToString ()
3284 return Namespace.Name;
3289 /// This class denotes an expression which evaluates to a member
3290 /// of a struct or a class.
3292 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3294 protected bool conditional_access_receiver;
3297 // An instance expression associated with this member, if it's a
3298 // non-static member
3300 public Expression InstanceExpression;
3303 /// The name of this member.
3305 public abstract string Name {
3310 // When base.member is used
3312 public bool IsBase {
3313 get { return InstanceExpression is BaseThis; }
3317 /// Whether this is an instance member.
3319 public abstract bool IsInstance {
3324 /// Whether this is a static member.
3326 public abstract bool IsStatic {
3330 public abstract string KindName {
3334 public bool ConditionalAccess { get; set; }
3336 protected abstract TypeSpec DeclaringType {
3340 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3342 return InstanceExpression.Type;
3347 // Converts best base candidate for virtual method starting from QueriedBaseType
3349 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3352 // Only when base.member is used and method is virtual
3358 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3359 // means for base.member access we have to find the closest match after we found best candidate
3361 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3363 // The method could already be what we are looking for
3365 TypeSpec[] targs = null;
3366 if (method.DeclaringType != InstanceExpression.Type) {
3368 // Candidate can have inflated MVAR parameters and we need to find
3369 // base match for original definition not inflated parameter types
3371 var parameters = method.Parameters;
3372 if (method.Arity > 0) {
3373 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3374 var inflated = method.DeclaringType as InflatedTypeSpec;
3375 if (inflated != null) {
3376 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3380 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3381 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3382 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3383 if (base_override.IsGeneric)
3384 targs = method.TypeArguments;
3386 method = base_override;
3391 // When base access is used inside anonymous method/iterator/etc we need to
3392 // get back to the context of original type. We do it by emiting proxy
3393 // method in original class and rewriting base call to this compiler
3394 // generated method call which does the actual base invocation. This may
3395 // introduce redundant storey but with `this' only but it's tricky to avoid
3396 // at this stage as we don't know what expressions follow base
3398 if (rc.CurrentAnonymousMethod != null) {
3399 if (targs == null && method.IsGeneric) {
3400 targs = method.TypeArguments;
3401 method = method.GetGenericMethodDefinition ();
3404 if (method.Parameters.HasArglist)
3405 throw new NotImplementedException ("__arglist base call proxy");
3407 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3409 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3410 // get/set member expressions second call would fail to proxy because left expression
3411 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3412 // FIXME: The async check is another hack but will probably fail with mutators
3413 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3414 InstanceExpression = new This (loc).Resolve (rc);
3418 method = method.MakeGenericMethod (rc, targs);
3422 // Only base will allow this invocation to happen.
3424 if (method.IsAbstract) {
3425 rc.Report.SymbolRelatedToPreviousError (method);
3426 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3432 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3434 if (InstanceExpression == null)
3437 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3438 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3439 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3444 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3446 if (InstanceExpression == null)
3449 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3452 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3454 var ct = rc.CurrentType;
3455 if (ct == qualifier)
3458 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3461 qualifier = qualifier.GetDefinition ();
3462 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3469 public override bool ContainsEmitWithAwait ()
3471 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3474 public override bool HasConditionalAccess ()
3476 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3479 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3482 type = type.GetDefinition ();
3484 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3487 type = type.DeclaringType;
3488 } while (type != null);
3493 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3495 if (InstanceExpression != null) {
3496 InstanceExpression = InstanceExpression.Resolve (rc);
3497 CheckProtectedMemberAccess (rc, member);
3500 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3501 UnsafeError (rc, loc);
3504 var dep = member.GetMissingDependencies ();
3506 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3509 member.CheckObsoleteness (rc, loc);
3511 if (!(member is FieldSpec))
3512 member.MemberDefinition.SetIsUsed ();
3515 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3517 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3520 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3522 rc.Report.SymbolRelatedToPreviousError (member);
3523 rc.Report.Error (1540, loc,
3524 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3525 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3528 public override void FlowAnalysis (FlowAnalysisContext fc)
3530 if (InstanceExpression != null) {
3531 InstanceExpression.FlowAnalysis (fc);
3535 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3537 if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && HasConditionalAccess ()) {
3538 conditional_access_receiver = true;
3542 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3544 if (!ResolveInstanceExpressionCore (rc, rhs))
3548 // Check intermediate value modification which won't have any effect
3550 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3551 var fexpr = InstanceExpression as FieldExpr;
3552 if (fexpr != null) {
3553 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3556 if (fexpr.IsStatic) {
3557 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3558 fexpr.GetSignatureForError ());
3560 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3561 fexpr.GetSignatureForError ());
3567 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3568 if (rc.CurrentInitializerVariable != null) {
3569 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3570 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3572 rc.Report.Error (1612, loc,
3573 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3574 InstanceExpression.GetSignatureForError ());
3580 var lvr = InstanceExpression as LocalVariableReference;
3583 if (!lvr.local_info.IsReadonly)
3586 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3587 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3594 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3597 if (InstanceExpression != null) {
3598 if (InstanceExpression is TypeExpr) {
3599 var t = InstanceExpression.Type;
3601 t.CheckObsoleteness (rc, loc);
3603 t = t.DeclaringType;
3604 } while (t != null);
3606 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3607 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3608 rc.Report.Error (176, loc,
3609 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3610 GetSignatureForError ());
3614 InstanceExpression = null;
3620 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3621 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3622 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3623 rc.Report.Error (236, loc,
3624 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3625 GetSignatureForError ());
3627 var fe = this as FieldExpr;
3628 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3629 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3630 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3632 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3636 rc.Report.Error (120, loc,
3637 "An object reference is required to access non-static member `{0}'",
3638 GetSignatureForError ());
3642 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3646 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3647 rc.Report.Error (38, loc,
3648 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3649 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3652 InstanceExpression = new This (loc).Resolve (rc);
3656 var me = InstanceExpression as MemberExpr;
3658 me.ResolveInstanceExpressionCore (rc, rhs);
3660 var fe = me as FieldExpr;
3661 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3662 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3663 rc.Report.Warning (1690, 1, loc,
3664 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3665 me.GetSignatureForError ());
3672 // Additional checks for l-value member access
3675 if (InstanceExpression is UnboxCast) {
3676 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3683 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3685 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3686 ec.Report.Warning (1720, 1, left.Location,
3687 "Expression will always cause a `{0}'", "System.NullReferenceException");
3690 InstanceExpression = left;
3694 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3696 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3697 inst.Emit (ec, ConditionalAccess);
3699 if (prepare_for_load)
3700 ec.Emit (OpCodes.Dup);
3703 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3706 public class ExtensionMethodCandidates
3708 readonly NamespaceContainer container;
3709 readonly IList<MethodSpec> methods;
3711 readonly IMemberContext context;
3713 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3715 this.context = context;
3716 this.methods = methods;
3717 this.container = nsContainer;
3718 this.index = lookupIndex;
3721 public NamespaceContainer Container {
3727 public IMemberContext Context {
3733 public int LookupIndex {
3739 public IList<MethodSpec> Methods {
3747 // Represents a group of extension method candidates for whole namespace
3749 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3751 ExtensionMethodCandidates candidates;
3752 public Expression ExtensionExpression;
3754 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3755 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3757 this.candidates = candidates;
3758 this.ExtensionExpression = extensionExpr;
3761 public override bool IsStatic {
3762 get { return true; }
3766 // For extension methodgroup we are not looking for base members but parent
3767 // namespace extension methods
3769 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3771 // TODO: candidates are null only when doing error reporting, that's
3772 // incorrect. We have to discover same extension methods in error mode
3773 if (candidates == null)
3776 int arity = type_arguments == null ? 0 : type_arguments.Count;
3778 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3779 if (candidates == null)
3782 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3785 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3788 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3790 // LAMESPEC: or implicit type parameter conversion
3792 return argType == extensionType ||
3793 TypeSpecComparer.IsEqual (argType, extensionType) ||
3794 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3795 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3798 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3800 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3802 // Not included in C#6
3804 ExtensionExpression = ExtensionExpression.Resolve (rc);
3805 if (ExtensionExpression == null)
3808 var argType = ExtensionExpression.Type;
3809 foreach (MethodSpec candidate in Candidates) {
3810 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3814 // TODO: Scan full hierarchy
3816 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3821 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3823 // We are already here
3827 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3829 if (arguments == null)
3830 arguments = new Arguments (1);
3832 ExtensionExpression = ExtensionExpression.Resolve (ec);
3833 if (ExtensionExpression == null)
3836 var cand = candidates;
3837 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3838 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3839 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3841 // Restore candidates in case we are running in probing mode
3844 // Store resolved argument and restore original arguments
3846 // Clean-up modified arguments for error reporting
3847 arguments.RemoveAt (0);
3851 var me = ExtensionExpression as MemberExpr;
3853 me.ResolveInstanceExpression (ec, null);
3854 var fe = me as FieldExpr;
3856 fe.Spec.MemberDefinition.SetIsUsed ();
3859 InstanceExpression = null;
3863 #region IErrorHandler Members
3865 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3870 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3872 rc.Report.SymbolRelatedToPreviousError (best);
3875 rc.Report.Error (1929, loc,
3876 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3877 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3879 rc.Report.Error (1928, loc,
3880 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3881 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3887 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3892 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3901 /// MethodGroupExpr represents a group of method candidates which
3902 /// can be resolved to the best method overload
3904 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3906 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3908 protected IList<MemberSpec> Methods;
3909 MethodSpec best_candidate;
3910 TypeSpec best_candidate_return;
3911 protected TypeArguments type_arguments;
3913 SimpleName simple_name;
3914 protected TypeSpec queried_type;
3916 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3920 this.type = InternalType.MethodGroup;
3922 eclass = ExprClass.MethodGroup;
3923 queried_type = type;
3926 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3927 : this (new MemberSpec[] { m }, type, loc)
3933 public MethodSpec BestCandidate {
3935 return best_candidate;
3939 public TypeSpec BestCandidateReturnType {
3941 return best_candidate_return;
3945 public IList<MemberSpec> Candidates {
3951 protected override TypeSpec DeclaringType {
3953 return queried_type;
3957 public bool IsConditionallyExcluded {
3959 return Methods == Excluded;
3963 public override bool IsInstance {
3965 if (best_candidate != null)
3966 return !best_candidate.IsStatic;
3972 public override bool IsSideEffectFree {
3974 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3978 public override bool IsStatic {
3980 if (best_candidate != null)
3981 return best_candidate.IsStatic;
3987 public override string KindName {
3988 get { return "method"; }
3991 public override string Name {
3993 if (best_candidate != null)
3994 return best_candidate.Name;
3997 return Methods.First ().Name;
4004 // When best candidate is already know this factory can be used
4005 // to avoid expensive overload resolution to be called
4007 // NOTE: InstanceExpression has to be set manually
4009 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
4011 return new MethodGroupExpr (best, queriedType, loc) {
4012 best_candidate = best,
4013 best_candidate_return = best.ReturnType
4017 public override string GetSignatureForError ()
4019 if (best_candidate != null)
4020 return best_candidate.GetSignatureForError ();
4022 return Methods.First ().GetSignatureForError ();
4025 public override Expression CreateExpressionTree (ResolveContext ec)
4027 if (best_candidate == null) {
4028 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4032 if (IsConditionallyExcluded)
4033 ec.Report.Error (765, loc,
4034 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4036 if (ConditionalAccess)
4037 Error_NullShortCircuitInsideExpressionTree (ec);
4039 return new TypeOfMethod (best_candidate, loc);
4042 protected override Expression DoResolve (ResolveContext ec)
4044 this.eclass = ExprClass.MethodGroup;
4046 if (InstanceExpression != null) {
4047 InstanceExpression = InstanceExpression.Resolve (ec);
4048 if (InstanceExpression == null)
4055 public override void Emit (EmitContext ec)
4057 throw new NotSupportedException ();
4060 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4062 var call = new CallEmitter ();
4063 call.InstanceExpression = InstanceExpression;
4064 call.ConditionalAccess = ConditionalAccess;
4067 call.EmitStatement (ec, best_candidate, arguments, loc);
4069 call.Emit (ec, best_candidate, arguments, loc);
4072 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4074 var ca = ec.ConditionalAccess;
4075 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4076 Statement = statement
4079 EmitCall (ec, arguments, statement);
4081 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4082 ec.ConditionalAccess = ca;
4085 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4087 if (target != InternalType.ErrorType) {
4088 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4089 Name, target.GetSignatureForError ());
4093 public bool HasAccessibleCandidate (ResolveContext rc)
4095 foreach (var candidate in Candidates) {
4096 if (candidate.IsAccessible (rc))
4103 public static bool IsExtensionMethodArgument (Expression expr)
4106 // LAMESPEC: No details about which expressions are not allowed
4108 return !(expr is TypeExpr) && !(expr is BaseThis);
4112 /// Find the Applicable Function Members (7.4.2.1)
4114 /// me: Method Group expression with the members to select.
4115 /// it might contain constructors or methods (or anything
4116 /// that maps to a method).
4118 /// Arguments: ArrayList containing resolved Argument objects.
4120 /// loc: The location if we want an error to be reported, or a Null
4121 /// location for "probing" purposes.
4123 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4124 /// that is the best match of me on Arguments.
4127 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4129 // TODO: causes issues with probing mode, remove explicit Kind check
4130 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4133 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4134 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4135 r.BaseMembersProvider = this;
4136 r.InstanceQualifier = this;
4139 if (cerrors != null)
4140 r.CustomErrors = cerrors;
4142 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4143 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4144 if (best_candidate == null) {
4145 if (!r.BestCandidateIsDynamic)
4148 if (simple_name != null && ec.IsStatic)
4149 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4154 // Overload resolver had to create a new method group, all checks bellow have already been executed
4155 if (r.BestCandidateNewMethodGroup != null)
4156 return r.BestCandidateNewMethodGroup;
4158 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4159 if (InstanceExpression != null) {
4160 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4161 InstanceExpression = null;
4163 if (simple_name != null && best_candidate.IsStatic) {
4164 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4167 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4171 ResolveInstanceExpression (ec, null);
4174 var base_override = CandidateToBaseOverride (ec, best_candidate);
4175 if (base_override == best_candidate) {
4176 best_candidate_return = r.BestCandidateReturnType;
4178 best_candidate = base_override;
4179 best_candidate_return = best_candidate.ReturnType;
4182 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4183 ConstraintChecker cc = new ConstraintChecker (ec);
4184 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4188 // Additional check for possible imported base override method which
4189 // could not be done during IsOverrideMethodBaseTypeAccessible
4191 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4192 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4193 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4194 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4197 // Speed up the check by not doing it on disallowed targets
4198 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4204 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4206 var fe = left as FieldExpr;
4209 // Using method-group on struct fields makes the struct assigned. I am not sure
4210 // why but that's what .net does
4212 fe.Spec.MemberDefinition.SetIsAssigned ();
4215 simple_name = original;
4216 return base.ResolveMemberAccess (ec, left, original);
4219 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4221 type_arguments = ta;
4224 #region IBaseMembersProvider Members
4226 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4228 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4231 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4233 if (queried_type == member.DeclaringType)
4236 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4237 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4241 // Extension methods lookup after ordinary methods candidates failed to apply
4243 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4245 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4248 if (!IsExtensionMethodArgument (InstanceExpression))
4251 int arity = type_arguments == null ? 0 : type_arguments.Count;
4252 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4253 if (methods == null)
4256 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4257 emg.SetTypeArguments (rc, type_arguments);
4264 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4266 public ConstructorInstanceQualifier (TypeSpec type)
4269 InstanceType = type;
4272 public TypeSpec InstanceType { get; private set; }
4274 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4276 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4280 public struct OverloadResolver
4283 public enum Restrictions
4287 ProbingOnly = 1 << 1,
4288 CovariantDelegate = 1 << 2,
4289 NoBaseMembers = 1 << 3,
4290 BaseMembersIncluded = 1 << 4,
4291 GetEnumeratorLookup = 1 << 5
4294 public interface IBaseMembersProvider
4296 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4297 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4298 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4301 public interface IErrorHandler
4303 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4304 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4305 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4306 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4309 public interface IInstanceQualifier
4311 TypeSpec InstanceType { get; }
4312 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4315 sealed class NoBaseMembers : IBaseMembersProvider
4317 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4319 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4324 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4329 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4335 struct AmbiguousCandidate
4337 public readonly MemberSpec Member;
4338 public readonly bool Expanded;
4339 public readonly AParametersCollection Parameters;
4341 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4344 Parameters = parameters;
4345 Expanded = expanded;
4350 IList<MemberSpec> members;
4351 TypeArguments type_arguments;
4352 IBaseMembersProvider base_provider;
4353 IErrorHandler custom_errors;
4354 IInstanceQualifier instance_qualifier;
4355 Restrictions restrictions;
4356 MethodGroupExpr best_candidate_extension_group;
4357 TypeSpec best_candidate_return_type;
4359 SessionReportPrinter lambda_conv_msgs;
4361 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4362 : this (members, null, restrictions, loc)
4366 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4369 if (members == null || members.Count == 0)
4370 throw new ArgumentException ("empty members set");
4372 this.members = members;
4374 type_arguments = targs;
4375 this.restrictions = restrictions;
4376 if (IsDelegateInvoke)
4377 this.restrictions |= Restrictions.NoBaseMembers;
4379 base_provider = NoBaseMembers.Instance;
4384 public IBaseMembersProvider BaseMembersProvider {
4386 return base_provider;
4389 base_provider = value;
4393 public bool BestCandidateIsDynamic { get; set; }
4396 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4398 public MethodGroupExpr BestCandidateNewMethodGroup {
4400 return best_candidate_extension_group;
4405 // Return type can be different between best candidate and closest override
4407 public TypeSpec BestCandidateReturnType {
4409 return best_candidate_return_type;
4413 public IErrorHandler CustomErrors {
4415 return custom_errors;
4418 custom_errors = value;
4422 TypeSpec DelegateType {
4424 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4425 throw new InternalErrorException ("Not running in delegate mode", loc);
4427 return members [0].DeclaringType;
4431 public IInstanceQualifier InstanceQualifier {
4433 return instance_qualifier;
4436 instance_qualifier = value;
4440 bool IsProbingOnly {
4442 return (restrictions & Restrictions.ProbingOnly) != 0;
4446 bool IsDelegateInvoke {
4448 return (restrictions & Restrictions.DelegateInvoke) != 0;
4455 // 7.4.3.3 Better conversion from expression
4456 // Returns : 1 if a->p is better,
4457 // 2 if a->q is better,
4458 // 0 if neither is better
4460 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4462 TypeSpec argument_type = a.Type;
4465 // If argument is an anonymous function
4467 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4469 // p and q are delegate types or expression tree types
4471 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4472 if (q.MemberDefinition != p.MemberDefinition) {
4477 // Uwrap delegate from Expression<T>
4479 q = TypeManager.GetTypeArguments (q)[0];
4480 p = TypeManager.GetTypeArguments (p)[0];
4483 var p_m = Delegate.GetInvokeMethod (p);
4484 var q_m = Delegate.GetInvokeMethod (q);
4487 // With identical parameter lists
4489 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4497 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4499 if (p.Kind == MemberKind.Void) {
4500 return q.Kind != MemberKind.Void ? 2 : 0;
4504 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4506 if (q.Kind == MemberKind.Void) {
4507 return p.Kind != MemberKind.Void ? 1: 0;
4510 var am = (AnonymousMethodExpression) a.Expr;
4513 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4514 // better conversion is performed between underlying types Y1 and Y2
4516 if (p.IsGenericTask || q.IsGenericTask) {
4517 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4518 q = q.TypeArguments[0];
4519 p = p.TypeArguments[0];
4525 // An inferred return type X exists for E in the context of that parameter list, and
4526 // the conversion from X to Y1 is better than the conversion from X to Y2
4528 argument_type = am.InferReturnType (ec, null, orig_q);
4529 if (argument_type == null) {
4530 // TODO: Can this be hit?
4534 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4535 argument_type = ec.BuiltinTypes.Object;
4539 if (argument_type == p)
4542 if (argument_type == q)
4546 // The parameters are identicial and return type is not void, use better type conversion
4547 // on return type to determine better one
4549 return BetterTypeConversion (ec, p, q);
4553 // 7.4.3.4 Better conversion from type
4555 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4557 if (p == null || q == null)
4558 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4560 switch (p.BuiltinType) {
4561 case BuiltinTypeSpec.Type.Int:
4562 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4565 case BuiltinTypeSpec.Type.Long:
4566 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4569 case BuiltinTypeSpec.Type.SByte:
4570 switch (q.BuiltinType) {
4571 case BuiltinTypeSpec.Type.Byte:
4572 case BuiltinTypeSpec.Type.UShort:
4573 case BuiltinTypeSpec.Type.UInt:
4574 case BuiltinTypeSpec.Type.ULong:
4578 case BuiltinTypeSpec.Type.Short:
4579 switch (q.BuiltinType) {
4580 case BuiltinTypeSpec.Type.UShort:
4581 case BuiltinTypeSpec.Type.UInt:
4582 case BuiltinTypeSpec.Type.ULong:
4586 case BuiltinTypeSpec.Type.Dynamic:
4587 // Dynamic is never better
4591 switch (q.BuiltinType) {
4592 case BuiltinTypeSpec.Type.Int:
4593 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4596 case BuiltinTypeSpec.Type.Long:
4597 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4600 case BuiltinTypeSpec.Type.SByte:
4601 switch (p.BuiltinType) {
4602 case BuiltinTypeSpec.Type.Byte:
4603 case BuiltinTypeSpec.Type.UShort:
4604 case BuiltinTypeSpec.Type.UInt:
4605 case BuiltinTypeSpec.Type.ULong:
4609 case BuiltinTypeSpec.Type.Short:
4610 switch (p.BuiltinType) {
4611 case BuiltinTypeSpec.Type.UShort:
4612 case BuiltinTypeSpec.Type.UInt:
4613 case BuiltinTypeSpec.Type.ULong:
4617 case BuiltinTypeSpec.Type.Dynamic:
4618 // Dynamic is never better
4622 // FIXME: handle lifted operators
4624 // TODO: this is expensive
4625 Expression p_tmp = new EmptyExpression (p);
4626 Expression q_tmp = new EmptyExpression (q);
4628 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4629 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4631 if (p_to_q && !q_to_p)
4634 if (q_to_p && !p_to_q)
4641 /// Determines "Better function" between candidate
4642 /// and the current best match
4645 /// Returns a boolean indicating :
4646 /// false if candidate ain't better
4647 /// true if candidate is better than the current best match
4649 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4650 MemberSpec best, AParametersCollection bparam, bool best_params)
4652 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4653 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4655 bool better_at_least_one = false;
4656 bool are_equivalent = true;
4657 int args_count = args == null ? 0 : args.Count;
4661 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4664 // Default arguments are ignored for better decision
4665 if (a.IsDefaultArgument)
4669 // When comparing named argument the parameter type index has to be looked up
4670 // in original parameter set (override version for virtual members)
4672 NamedArgument na = a as NamedArgument;
4674 int idx = cparam.GetParameterIndexByName (na.Name);
4675 ct = candidate_pd.Types[idx];
4676 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4677 ct = TypeManager.GetElementType (ct);
4679 idx = bparam.GetParameterIndexByName (na.Name);
4680 bt = best_pd.Types[idx];
4681 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4682 bt = TypeManager.GetElementType (bt);
4684 ct = candidate_pd.Types[c_idx];
4685 bt = best_pd.Types[b_idx];
4687 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4688 ct = TypeManager.GetElementType (ct);
4692 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4693 bt = TypeManager.GetElementType (bt);
4698 if (TypeSpecComparer.IsEqual (ct, bt))
4701 are_equivalent = false;
4702 int result = BetterExpressionConversion (ec, a, ct, bt);
4704 // for each argument, the conversion to 'ct' should be no worse than
4705 // the conversion to 'bt'.
4709 // for at least one argument, the conversion to 'ct' should be better than
4710 // the conversion to 'bt'.
4712 better_at_least_one = true;
4715 if (better_at_least_one)
4719 // Tie-breaking rules are applied only for equivalent parameter types
4721 if (!are_equivalent) {
4723 // LAMESPEC: A candidate with less default parameters is still better when there
4724 // is no better expression conversion
4726 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4734 // If candidate is applicable in its normal form and best has a params array and is applicable
4735 // only in its expanded form, then candidate is better
4737 if (candidate_params != best_params)
4738 return !candidate_params;
4741 // We have not reached end of parameters list due to params or used default parameters
4743 bool defaults_ambiguity = false;
4744 while (j < candidate_pd.Count && j < best_pd.Count) {
4745 var cand_param = candidate_pd.FixedParameters [j];
4746 var best_param = best_pd.FixedParameters [j];
4748 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4749 return cand_param.HasDefaultValue;
4751 defaults_ambiguity = true;
4752 if (candidate_pd.Count == best_pd.Count) {
4756 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4757 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4759 if (cand_param.HasDefaultValue) {
4768 // Neither is better when not all arguments are provided
4770 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4771 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4772 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4777 if (candidate_pd.Count != best_pd.Count) {
4778 if (defaults_ambiguity && best_pd.Count - 1 == j)
4779 return best_pd.HasParams;
4781 return candidate_pd.Count < best_pd.Count;
4785 // One is a non-generic method and second is a generic method, then non-generic is better
4787 if (best.IsGeneric != candidate.IsGeneric)
4788 return best.IsGeneric;
4791 // Both methods have the same number of parameters, and the parameters have equal types
4792 // Pick the "more specific" signature using rules over original (non-inflated) types
4794 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4795 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4797 bool specific_at_least_once = false;
4798 for (j = 0; j < args_count; ++j) {
4799 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4801 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4802 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4804 ct = candidate_def_pd.Types[j];
4805 bt = best_def_pd.Types[j];
4810 TypeSpec specific = MoreSpecific (ct, bt);
4814 specific_at_least_once = true;
4817 if (specific_at_least_once)
4823 static bool CheckInflatedArguments (MethodSpec ms)
4825 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4828 // Setup constraint checker for probing only
4829 ConstraintChecker cc = new ConstraintChecker (null);
4831 var mp = ms.Parameters.Types;
4832 for (int i = 0; i < mp.Length; ++i) {
4833 var type = mp[i] as InflatedTypeSpec;
4837 var targs = type.TypeArguments;
4838 if (targs.Length == 0)
4841 // TODO: Checking inflated MVAR arguments should be enough
4842 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4849 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4851 rc.Report.Error (1729, loc,
4852 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4853 type.GetSignatureForError (), argCount.ToString ());
4857 // Determines if the candidate method is applicable to the given set of arguments
4858 // There could be two different set of parameters for same candidate where one
4859 // is the closest override for default values and named arguments checks and second
4860 // one being the virtual base for the parameter types and modifiers.
4862 // A return value rates candidate method compatibility,
4864 // 0 = the best, int.MaxValue = the worst
4866 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)
4869 // Each step has allocated 10 values, it can overflow for
4870 // more than 10 arguments but that's ok as it's used for
4871 // better error reporting only
4873 const int ArgumentCountMismatch = 1000000000;
4874 const int NamedArgumentsMismatch = 100000000;
4875 const int DefaultArgumentMismatch = 10000000;
4876 const int UnexpectedTypeArguments = 1000000;
4877 const int TypeArgumentsMismatch = 100000;
4878 const int InflatedTypesMismatch = 10000;
4880 // Parameters of most-derived type used mainly for named and optional parameters
4881 var pd = pm.Parameters;
4883 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4884 // params modifier instead of most-derived type
4885 var cpd = ((IParametersMember) candidate).Parameters;
4886 int param_count = pd.Count;
4887 int optional_count = 0;
4889 Arguments orig_args = arguments;
4891 if (arg_count != param_count) {
4893 // No arguments expansion when doing exact match for delegates
4895 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4896 for (int i = 0; i < pd.Count; ++i) {
4897 if (pd.FixedParameters[i].HasDefaultValue) {
4898 optional_count = pd.Count - i;
4904 if (optional_count != 0) {
4905 // Readjust expected number when params used
4906 if (cpd.HasParams) {
4908 if (arg_count < param_count)
4910 } else if (arg_count > param_count) {
4911 int args_gap = System.Math.Abs (arg_count - param_count);
4912 return ArgumentCountMismatch + args_gap;
4913 } else if (arg_count < param_count - optional_count) {
4914 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4915 return ArgumentCountMismatch + args_gap;
4917 } else if (arg_count != param_count) {
4918 int args_gap = System.Math.Abs (arg_count - param_count);
4920 return ArgumentCountMismatch + args_gap;
4921 if (arg_count < param_count - 1)
4922 return ArgumentCountMismatch + args_gap;
4925 // Resize to fit optional arguments
4926 if (optional_count != 0) {
4927 if (arguments == null) {
4928 arguments = new Arguments (optional_count);
4930 // Have to create a new container, so the next run can do same
4931 var resized = new Arguments (param_count);
4932 resized.AddRange (arguments);
4933 arguments = resized;
4936 for (int i = arg_count; i < param_count; ++i)
4937 arguments.Add (null);
4941 if (arg_count > 0) {
4943 // Shuffle named arguments to the right positions if there are any
4945 if (arguments[arg_count - 1] is NamedArgument) {
4946 arg_count = arguments.Count;
4948 for (int i = 0; i < arg_count; ++i) {
4949 bool arg_moved = false;
4951 NamedArgument na = arguments[i] as NamedArgument;
4955 int index = pd.GetParameterIndexByName (na.Name);
4957 // Named parameter not found
4959 return NamedArgumentsMismatch - i;
4961 // already reordered
4966 if (index >= param_count) {
4967 // When using parameters which should not be available to the user
4968 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4971 arguments.Add (null);
4975 if (index == arg_count)
4976 return NamedArgumentsMismatch - i - 1;
4978 temp = arguments [index];
4980 // The slot has been taken by positional argument
4981 if (temp != null && !(temp is NamedArgument))
4986 arguments = arguments.MarkOrderedArgument (na);
4990 if (arguments == orig_args) {
4991 arguments = new Arguments (orig_args.Count);
4992 arguments.AddRange (orig_args);
4995 arguments[index] = arguments[i];
4996 arguments[i] = temp;
5003 arg_count = arguments.Count;
5005 } else if (arguments != null) {
5006 arg_count = arguments.Count;
5010 // Don't do any expensive checks when the candidate cannot succeed
5012 if (arg_count != param_count && !cpd.HasParams)
5013 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5015 var dep = candidate.GetMissingDependencies ();
5017 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5022 // 1. Handle generic method using type arguments when specified or type inference
5025 var ms = candidate as MethodSpec;
5026 if (ms != null && ms.IsGeneric) {
5027 if (type_arguments != null) {
5028 var g_args_count = ms.Arity;
5029 if (g_args_count != type_arguments.Count)
5030 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5032 if (type_arguments.Arguments != null)
5033 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5036 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5037 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5038 // candidate was found use the set to report more details about what was wrong with lambda body.
5039 // The general idea is to distinguish between code errors and errors caused by
5040 // trial-and-error type inference
5042 if (lambda_conv_msgs == null) {
5043 for (int i = 0; i < arg_count; i++) {
5044 Argument a = arguments[i];
5048 var am = a.Expr as AnonymousMethodExpression;
5050 if (lambda_conv_msgs == null)
5051 lambda_conv_msgs = new SessionReportPrinter ();
5053 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5058 var ti = new TypeInference (arguments);
5059 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5062 return TypeArgumentsMismatch - ti.InferenceScore;
5065 // Clear any error messages when the result was success
5067 if (lambda_conv_msgs != null)
5068 lambda_conv_msgs.ClearSession ();
5070 if (i_args.Length != 0) {
5072 for (int i = 0; i < i_args.Length; ++i) {
5073 var ta = i_args [i];
5074 if (!ta.IsAccessible (ec))
5075 return TypeArgumentsMismatch - i;
5079 ms = ms.MakeGenericMethod (ec, i_args);
5084 // Type arguments constraints have to match for the method to be applicable
5086 if (!CheckInflatedArguments (ms)) {
5088 return InflatedTypesMismatch;
5092 // We have a generic return type and at same time the method is override which
5093 // means we have to also inflate override return type in case the candidate is
5094 // best candidate and override return type is different to base return type.
5096 // virtual Foo<T, object> with override Foo<T, dynamic>
5098 if (candidate != pm) {
5099 MethodSpec override_ms = (MethodSpec) pm;
5100 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5101 returnType = inflator.Inflate (returnType);
5103 returnType = ms.ReturnType;
5110 if (type_arguments != null)
5111 return UnexpectedTypeArguments;
5117 // 2. Each argument has to be implicitly convertible to method parameter
5119 Parameter.Modifier p_mod = 0;
5122 for (int i = 0; i < arg_count; i++) {
5123 Argument a = arguments[i];
5125 var fp = pd.FixedParameters[i];
5126 if (!fp.HasDefaultValue) {
5127 arguments = orig_args;
5128 return arg_count * 2 + 2;
5132 // Get the default value expression, we can use the same expression
5133 // if the type matches
5135 Expression e = fp.DefaultValue;
5137 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5139 // Restore for possible error reporting
5140 for (int ii = i; ii < arg_count; ++ii)
5141 arguments.RemoveAt (i);
5143 return (arg_count - i) * 2 + 1;
5147 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5149 // LAMESPEC: Attributes can be mixed together with build-in priority
5151 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5152 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5153 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5154 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5155 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5156 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5160 arguments[i] = new Argument (e, Argument.AType.Default);
5164 if (p_mod != Parameter.Modifier.PARAMS) {
5165 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5167 } else if (!params_expanded_form) {
5168 params_expanded_form = true;
5169 pt = ((ElementTypeSpec) pt).Element;
5175 if (!params_expanded_form) {
5176 if (a.IsExtensionType) {
5177 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5182 score = IsArgumentCompatible (ec, a, p_mod, pt);
5185 dynamicArgument = true;
5190 // It can be applicable in expanded form (when not doing exact match like for delegates)
5192 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5193 if (!params_expanded_form) {
5194 pt = ((ElementTypeSpec) pt).Element;
5198 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5201 params_expanded_form = true;
5202 dynamicArgument = true;
5203 } else if (score == 0 || arg_count > pd.Count) {
5204 params_expanded_form = true;
5209 if (params_expanded_form)
5211 return (arg_count - i) * 2 + score;
5216 // Restore original arguments for dynamic binder to keep the intention of original source code
5218 if (dynamicArgument)
5219 arguments = orig_args;
5224 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5226 if (e is Constant && e.Type == ptype)
5230 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5232 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5233 e = new MemberAccess (new MemberAccess (new MemberAccess (
5234 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5235 } else if (e is Constant) {
5237 // Handles int to int? conversions, DefaultParameterValue check
5239 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5243 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5246 return e.Resolve (ec);
5250 // Tests argument compatibility with the parameter
5251 // The possible return values are
5253 // 1 - modifier mismatch
5254 // 2 - type mismatch
5255 // -1 - dynamic binding required
5257 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5260 // Types have to be identical when ref or out modifer
5261 // is used and argument is not of dynamic type
5263 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5264 var arg_type = argument.Type;
5266 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5268 // Using dynamic for ref/out parameter can still succeed at runtime
5270 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5276 if (arg_type != parameter) {
5277 if (arg_type == InternalType.VarOutType)
5281 // Do full equality check after quick path
5283 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5285 // Using dynamic for ref/out parameter can still succeed at runtime
5287 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5295 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5299 // Use implicit conversion in all modes to return same candidates when the expression
5300 // is used as argument or delegate conversion
5302 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5303 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5310 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5312 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5314 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5317 var ac_p = p as ArrayContainer;
5319 var ac_q = q as ArrayContainer;
5323 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5324 if (specific == ac_p.Element)
5326 if (specific == ac_q.Element)
5328 } else if (p.IsGeneric && q.IsGeneric) {
5329 var pargs = TypeManager.GetTypeArguments (p);
5330 var qargs = TypeManager.GetTypeArguments (q);
5332 bool p_specific_at_least_once = false;
5333 bool q_specific_at_least_once = false;
5335 for (int i = 0; i < pargs.Length; i++) {
5336 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5337 if (specific == pargs[i])
5338 p_specific_at_least_once = true;
5339 if (specific == qargs[i])
5340 q_specific_at_least_once = true;
5343 if (p_specific_at_least_once && !q_specific_at_least_once)
5345 if (!p_specific_at_least_once && q_specific_at_least_once)
5353 // Find the best method from candidate list
5355 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5357 List<AmbiguousCandidate> ambiguous_candidates = null;
5359 MemberSpec best_candidate;
5360 Arguments best_candidate_args = null;
5361 bool best_candidate_params = false;
5362 bool best_candidate_dynamic = false;
5363 int best_candidate_rate;
5364 IParametersMember best_parameter_member = null;
5366 int args_count = args != null ? args.Count : 0;
5368 Arguments candidate_args = args;
5369 bool error_mode = false;
5370 MemberSpec invocable_member = null;
5371 int applicable_candidates = 0;
5374 best_candidate = null;
5375 best_candidate_rate = int.MaxValue;
5377 var type_members = members;
5379 for (int i = 0; i < type_members.Count; ++i) {
5380 var member = type_members[i];
5383 // Methods in a base class are not candidates if any method in a derived
5384 // class is applicable
5386 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5390 if (!member.IsAccessible (rc))
5393 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5396 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5397 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5402 IParametersMember pm = member as IParametersMember;
5405 // Will use it later to report ambiguity between best method and invocable member
5407 if (Invocation.IsMemberInvocable (member))
5408 invocable_member = member;
5414 // Overload resolution is looking for base member but using parameter names
5415 // and default values from the closest member. That means to do expensive lookup
5416 // for the closest override for virtual or abstract members
5418 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5419 var override_params = base_provider.GetOverrideMemberParameters (member);
5420 if (override_params != null)
5421 pm = override_params;
5425 // Check if the member candidate is applicable
5427 bool params_expanded_form = false;
5428 bool dynamic_argument = false;
5429 TypeSpec rt = pm.MemberType;
5430 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5432 if (lambda_conv_msgs != null)
5433 lambda_conv_msgs.EndSession ();
5436 // How does it score compare to others
5438 if (candidate_rate < best_candidate_rate) {
5440 // Fatal error (missing dependency), cannot continue
5441 if (candidate_rate < 0)
5444 applicable_candidates = 1;
5445 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5446 // Only parameterless methods are considered
5448 best_candidate_rate = candidate_rate;
5449 best_candidate = member;
5450 best_candidate_args = candidate_args;
5451 best_candidate_params = params_expanded_form;
5452 best_candidate_dynamic = dynamic_argument;
5453 best_parameter_member = pm;
5454 best_candidate_return_type = rt;
5456 } else if (candidate_rate == 0) {
5458 // The member look is done per type for most operations but sometimes
5459 // it's not possible like for binary operators overload because they
5460 // are unioned between 2 sides
5462 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5463 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5467 ++applicable_candidates;
5469 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5471 // We pack all interface members into top level type which makes the overload resolution
5472 // more complicated for interfaces. We compensate it by removing methods with same
5473 // signature when building the cache hence this path should not really be hit often
5476 // interface IA { void Foo (int arg); }
5477 // interface IB : IA { void Foo (params int[] args); }
5479 // IB::Foo is the best overload when calling IB.Foo (1)
5482 if (ambiguous_candidates != null) {
5483 foreach (var amb_cand in ambiguous_candidates) {
5484 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5493 ambiguous_candidates = null;
5496 // Is the new candidate better
5497 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5501 best_candidate = member;
5502 best_candidate_args = candidate_args;
5503 best_candidate_params = params_expanded_form;
5504 best_candidate_dynamic = dynamic_argument;
5505 best_parameter_member = pm;
5506 best_candidate_return_type = rt;
5508 // It's not better but any other found later could be but we are not sure yet
5509 if (ambiguous_candidates == null)
5510 ambiguous_candidates = new List<AmbiguousCandidate> ();
5512 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5516 // Restore expanded arguments
5517 candidate_args = args;
5519 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5522 // We've found exact match
5524 if (best_candidate_rate == 0)
5528 // Try extension methods lookup when no ordinary method match was found and provider enables it
5531 var emg = base_provider.LookupExtensionMethod (rc);
5533 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5535 best_candidate_extension_group = emg;
5536 return (T) (MemberSpec) emg.BestCandidate;
5541 // Don't run expensive error reporting mode for probing
5548 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5551 lambda_conv_msgs = null;
5556 // No best member match found, report an error
5558 if (best_candidate_rate != 0 || error_mode) {
5559 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5563 if (best_candidate_dynamic) {
5564 if (args[0].IsExtensionType) {
5565 rc.Report.Error (1973, loc,
5566 "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",
5567 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5571 // Check type constraints only when explicit type arguments are used
5573 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5574 MethodSpec bc = best_candidate as MethodSpec;
5575 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5576 ConstraintChecker cc = new ConstraintChecker (rc);
5577 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5581 BestCandidateIsDynamic = true;
5586 // These flags indicates we are running delegate probing conversion. No need to
5587 // do more expensive checks
5589 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5590 return (T) best_candidate;
5592 if (ambiguous_candidates != null) {
5594 // Now check that there are no ambiguities i.e the selected method
5595 // should be better than all the others
5597 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5598 var candidate = ambiguous_candidates [ix];
5600 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5601 var ambiguous = candidate.Member;
5602 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5603 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5604 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5605 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5606 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5609 return (T) best_candidate;
5614 if (invocable_member != null && !IsProbingOnly) {
5615 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5616 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5617 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5618 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5622 // And now check if the arguments are all
5623 // compatible, perform conversions if
5624 // necessary etc. and return if everything is
5627 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5630 if (best_candidate == null)
5634 // Don't run possibly expensive checks in probing mode
5636 if (!IsProbingOnly && !rc.IsInProbingMode) {
5638 // Check ObsoleteAttribute on the best method
5640 best_candidate.CheckObsoleteness (rc, loc);
5642 best_candidate.MemberDefinition.SetIsUsed ();
5645 args = best_candidate_args;
5646 return (T) best_candidate;
5649 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5651 return ResolveMember<MethodSpec> (rc, ref args);
5654 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5655 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5657 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5660 if (a.Type == InternalType.ErrorType)
5663 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5664 ec.Report.SymbolRelatedToPreviousError (method);
5665 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5666 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5667 TypeManager.CSharpSignature (method));
5670 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5671 TypeManager.CSharpSignature (method));
5672 } else if (IsDelegateInvoke) {
5673 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5674 DelegateType.GetSignatureForError ());
5676 ec.Report.SymbolRelatedToPreviousError (method);
5677 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5678 method.GetSignatureForError ());
5681 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5683 string index = (idx + 1).ToString ();
5684 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5685 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5686 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5687 index, Parameter.GetModifierSignature (a.Modifier));
5689 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5690 index, Parameter.GetModifierSignature (mod));
5692 string p1 = a.GetSignatureForError ();
5693 string p2 = paramType.GetSignatureForError ();
5696 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5697 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5700 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5701 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5702 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5705 ec.Report.Error (1503, a.Expr.Location,
5706 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5711 // We have failed to find exact match so we return error info about the closest match
5713 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5715 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5716 int arg_count = args == null ? 0 : args.Count;
5718 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5719 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5720 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5724 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5729 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5730 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5731 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5735 // For candidates which match on parameters count report more details about incorrect arguments
5738 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5739 // Reject any inaccessible member
5740 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5741 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5742 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5746 var ms = best_candidate as MethodSpec;
5747 if (ms != null && ms.IsGeneric) {
5748 bool constr_ok = true;
5749 if (ms.TypeArguments != null)
5750 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5752 if (ta_count == 0 && ms.TypeArguments == null) {
5753 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5757 rc.Report.Error (411, loc,
5758 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5759 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5766 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5772 // We failed to find any method with correct argument count, report best candidate
5774 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5777 if (best_candidate.Kind == MemberKind.Constructor) {
5778 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5779 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5780 } else if (IsDelegateInvoke) {
5781 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5782 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5783 DelegateType.GetSignatureForError (), arg_count.ToString ());
5785 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5786 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5787 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5788 name, arg_count.ToString ());
5792 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5794 var p = ((IParametersMember)best_candidate).Parameters;
5799 for (int i = p.Count - 1; i != 0; --i) {
5800 var fp = p.FixedParameters [i];
5801 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5811 foreach (var arg in args) {
5812 var na = arg as NamedArgument;
5816 if (na.Name == name) {
5825 return args.Count + 1 == pm.Parameters.Count;
5828 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5830 var pd = pm.Parameters;
5831 var cpd = ((IParametersMember) member).Parameters;
5832 var ptypes = cpd.Types;
5834 Parameter.Modifier p_mod = 0;
5836 int a_idx = 0, a_pos = 0;
5838 ArrayInitializer params_initializers = null;
5839 bool has_unsafe_arg = pm.MemberType.IsPointer;
5840 int arg_count = args == null ? 0 : args.Count;
5842 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5847 if (p_mod != Parameter.Modifier.PARAMS) {
5848 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5850 has_unsafe_arg |= pt.IsPointer;
5852 if (p_mod == Parameter.Modifier.PARAMS) {
5853 if (chose_params_expanded) {
5854 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5855 pt = TypeManager.GetElementType (pt);
5861 // Types have to be identical when ref or out modifer is used
5863 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5864 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5867 var arg_type = a.Type;
5871 if (arg_type == InternalType.VarOutType) {
5873 // Set underlying variable type based on parameter type
5875 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5879 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5883 NamedArgument na = a as NamedArgument;
5885 int name_index = pd.GetParameterIndexByName (na.Name);
5886 if (name_index < 0 || name_index >= pd.Count) {
5887 if (IsDelegateInvoke) {
5888 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5889 ec.Report.Error (1746, na.Location,
5890 "The delegate `{0}' does not contain a parameter named `{1}'",
5891 DelegateType.GetSignatureForError (), na.Name);
5893 ec.Report.SymbolRelatedToPreviousError (member);
5894 ec.Report.Error (1739, na.Location,
5895 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5896 TypeManager.CSharpSignature (member), na.Name);
5898 } else if (args[name_index] != a && args[name_index] != null) {
5899 if (IsDelegateInvoke)
5900 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5902 ec.Report.SymbolRelatedToPreviousError (member);
5904 ec.Report.Error (1744, na.Location,
5905 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5910 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5913 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5914 if (a.IsExtensionType) {
5915 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5916 // CS1061 but that still better than confusing CS0123
5917 var ma = new MemberAccess (a.Expr, member.Name, loc);
5918 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5920 custom_errors.NoArgumentMatch (ec, member);
5926 if (a.IsExtensionType) {
5927 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5930 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5932 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5935 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5942 // Convert params arguments to an array initializer
5944 if (params_initializers != null) {
5945 // we choose to use 'a.Expr' rather than 'conv' so that
5946 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5947 params_initializers.Add (a.Expr);
5948 args.RemoveAt (a_idx--);
5954 // Update the argument with the implicit conversion
5958 if (a_idx != arg_count) {
5960 // Convert all var out argument to error type for less confusing error reporting
5961 // when no matching overload is found
5963 for (; a_idx < arg_count; a_idx++) {
5964 var arg = args [a_idx];
5968 if (arg.Type == InternalType.VarOutType) {
5969 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5973 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5978 // Fill not provided arguments required by params modifier
5980 if (params_initializers == null && arg_count + 1 == pd.Count) {
5982 args = new Arguments (1);
5984 pt = ptypes[pd.Count - 1];
5985 pt = TypeManager.GetElementType (pt);
5986 has_unsafe_arg |= pt.IsPointer;
5987 params_initializers = new ArrayInitializer (0, loc);
5991 // Append an array argument with all params arguments
5993 if (params_initializers != null) {
5994 args.Add (new Argument (
5995 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5999 if (has_unsafe_arg && !ec.IsUnsafe) {
6000 Expression.UnsafeError (ec, loc);
6004 // We could infer inaccesible type arguments
6006 if (type_arguments == null && member.IsGeneric) {
6007 var ms = (MethodSpec) member;
6008 foreach (var ta in ms.TypeArguments) {
6009 if (!ta.IsAccessible (ec)) {
6010 ec.Report.SymbolRelatedToPreviousError (ta);
6011 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6021 public class ConstantExpr : MemberExpr
6023 readonly ConstSpec constant;
6025 public ConstantExpr (ConstSpec constant, Location loc)
6027 this.constant = constant;
6031 public override string Name {
6032 get { throw new NotImplementedException (); }
6035 public override string KindName {
6036 get { return "constant"; }
6039 public override bool IsInstance {
6040 get { return !IsStatic; }
6043 public override bool IsStatic {
6044 get { return true; }
6047 protected override TypeSpec DeclaringType {
6048 get { return constant.DeclaringType; }
6051 public override Expression CreateExpressionTree (ResolveContext ec)
6053 throw new NotSupportedException ("ET");
6056 protected override Expression DoResolve (ResolveContext rc)
6058 ResolveInstanceExpression (rc, null);
6059 DoBestMemberChecks (rc, constant);
6061 var c = constant.GetConstant (rc);
6063 // Creates reference expression to the constant value
6064 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6067 public override void Emit (EmitContext ec)
6069 throw new NotSupportedException ();
6072 public override string GetSignatureForError ()
6074 return constant.GetSignatureForError ();
6077 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6079 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6084 // Fully resolved expression that references a Field
6086 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6088 protected FieldSpec spec;
6089 VariableInfo variable_info;
6091 LocalTemporary temp;
6094 protected FieldExpr (Location l)
6099 public FieldExpr (FieldSpec spec, Location loc)
6104 type = spec.MemberType;
6107 public FieldExpr (FieldBase fi, Location l)
6114 public override string Name {
6120 public bool IsHoisted {
6122 IVariableReference hv = InstanceExpression as IVariableReference;
6123 return hv != null && hv.IsHoisted;
6127 public override bool IsInstance {
6129 return !spec.IsStatic;
6133 public override bool IsStatic {
6135 return spec.IsStatic;
6139 public override string KindName {
6140 get { return "field"; }
6143 public FieldSpec Spec {
6149 protected override TypeSpec DeclaringType {
6151 return spec.DeclaringType;
6155 public VariableInfo VariableInfo {
6157 return variable_info;
6163 public override string GetSignatureForError ()
6165 return spec.GetSignatureForError ();
6168 public bool IsMarshalByRefAccess (ResolveContext rc)
6170 // Checks possible ldflda of field access expression
6171 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6172 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6173 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6176 public void SetHasAddressTaken ()
6178 IVariableReference vr = InstanceExpression as IVariableReference;
6180 vr.SetHasAddressTaken ();
6184 protected override void CloneTo (CloneContext clonectx, Expression target)
6186 var t = (FieldExpr) target;
6188 if (InstanceExpression != null)
6189 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6192 public override Expression CreateExpressionTree (ResolveContext ec)
6194 if (ConditionalAccess) {
6195 Error_NullShortCircuitInsideExpressionTree (ec);
6198 return CreateExpressionTree (ec, true);
6201 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6204 Expression instance;
6206 if (InstanceExpression == null) {
6207 instance = new NullLiteral (loc);
6208 } else if (convertInstance) {
6209 instance = InstanceExpression.CreateExpressionTree (ec);
6211 args = new Arguments (1);
6212 args.Add (new Argument (InstanceExpression));
6213 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6216 args = Arguments.CreateForExpressionTree (ec, null,
6218 CreateTypeOfExpression ());
6220 return CreateExpressionFactoryCall (ec, "Field", args);
6223 public Expression CreateTypeOfExpression ()
6225 return new TypeOfField (spec, loc);
6228 protected override Expression DoResolve (ResolveContext ec)
6230 spec.MemberDefinition.SetIsUsed ();
6232 return DoResolve (ec, null);
6235 Expression DoResolve (ResolveContext ec, Expression rhs)
6237 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6240 ResolveConditionalAccessReceiver (ec);
6242 if (ResolveInstanceExpression (ec, rhs)) {
6243 // Resolve the field's instance expression while flow analysis is turned
6244 // off: when accessing a field "a.b", we must check whether the field
6245 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6247 if (lvalue_instance) {
6248 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6250 Expression right_side =
6251 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6253 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6255 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6258 if (InstanceExpression == null)
6262 DoBestMemberChecks (ec, spec);
6264 if (conditional_access_receiver)
6265 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6268 var fb = spec as FixedFieldSpec;
6269 IVariableReference var = InstanceExpression as IVariableReference;
6272 IFixedExpression fe = InstanceExpression as IFixedExpression;
6273 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6274 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6277 if (InstanceExpression.eclass != ExprClass.Variable) {
6278 ec.Report.SymbolRelatedToPreviousError (spec);
6279 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6280 TypeManager.GetFullNameSignature (spec));
6281 } else if (var != null && var.IsHoisted) {
6282 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6285 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6289 // Set flow-analysis variable info for struct member access. It will be check later
6290 // for precise error reporting
6292 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6293 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6296 if (conditional_access_receiver)
6297 type = LiftMemberType (ec, type);
6299 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6300 return Constant.CreateConstantFromValue (type, null, loc);
6302 eclass = ExprClass.Variable;
6306 public void SetFieldAssigned (FlowAnalysisContext fc)
6311 bool lvalue_instance = spec.DeclaringType.IsStruct;
6312 if (lvalue_instance) {
6313 var var = InstanceExpression as IVariableReference;
6314 if (var != null && var.VariableInfo != null) {
6315 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6319 var fe = InstanceExpression as FieldExpr;
6321 Expression instance;
6324 instance = fe.InstanceExpression;
6325 var fe_instance = instance as FieldExpr;
6326 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6327 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6328 var var = InstanceExpression as IVariableReference;
6329 if (var != null && var.VariableInfo == null) {
6330 var var_inst = instance as IVariableReference;
6331 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6332 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6336 if (fe_instance != null) {
6345 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6346 instance.FlowAnalysis (fc);
6348 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6349 InstanceExpression.FlowAnalysis (fc);
6353 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6355 // The return value is always null. Returning a value simplifies calling code.
6357 if (right_side == EmptyExpression.OutAccess) {
6359 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6360 GetSignatureForError ());
6362 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6363 GetSignatureForError ());
6369 if (right_side == EmptyExpression.LValueMemberAccess) {
6370 // Already reported as CS1648/CS1650
6374 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6376 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6377 GetSignatureForError ());
6379 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6380 GetSignatureForError ());
6386 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6387 GetSignatureForError ());
6389 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6390 GetSignatureForError ());
6396 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6398 if (HasConditionalAccess ())
6399 Error_NullPropagatingLValue (ec);
6401 if (spec is FixedFieldSpec) {
6402 // It could be much better error message but we want to be error compatible
6403 Error_ValueAssignment (ec, right_side);
6406 Expression e = DoResolve (ec, right_side);
6411 spec.MemberDefinition.SetIsAssigned ();
6413 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6414 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6415 ec.Report.Warning (420, 1, loc,
6416 "`{0}': A volatile field references will not be treated as volatile",
6417 spec.GetSignatureForError ());
6420 if (spec.IsReadOnly) {
6421 // InitOnly fields can only be assigned in constructors or initializers
6422 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6423 return Error_AssignToReadonly (ec, right_side);
6425 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6427 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6428 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6429 return Error_AssignToReadonly (ec, right_side);
6430 // static InitOnly fields cannot be assigned-to in an instance constructor
6431 if (IsStatic && !ec.IsStatic)
6432 return Error_AssignToReadonly (ec, right_side);
6433 // instance constructors can't modify InitOnly fields of other instances of the same type
6434 if (!IsStatic && !(InstanceExpression is This))
6435 return Error_AssignToReadonly (ec, right_side);
6439 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6440 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6441 ec.Report.Warning (197, 1, loc,
6442 "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",
6443 GetSignatureForError ());
6446 eclass = ExprClass.Variable;
6450 public override void FlowAnalysis (FlowAnalysisContext fc)
6452 var var = InstanceExpression as IVariableReference;
6454 var vi = var.VariableInfo;
6455 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6456 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6460 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6461 var le = SkipLeftValueTypeAccess (InstanceExpression);
6463 le.FlowAnalysis (fc);
6469 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6471 base.FlowAnalysis (fc);
6473 if (conditional_access_receiver)
6474 fc.DefiniteAssignment = da;
6477 static Expression SkipLeftValueTypeAccess (Expression expr)
6479 if (!TypeSpec.IsValueType (expr.Type))
6482 if (expr is VariableReference)
6485 var fe = expr as FieldExpr;
6489 if (fe.InstanceExpression == null)
6492 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6495 public override int GetHashCode ()
6497 return spec.GetHashCode ();
6500 public bool IsFixed {
6503 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6505 IVariableReference variable = InstanceExpression as IVariableReference;
6506 if (variable != null)
6507 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6509 IFixedExpression fe = InstanceExpression as IFixedExpression;
6510 return fe != null && fe.IsFixed;
6514 public override bool Equals (object obj)
6516 FieldExpr fe = obj as FieldExpr;
6520 if (spec != fe.spec)
6523 if (InstanceExpression == null || fe.InstanceExpression == null)
6526 return InstanceExpression.Equals (fe.InstanceExpression);
6529 public void Emit (EmitContext ec, bool leave_copy)
6531 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6535 ec.Emit (OpCodes.Volatile);
6537 ec.Emit (OpCodes.Ldsfld, spec);
6540 if (conditional_access_receiver)
6541 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6543 EmitInstance (ec, false);
6546 // Optimization for build-in types
6547 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6548 ec.EmitLoadFromPtr (type);
6550 var ff = spec as FixedFieldSpec;
6552 ec.Emit (OpCodes.Ldflda, spec);
6553 ec.Emit (OpCodes.Ldflda, ff.Element);
6556 ec.Emit (OpCodes.Volatile);
6558 ec.Emit (OpCodes.Ldfld, spec);
6562 if (conditional_access_receiver) {
6563 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6568 ec.Emit (OpCodes.Dup);
6570 temp = new LocalTemporary (this.Type);
6576 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6578 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6579 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6584 if (ConditionalAccess)
6585 throw new NotImplementedException ("null operator assignment");
6587 if (has_await_source)
6588 source = source.EmitToField (ec);
6590 EmitInstance (ec, prepared);
6595 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6596 ec.Emit (OpCodes.Dup);
6598 temp = new LocalTemporary (this.Type);
6603 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6604 ec.Emit (OpCodes.Volatile);
6606 spec.MemberDefinition.SetIsAssigned ();
6609 ec.Emit (OpCodes.Stsfld, spec);
6611 ec.Emit (OpCodes.Stfld, spec);
6613 if (ec.NotifyEvaluatorOnStore) {
6615 throw new NotImplementedException ("instance field write");
6618 ec.Emit (OpCodes.Dup);
6620 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6631 // Emits store to field with prepared values on stack
6633 public void EmitAssignFromStack (EmitContext ec)
6636 ec.Emit (OpCodes.Stsfld, spec);
6638 ec.Emit (OpCodes.Stfld, spec);
6642 public override void Emit (EmitContext ec)
6647 public override void EmitSideEffect (EmitContext ec)
6649 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6651 if (is_volatile) // || is_marshal_by_ref ())
6652 base.EmitSideEffect (ec);
6655 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6657 if ((mode & AddressOp.Store) != 0)
6658 spec.MemberDefinition.SetIsAssigned ();
6659 if ((mode & AddressOp.Load) != 0)
6660 spec.MemberDefinition.SetIsUsed ();
6663 // Handle initonly fields specially: make a copy and then
6664 // get the address of the copy.
6667 if (spec.IsReadOnly){
6669 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6681 var temp = ec.GetTemporaryLocal (type);
6682 ec.Emit (OpCodes.Stloc, temp);
6683 ec.Emit (OpCodes.Ldloca, temp);
6689 ec.Emit (OpCodes.Ldsflda, spec);
6692 EmitInstance (ec, false);
6693 ec.Emit (OpCodes.Ldflda, spec);
6697 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6699 return MakeExpression (ctx);
6702 public override SLE.Expression MakeExpression (BuilderContext ctx)
6705 return base.MakeExpression (ctx);
6707 return SLE.Expression.Field (
6708 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6709 spec.GetMetaInfo ());
6713 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6715 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6721 // Expression that evaluates to a Property.
6723 // This is not an LValue because we need to re-write the expression. We
6724 // can not take data from the stack and store it.
6726 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6728 Arguments arguments;
6729 FieldExpr backing_field;
6731 public PropertyExpr (PropertySpec spec, Location l)
6734 best_candidate = spec;
6735 type = spec.MemberType;
6740 protected override Arguments Arguments {
6749 protected override TypeSpec DeclaringType {
6751 return best_candidate.DeclaringType;
6755 public override string Name {
6757 return best_candidate.Name;
6761 public bool IsAutoPropertyAccess {
6763 var prop = best_candidate.MemberDefinition as Property;
6764 return prop != null && prop.BackingField != null;
6768 public override bool IsInstance {
6774 public override bool IsStatic {
6776 return best_candidate.IsStatic;
6780 public override string KindName {
6781 get { return "property"; }
6784 public PropertySpec PropertyInfo {
6786 return best_candidate;
6792 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6794 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6797 var args_count = arguments == null ? 0 : arguments.Count;
6798 if (args_count != body.Parameters.Count && args_count == 0)
6801 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6802 mg.InstanceExpression = InstanceExpression;
6807 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6809 return new PropertyExpr (spec, loc) {
6815 public override Expression CreateExpressionTree (ResolveContext ec)
6817 if (ConditionalAccess) {
6818 Error_NullShortCircuitInsideExpressionTree (ec);
6822 if (IsSingleDimensionalArrayLength ()) {
6823 args = new Arguments (1);
6824 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6825 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6828 args = new Arguments (2);
6829 if (InstanceExpression == null)
6830 args.Add (new Argument (new NullLiteral (loc)));
6832 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6833 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6834 return CreateExpressionFactoryCall (ec, "Property", args);
6837 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6839 DoResolveLValue (rc, null);
6840 return new TypeOfMethod (Setter, loc);
6843 public override string GetSignatureForError ()
6845 return best_candidate.GetSignatureForError ();
6848 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6851 return base.MakeExpression (ctx);
6853 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6857 public override SLE.Expression MakeExpression (BuilderContext ctx)
6860 return base.MakeExpression (ctx);
6862 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6866 void Error_PropertyNotValid (ResolveContext ec)
6868 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6869 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6870 GetSignatureForError ());
6873 bool IsSingleDimensionalArrayLength ()
6875 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6878 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6879 return ac != null && ac.Rank == 1;
6882 public override void Emit (EmitContext ec, bool leave_copy)
6885 // Special case: length of single dimension array property is turned into ldlen
6887 if (IsSingleDimensionalArrayLength ()) {
6888 if (conditional_access_receiver) {
6889 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6892 EmitInstance (ec, false);
6894 ec.Emit (OpCodes.Ldlen);
6895 ec.Emit (OpCodes.Conv_I4);
6897 if (conditional_access_receiver) {
6898 ec.CloseConditionalAccess (type);
6904 base.Emit (ec, leave_copy);
6907 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6909 if (backing_field != null) {
6910 backing_field.EmitAssign (ec, source, false, false);
6915 LocalTemporary await_source_arg = null;
6917 if (isCompound && !(source is DynamicExpressionStatement)) {
6918 emitting_compound_assignment = true;
6921 if (has_await_arguments) {
6922 await_source_arg = new LocalTemporary (Type);
6923 await_source_arg.Store (ec);
6925 args = new Arguments (1);
6926 args.Add (new Argument (await_source_arg));
6929 temp = await_source_arg;
6932 has_await_arguments = false;
6937 ec.Emit (OpCodes.Dup);
6938 temp = new LocalTemporary (this.Type);
6943 args = arguments ?? new Arguments (1);
6947 temp = new LocalTemporary (this.Type);
6949 args.Add (new Argument (temp));
6951 args.Add (new Argument (source));
6955 emitting_compound_assignment = false;
6957 var call = new CallEmitter ();
6958 call.InstanceExpression = InstanceExpression;
6960 call.InstanceExpressionOnStack = true;
6962 if (ConditionalAccess) {
6963 call.ConditionalAccess = true;
6967 call.Emit (ec, Setter, args, loc);
6969 call.EmitStatement (ec, Setter, args, loc);
6976 if (await_source_arg != null) {
6977 await_source_arg.Release (ec);
6981 public override void FlowAnalysis (FlowAnalysisContext fc)
6983 var prop = best_candidate.MemberDefinition as Property;
6984 if (prop != null && prop.BackingField != null) {
6985 var var = InstanceExpression as IVariableReference;
6987 var vi = var.VariableInfo;
6988 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6989 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6993 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6998 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7000 base.FlowAnalysis (fc);
7002 if (conditional_access_receiver)
7003 fc.DefiniteAssignment = da;
7006 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7008 eclass = ExprClass.PropertyAccess;
7010 if (best_candidate.IsNotCSharpCompatible) {
7011 Error_PropertyNotValid (rc);
7014 ResolveInstanceExpression (rc, right_side);
7016 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7017 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7018 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7020 type = p.MemberType;
7024 DoBestMemberChecks (rc, best_candidate);
7026 // Handling of com-imported properties with any number of default property parameters
7027 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7028 var p = best_candidate.Get.Parameters;
7029 arguments = new Arguments (p.Count);
7030 for (int i = 0; i < p.Count; ++i) {
7031 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7033 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7034 var p = best_candidate.Set.Parameters;
7035 arguments = new Arguments (p.Count - 1);
7036 for (int i = 0; i < p.Count - 1; ++i) {
7037 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7044 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7046 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7049 var prop = best_candidate.MemberDefinition as Property;
7050 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7051 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7055 prop = (Property)ps.MemberDefinition;
7058 var spec = prop.BackingField;
7062 if (rc.IsStatic != spec.IsStatic)
7065 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7068 backing_field = new FieldExpr (prop.BackingField, loc);
7069 backing_field.ResolveLValue (rc, rhs);
7073 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7075 if (backing_field != null) {
7076 backing_field.SetFieldAssigned (fc);
7080 if (!IsAutoPropertyAccess)
7083 var prop = best_candidate.MemberDefinition as Property;
7084 if (prop != null && prop.BackingField != null) {
7085 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7086 if (lvalue_instance) {
7087 var var = InstanceExpression as IVariableReference;
7088 if (var != null && var.VariableInfo != null) {
7089 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7095 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7097 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7101 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7103 // getter and setter can be different for base calls
7104 MethodSpec getter, setter;
7105 protected T best_candidate;
7107 protected LocalTemporary temp;
7108 protected bool emitting_compound_assignment;
7109 protected bool has_await_arguments;
7111 protected PropertyOrIndexerExpr (Location l)
7118 protected abstract Arguments Arguments { get; set; }
7120 public MethodSpec Getter {
7129 public MethodSpec Setter {
7140 protected override Expression DoResolve (ResolveContext ec)
7142 if (eclass == ExprClass.Unresolved) {
7143 ResolveConditionalAccessReceiver (ec);
7145 var expr = OverloadResolve (ec, null);
7150 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7151 return expr.Resolve (ec);
7154 if (conditional_access_receiver) {
7155 type = LiftMemberType (ec, type);
7159 if (!ResolveGetter (ec))
7165 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7167 if (HasConditionalAccess ())
7168 Error_NullPropagatingLValue (rc);
7170 if (right_side == EmptyExpression.OutAccess) {
7171 // TODO: best_candidate can be null at this point
7172 INamedBlockVariable variable = null;
7173 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7174 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7175 best_candidate.Name);
7177 right_side.DoResolveLValue (rc, this);
7182 if (eclass == ExprClass.Unresolved) {
7183 var expr = OverloadResolve (rc, right_side);
7188 return expr.ResolveLValue (rc, right_side);
7190 ResolveInstanceExpression (rc, right_side);
7193 if (!best_candidate.HasSet) {
7194 if (ResolveAutopropertyAssignment (rc, right_side))
7197 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7198 GetSignatureForError ());
7202 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7203 if (best_candidate.HasDifferentAccessibility) {
7204 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7205 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7206 GetSignatureForError ());
7208 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7209 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7213 if (best_candidate.HasDifferentAccessibility)
7214 CheckProtectedMemberAccess (rc, best_candidate.Set);
7216 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7220 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7222 var ca = ec.ConditionalAccess;
7223 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7225 call.Emit (ec, method, arguments, loc);
7227 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7228 ec.ConditionalAccess = ca;
7232 // Implements the IAssignMethod interface for assignments
7234 public virtual void Emit (EmitContext ec, bool leave_copy)
7236 var call = new CallEmitter ();
7237 call.ConditionalAccess = ConditionalAccess;
7238 call.InstanceExpression = InstanceExpression;
7239 if (has_await_arguments)
7240 call.HasAwaitArguments = true;
7242 call.DuplicateArguments = emitting_compound_assignment;
7244 if (conditional_access_receiver)
7245 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7247 call.Emit (ec, Getter, Arguments, loc);
7249 if (call.HasAwaitArguments) {
7250 InstanceExpression = call.InstanceExpression;
7251 Arguments = call.EmittedArguments;
7252 has_await_arguments = true;
7256 ec.Emit (OpCodes.Dup);
7257 temp = new LocalTemporary (Type);
7262 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7264 public override void Emit (EmitContext ec)
7269 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7271 has_await_arguments = true;
7276 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7278 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7280 bool ResolveGetter (ResolveContext rc)
7282 if (!best_candidate.HasGet) {
7283 if (InstanceExpression != EmptyExpression.Null) {
7284 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7285 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7286 best_candidate.GetSignatureForError ());
7289 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7290 if (best_candidate.HasDifferentAccessibility) {
7291 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7292 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7293 TypeManager.CSharpSignature (best_candidate));
7295 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7296 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7300 if (best_candidate.HasDifferentAccessibility) {
7301 CheckProtectedMemberAccess (rc, best_candidate.Get);
7304 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7308 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7315 /// Fully resolved expression that evaluates to an Event
7317 public class EventExpr : MemberExpr, IAssignMethod
7319 readonly EventSpec spec;
7322 public EventExpr (EventSpec spec, Location loc)
7330 protected override TypeSpec DeclaringType {
7332 return spec.DeclaringType;
7336 public override string Name {
7342 public override bool IsInstance {
7344 return !spec.IsStatic;
7348 public override bool IsStatic {
7350 return spec.IsStatic;
7354 public override string KindName {
7355 get { return "event"; }
7358 public MethodSpec Operator {
7366 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7369 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7371 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7372 if (spec.BackingField != null &&
7373 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7375 spec.MemberDefinition.SetIsUsed ();
7377 spec.CheckObsoleteness (ec, loc);
7379 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7380 Error_AssignmentEventOnly (ec);
7382 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7384 InstanceExpression = null;
7386 return ml.ResolveMemberAccess (ec, left, original);
7390 return base.ResolveMemberAccess (ec, left, original);
7393 public override Expression CreateExpressionTree (ResolveContext ec)
7395 throw new NotSupportedException ("ET");
7398 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7400 if (right_side == EmptyExpression.EventAddition) {
7401 op = spec.AccessorAdd;
7402 } else if (right_side == EmptyExpression.EventSubtraction) {
7403 op = spec.AccessorRemove;
7407 Error_AssignmentEventOnly (ec);
7411 if (HasConditionalAccess ())
7412 Error_NullPropagatingLValue (ec);
7414 op = CandidateToBaseOverride (ec, op);
7418 protected override Expression DoResolve (ResolveContext ec)
7420 eclass = ExprClass.EventAccess;
7421 type = spec.MemberType;
7423 ResolveInstanceExpression (ec, null);
7425 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7426 Error_AssignmentEventOnly (ec);
7429 DoBestMemberChecks (ec, spec);
7433 public override void Emit (EmitContext ec)
7435 throw new NotSupportedException ();
7436 //Error_CannotAssign ();
7439 #region IAssignMethod Members
7441 public void Emit (EmitContext ec, bool leave_copy)
7443 throw new NotImplementedException ();
7446 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7448 if (leave_copy || !isCompound)
7449 throw new NotImplementedException ("EventExpr::EmitAssign");
7451 Arguments args = new Arguments (1);
7452 args.Add (new Argument (source));
7454 // TODO: Wrong, needs receiver
7455 // if (NullShortCircuit) {
7456 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7459 var call = new CallEmitter ();
7460 call.InstanceExpression = InstanceExpression;
7461 call.ConditionalAccess = ConditionalAccess;
7462 call.EmitStatement (ec, op, args, loc);
7464 // if (NullShortCircuit)
7465 // ec.CloseConditionalAccess (null);
7470 void Error_AssignmentEventOnly (ResolveContext ec)
7472 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7473 ec.Report.Error (79, loc,
7474 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7475 GetSignatureForError ());
7477 ec.Report.Error (70, loc,
7478 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7479 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7483 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7485 name = name.Substring (0, name.LastIndexOf ('.'));
7486 base.Error_CannotCallAbstractBase (rc, name);
7489 public override string GetSignatureForError ()
7491 return TypeManager.CSharpSignature (spec);
7494 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7496 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7500 public class TemporaryVariableReference : VariableReference
7502 public class Declarator : Statement
7504 TemporaryVariableReference variable;
7506 public Declarator (TemporaryVariableReference variable)
7508 this.variable = variable;
7512 protected override void DoEmit (EmitContext ec)
7514 variable.li.CreateBuilder (ec);
7517 public override void Emit (EmitContext ec)
7519 // Don't create sequence point
7523 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7528 protected override void CloneTo (CloneContext clonectx, Statement target)
7536 public TemporaryVariableReference (LocalVariable li, Location loc)
7539 this.type = li.Type;
7543 public override bool IsLockedByStatement {
7551 public LocalVariable LocalInfo {
7557 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7559 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7560 return new TemporaryVariableReference (li, loc);
7563 protected override Expression DoResolve (ResolveContext ec)
7565 eclass = ExprClass.Variable;
7568 // Don't capture temporary variables except when using
7569 // state machine redirection and block yields
7571 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7572 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7573 ec.IsVariableCapturingRequired) {
7574 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7575 storey.CaptureLocalVariable (ec, li);
7581 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7583 return Resolve (ec);
7586 public override void Emit (EmitContext ec)
7588 li.CreateBuilder (ec);
7593 public void EmitAssign (EmitContext ec, Expression source)
7595 li.CreateBuilder (ec);
7597 EmitAssign (ec, source, false, false);
7600 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7602 return li.HoistedVariant;
7605 public override bool IsFixed {
7606 get { return true; }
7609 public override bool IsRef {
7610 get { return false; }
7613 public override string Name {
7614 get { throw new NotImplementedException (); }
7617 public override void SetHasAddressTaken ()
7619 throw new NotImplementedException ();
7622 protected override ILocalVariable Variable {
7626 public override VariableInfo VariableInfo {
7627 get { return null; }
7632 /// Handles `var' contextual keyword; var becomes a keyword only
7633 /// if no type called var exists in a variable scope
7635 class VarExpr : SimpleName
7637 public VarExpr (Location loc)
7642 public bool InferType (ResolveContext ec, Expression right_side)
7645 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7647 type = right_side.Type;
7648 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7649 ec.Report.Error (815, loc,
7650 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7651 type.GetSignatureForError ());
7652 type = InternalType.ErrorType;
7656 eclass = ExprClass.Variable;
7660 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7662 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7663 base.Error_TypeOrNamespaceNotFound (ec);
7665 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");