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 && !ec.HasSet (ResolveContext.Options.NameOfScope) && 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);
4258 emg.ConditionalAccess = ConditionalAccess;
4265 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4267 public ConstructorInstanceQualifier (TypeSpec type)
4270 InstanceType = type;
4273 public TypeSpec InstanceType { get; private set; }
4275 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4277 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4281 public struct OverloadResolver
4284 public enum Restrictions
4288 ProbingOnly = 1 << 1,
4289 CovariantDelegate = 1 << 2,
4290 NoBaseMembers = 1 << 3,
4291 BaseMembersIncluded = 1 << 4,
4292 GetEnumeratorLookup = 1 << 5
4295 public interface IBaseMembersProvider
4297 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4298 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4299 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4302 public interface IErrorHandler
4304 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4305 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4306 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4307 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4310 public interface IInstanceQualifier
4312 TypeSpec InstanceType { get; }
4313 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4316 sealed class NoBaseMembers : IBaseMembersProvider
4318 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4320 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4325 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4330 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4336 struct AmbiguousCandidate
4338 public readonly MemberSpec Member;
4339 public readonly bool Expanded;
4340 public readonly AParametersCollection Parameters;
4342 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4345 Parameters = parameters;
4346 Expanded = expanded;
4351 IList<MemberSpec> members;
4352 TypeArguments type_arguments;
4353 IBaseMembersProvider base_provider;
4354 IErrorHandler custom_errors;
4355 IInstanceQualifier instance_qualifier;
4356 Restrictions restrictions;
4357 MethodGroupExpr best_candidate_extension_group;
4358 TypeSpec best_candidate_return_type;
4360 SessionReportPrinter lambda_conv_msgs;
4362 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4363 : this (members, null, restrictions, loc)
4367 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4370 if (members == null || members.Count == 0)
4371 throw new ArgumentException ("empty members set");
4373 this.members = members;
4375 type_arguments = targs;
4376 this.restrictions = restrictions;
4377 if (IsDelegateInvoke)
4378 this.restrictions |= Restrictions.NoBaseMembers;
4380 base_provider = NoBaseMembers.Instance;
4385 public IBaseMembersProvider BaseMembersProvider {
4387 return base_provider;
4390 base_provider = value;
4394 public bool BestCandidateIsDynamic { get; set; }
4397 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4399 public MethodGroupExpr BestCandidateNewMethodGroup {
4401 return best_candidate_extension_group;
4406 // Return type can be different between best candidate and closest override
4408 public TypeSpec BestCandidateReturnType {
4410 return best_candidate_return_type;
4414 public IErrorHandler CustomErrors {
4416 return custom_errors;
4419 custom_errors = value;
4423 TypeSpec DelegateType {
4425 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4426 throw new InternalErrorException ("Not running in delegate mode", loc);
4428 return members [0].DeclaringType;
4432 public IInstanceQualifier InstanceQualifier {
4434 return instance_qualifier;
4437 instance_qualifier = value;
4441 bool IsProbingOnly {
4443 return (restrictions & Restrictions.ProbingOnly) != 0;
4447 bool IsDelegateInvoke {
4449 return (restrictions & Restrictions.DelegateInvoke) != 0;
4456 // 7.4.3.3 Better conversion from expression
4457 // Returns : 1 if a->p is better,
4458 // 2 if a->q is better,
4459 // 0 if neither is better
4461 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4463 TypeSpec argument_type = a.Type;
4466 // If argument is an anonymous function
4468 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4470 // p and q are delegate types or expression tree types
4472 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4473 if (q.MemberDefinition != p.MemberDefinition) {
4478 // Uwrap delegate from Expression<T>
4480 q = TypeManager.GetTypeArguments (q)[0];
4481 p = TypeManager.GetTypeArguments (p)[0];
4484 var p_m = Delegate.GetInvokeMethod (p);
4485 var q_m = Delegate.GetInvokeMethod (q);
4488 // With identical parameter lists
4490 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4498 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4500 if (p.Kind == MemberKind.Void) {
4501 return q.Kind != MemberKind.Void ? 2 : 0;
4505 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4507 if (q.Kind == MemberKind.Void) {
4508 return p.Kind != MemberKind.Void ? 1: 0;
4511 var am = (AnonymousMethodExpression) a.Expr;
4514 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4515 // better conversion is performed between underlying types Y1 and Y2
4517 if (p.IsGenericTask || q.IsGenericTask) {
4518 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4519 q = q.TypeArguments[0];
4520 p = p.TypeArguments[0];
4526 // An inferred return type X exists for E in the context of that parameter list, and
4527 // the conversion from X to Y1 is better than the conversion from X to Y2
4529 argument_type = am.InferReturnType (ec, null, orig_q);
4530 if (argument_type == null) {
4531 // TODO: Can this be hit?
4535 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4536 argument_type = ec.BuiltinTypes.Object;
4540 if (argument_type == p)
4543 if (argument_type == q)
4547 // The parameters are identicial and return type is not void, use better type conversion
4548 // on return type to determine better one
4550 return BetterTypeConversion (ec, p, q);
4554 // 7.4.3.4 Better conversion from type
4556 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4558 if (p == null || q == null)
4559 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4561 switch (p.BuiltinType) {
4562 case BuiltinTypeSpec.Type.Int:
4563 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4566 case BuiltinTypeSpec.Type.Long:
4567 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4570 case BuiltinTypeSpec.Type.SByte:
4571 switch (q.BuiltinType) {
4572 case BuiltinTypeSpec.Type.Byte:
4573 case BuiltinTypeSpec.Type.UShort:
4574 case BuiltinTypeSpec.Type.UInt:
4575 case BuiltinTypeSpec.Type.ULong:
4579 case BuiltinTypeSpec.Type.Short:
4580 switch (q.BuiltinType) {
4581 case BuiltinTypeSpec.Type.UShort:
4582 case BuiltinTypeSpec.Type.UInt:
4583 case BuiltinTypeSpec.Type.ULong:
4587 case BuiltinTypeSpec.Type.Dynamic:
4588 // Dynamic is never better
4592 switch (q.BuiltinType) {
4593 case BuiltinTypeSpec.Type.Int:
4594 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4597 case BuiltinTypeSpec.Type.Long:
4598 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4601 case BuiltinTypeSpec.Type.SByte:
4602 switch (p.BuiltinType) {
4603 case BuiltinTypeSpec.Type.Byte:
4604 case BuiltinTypeSpec.Type.UShort:
4605 case BuiltinTypeSpec.Type.UInt:
4606 case BuiltinTypeSpec.Type.ULong:
4610 case BuiltinTypeSpec.Type.Short:
4611 switch (p.BuiltinType) {
4612 case BuiltinTypeSpec.Type.UShort:
4613 case BuiltinTypeSpec.Type.UInt:
4614 case BuiltinTypeSpec.Type.ULong:
4618 case BuiltinTypeSpec.Type.Dynamic:
4619 // Dynamic is never better
4623 // FIXME: handle lifted operators
4625 // TODO: this is expensive
4626 Expression p_tmp = new EmptyExpression (p);
4627 Expression q_tmp = new EmptyExpression (q);
4629 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4630 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4632 if (p_to_q && !q_to_p)
4635 if (q_to_p && !p_to_q)
4642 /// Determines "Better function" between candidate
4643 /// and the current best match
4646 /// Returns a boolean indicating :
4647 /// false if candidate ain't better
4648 /// true if candidate is better than the current best match
4650 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4651 MemberSpec best, AParametersCollection bparam, bool best_params)
4653 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4654 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4656 bool better_at_least_one = false;
4657 bool are_equivalent = true;
4658 int args_count = args == null ? 0 : args.Count;
4662 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4665 // Default arguments are ignored for better decision
4666 if (a.IsDefaultArgument)
4670 // When comparing named argument the parameter type index has to be looked up
4671 // in original parameter set (override version for virtual members)
4673 NamedArgument na = a as NamedArgument;
4675 int idx = cparam.GetParameterIndexByName (na.Name);
4676 ct = candidate_pd.Types[idx];
4677 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4678 ct = TypeManager.GetElementType (ct);
4680 idx = bparam.GetParameterIndexByName (na.Name);
4681 bt = best_pd.Types[idx];
4682 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4683 bt = TypeManager.GetElementType (bt);
4685 ct = candidate_pd.Types[c_idx];
4686 bt = best_pd.Types[b_idx];
4688 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4689 ct = TypeManager.GetElementType (ct);
4693 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4694 bt = TypeManager.GetElementType (bt);
4699 if (TypeSpecComparer.IsEqual (ct, bt))
4702 are_equivalent = false;
4703 int result = BetterExpressionConversion (ec, a, ct, bt);
4705 // for each argument, the conversion to 'ct' should be no worse than
4706 // the conversion to 'bt'.
4708 better_at_least_one = false;
4711 while (j < args_count && !args [j++].IsDefaultArgument) ;
4716 // for at least one argument, the conversion to 'ct' should be better than
4717 // the conversion to 'bt'.
4719 better_at_least_one = true;
4722 if (better_at_least_one)
4726 // LAMESPEC: Tie-breaking rules for not equivalent parameter types
4728 if (!are_equivalent) {
4730 // A candidate with no default parameters is still better when there
4731 // is no better expression conversion
4733 if (candidate_pd.Count < best_pd.Count) {
4734 if (!candidate_params && !candidate_pd.FixedParameters [j - j].HasDefaultValue) {
4737 } else if (candidate_pd.Count == best_pd.Count) {
4738 if (candidate_params)
4741 if (!candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.FixedParameters [j - 1].HasDefaultValue)
4744 if (candidate_pd.FixedParameters [j - 1].HasDefaultValue && best_pd.HasParams)
4752 // If candidate is applicable in its normal form and best has a params array and is applicable
4753 // only in its expanded form, then candidate is better
4755 if (candidate_params != best_params)
4756 return !candidate_params;
4759 // We have not reached end of parameters list due to params or used default parameters
4761 bool defaults_ambiguity = false;
4762 while (j < candidate_pd.Count && j < best_pd.Count) {
4763 var cand_param = candidate_pd.FixedParameters [j];
4764 var best_param = best_pd.FixedParameters [j];
4766 if (cand_param.HasDefaultValue != best_param.HasDefaultValue && (!candidate_pd.HasParams || !best_pd.HasParams))
4767 return cand_param.HasDefaultValue;
4769 defaults_ambiguity = true;
4770 if (candidate_pd.Count == best_pd.Count) {
4774 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4775 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4777 if (cand_param.HasDefaultValue) {
4786 // Neither is better when not all arguments are provided
4788 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4789 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4790 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4795 if (candidate_pd.Count != best_pd.Count) {
4796 if (defaults_ambiguity && best_pd.Count - 1 == j)
4797 return best_pd.HasParams;
4799 return candidate_pd.Count < best_pd.Count;
4803 // One is a non-generic method and second is a generic method, then non-generic is better
4805 if (best.IsGeneric != candidate.IsGeneric)
4806 return best.IsGeneric;
4809 // Both methods have the same number of parameters, and the parameters have equal types
4810 // Pick the "more specific" signature using rules over original (non-inflated) types
4812 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4813 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4815 bool specific_at_least_once = false;
4816 for (j = 0; j < args_count; ++j) {
4817 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4819 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4820 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4822 ct = candidate_def_pd.Types[j];
4823 bt = best_def_pd.Types[j];
4828 TypeSpec specific = MoreSpecific (ct, bt);
4832 specific_at_least_once = true;
4835 if (specific_at_least_once)
4841 static bool CheckInflatedArguments (MethodSpec ms)
4843 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4846 // Setup constraint checker for probing only
4847 ConstraintChecker cc = new ConstraintChecker (null);
4849 var mp = ms.Parameters.Types;
4850 for (int i = 0; i < mp.Length; ++i) {
4851 var type = mp[i] as InflatedTypeSpec;
4855 var targs = type.TypeArguments;
4856 if (targs.Length == 0)
4859 // TODO: Checking inflated MVAR arguments should be enough
4860 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4867 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4869 rc.Report.Error (1729, loc,
4870 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4871 type.GetSignatureForError (), argCount.ToString ());
4875 // Determines if the candidate method is applicable to the given set of arguments
4876 // There could be two different set of parameters for same candidate where one
4877 // is the closest override for default values and named arguments checks and second
4878 // one being the virtual base for the parameter types and modifiers.
4880 // A return value rates candidate method compatibility,
4882 // 0 = the best, int.MaxValue = the worst
4884 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)
4887 // Each step has allocated 10 values, it can overflow for
4888 // more than 10 arguments but that's ok as it's used for
4889 // better error reporting only
4891 const int ArgumentCountMismatch = 1000000000;
4892 const int NamedArgumentsMismatch = 100000000;
4893 const int DefaultArgumentMismatch = 10000000;
4894 const int UnexpectedTypeArguments = 1000000;
4895 const int TypeArgumentsMismatch = 100000;
4896 const int InflatedTypesMismatch = 10000;
4898 // Parameters of most-derived type used mainly for named and optional parameters
4899 var pd = pm.Parameters;
4901 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4902 // params modifier instead of most-derived type
4903 var cpd = ((IParametersMember) candidate).Parameters;
4904 int param_count = pd.Count;
4905 int optional_count = 0;
4907 Arguments orig_args = arguments;
4909 if (arg_count != param_count) {
4911 // No arguments expansion when doing exact match for delegates
4913 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4914 for (int i = 0; i < pd.Count; ++i) {
4915 if (pd.FixedParameters[i].HasDefaultValue) {
4916 optional_count = pd.Count - i;
4922 if (optional_count != 0) {
4923 // Readjust expected number when params used
4924 if (cpd.HasParams) {
4926 if (arg_count < param_count)
4928 } else if (arg_count > param_count) {
4929 int args_gap = System.Math.Abs (arg_count - param_count);
4930 return ArgumentCountMismatch + args_gap;
4931 } else if (arg_count < param_count - optional_count) {
4932 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4933 return ArgumentCountMismatch + args_gap;
4935 } else if (arg_count != param_count) {
4936 int args_gap = System.Math.Abs (arg_count - param_count);
4938 return ArgumentCountMismatch + args_gap;
4939 if (arg_count < param_count - 1)
4940 return ArgumentCountMismatch + args_gap;
4943 // Resize to fit optional arguments
4944 if (optional_count != 0) {
4945 if (arguments == null) {
4946 arguments = new Arguments (optional_count);
4948 // Have to create a new container, so the next run can do same
4949 var resized = new Arguments (param_count);
4950 resized.AddRange (arguments);
4951 arguments = resized;
4954 for (int i = arg_count; i < param_count; ++i)
4955 arguments.Add (null);
4959 if (arg_count > 0) {
4961 // Shuffle named arguments to the right positions if there are any
4963 if (arguments[arg_count - 1] is NamedArgument) {
4964 arg_count = arguments.Count;
4966 for (int i = 0; i < arg_count; ++i) {
4967 bool arg_moved = false;
4969 NamedArgument na = arguments[i] as NamedArgument;
4973 int index = pd.GetParameterIndexByName (na.Name);
4975 // Named parameter not found
4977 return NamedArgumentsMismatch - i;
4979 // already reordered
4984 if (index >= param_count) {
4985 // When using parameters which should not be available to the user
4986 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4989 arguments.Add (null);
4993 if (index == arg_count)
4994 return NamedArgumentsMismatch - i - 1;
4996 temp = arguments [index];
4998 // The slot has been taken by positional argument
4999 if (temp != null && !(temp is NamedArgument))
5004 arguments = arguments.MarkOrderedArgument (na);
5008 if (arguments == orig_args) {
5009 arguments = new Arguments (orig_args.Count);
5010 arguments.AddRange (orig_args);
5013 arguments[index] = arguments[i];
5014 arguments[i] = temp;
5021 arg_count = arguments.Count;
5023 } else if (arguments != null) {
5024 arg_count = arguments.Count;
5028 // Don't do any expensive checks when the candidate cannot succeed
5030 if (arg_count != param_count && !cpd.HasParams)
5031 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
5033 var dep = candidate.GetMissingDependencies ();
5035 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5040 // 1. Handle generic method using type arguments when specified or type inference
5043 var ms = candidate as MethodSpec;
5044 if (ms != null && ms.IsGeneric) {
5045 if (type_arguments != null) {
5046 var g_args_count = ms.Arity;
5047 if (g_args_count != type_arguments.Count)
5048 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5050 if (type_arguments.Arguments != null)
5051 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5054 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5055 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5056 // candidate was found use the set to report more details about what was wrong with lambda body.
5057 // The general idea is to distinguish between code errors and errors caused by
5058 // trial-and-error type inference
5060 if (lambda_conv_msgs == null) {
5061 for (int i = 0; i < arg_count; i++) {
5062 Argument a = arguments[i];
5066 var am = a.Expr as AnonymousMethodExpression;
5068 if (lambda_conv_msgs == null)
5069 lambda_conv_msgs = new SessionReportPrinter ();
5071 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5076 var ti = new TypeInference (arguments);
5077 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5080 return TypeArgumentsMismatch - ti.InferenceScore;
5083 // Clear any error messages when the result was success
5085 if (lambda_conv_msgs != null)
5086 lambda_conv_msgs.ClearSession ();
5088 if (i_args.Length != 0) {
5090 for (int i = 0; i < i_args.Length; ++i) {
5091 var ta = i_args [i];
5092 if (!ta.IsAccessible (ec))
5093 return TypeArgumentsMismatch - i;
5097 ms = ms.MakeGenericMethod (ec, i_args);
5102 // Type arguments constraints have to match for the method to be applicable
5104 if (!CheckInflatedArguments (ms)) {
5106 return InflatedTypesMismatch;
5110 // We have a generic return type and at same time the method is override which
5111 // means we have to also inflate override return type in case the candidate is
5112 // best candidate and override return type is different to base return type.
5114 // virtual Foo<T, object> with override Foo<T, dynamic>
5116 if (candidate != pm) {
5117 MethodSpec override_ms = (MethodSpec) pm;
5118 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5119 returnType = inflator.Inflate (returnType);
5121 returnType = ms.ReturnType;
5128 if (type_arguments != null)
5129 return UnexpectedTypeArguments;
5135 // 2. Each argument has to be implicitly convertible to method parameter
5137 Parameter.Modifier p_mod = 0;
5140 for (int i = 0; i < arg_count; i++) {
5141 Argument a = arguments[i];
5143 var fp = pd.FixedParameters[i];
5144 if (!fp.HasDefaultValue) {
5145 arguments = orig_args;
5146 return arg_count * 2 + 2;
5150 // Get the default value expression, we can use the same expression
5151 // if the type matches
5153 Expression e = fp.DefaultValue;
5155 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5157 // Restore for possible error reporting
5158 for (int ii = i; ii < arg_count; ++ii)
5159 arguments.RemoveAt (i);
5161 return (arg_count - i) * 2 + 1;
5165 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5167 // LAMESPEC: Attributes can be mixed together with build-in priority
5169 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5170 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5171 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5172 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5173 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5174 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5178 arguments[i] = new Argument (e, Argument.AType.Default);
5182 if (p_mod != Parameter.Modifier.PARAMS) {
5183 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5185 } else if (!params_expanded_form) {
5186 params_expanded_form = true;
5187 pt = ((ElementTypeSpec) pt).Element;
5193 if (!params_expanded_form) {
5194 if (a.IsExtensionType) {
5195 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5200 score = IsArgumentCompatible (ec, a, p_mod, pt);
5203 dynamicArgument = true;
5208 // It can be applicable in expanded form (when not doing exact match like for delegates)
5210 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5211 if (!params_expanded_form) {
5212 pt = ((ElementTypeSpec) pt).Element;
5216 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5219 params_expanded_form = true;
5220 dynamicArgument = true;
5221 } else if (score == 0 || arg_count > pd.Count) {
5222 params_expanded_form = true;
5227 if (params_expanded_form)
5229 return (arg_count - i) * 2 + score;
5234 // Restore original arguments for dynamic binder to keep the intention of original source code
5236 if (dynamicArgument)
5237 arguments = orig_args;
5242 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5244 if (e is Constant && e.Type == ptype)
5248 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5250 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5251 e = new MemberAccess (new MemberAccess (new MemberAccess (
5252 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5253 } else if (e is Constant) {
5255 // Handles int to int? conversions, DefaultParameterValue check
5257 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5261 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5264 return e.Resolve (ec);
5268 // Tests argument compatibility with the parameter
5269 // The possible return values are
5271 // 1 - modifier mismatch
5272 // 2 - type mismatch
5273 // -1 - dynamic binding required
5275 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5278 // Types have to be identical when ref or out modifer
5279 // is used and argument is not of dynamic type
5281 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5282 var arg_type = argument.Type;
5284 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5286 // Using dynamic for ref/out parameter can still succeed at runtime
5288 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5294 if (arg_type != parameter) {
5295 if (arg_type == InternalType.VarOutType)
5299 // Do full equality check after quick path
5301 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5303 // Using dynamic for ref/out parameter can still succeed at runtime
5305 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5313 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5317 // Use implicit conversion in all modes to return same candidates when the expression
5318 // is used as argument or delegate conversion
5320 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5321 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5328 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5330 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5332 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5335 var ac_p = p as ArrayContainer;
5337 var ac_q = q as ArrayContainer;
5341 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5342 if (specific == ac_p.Element)
5344 if (specific == ac_q.Element)
5346 } else if (p.IsGeneric && q.IsGeneric) {
5347 var pargs = TypeManager.GetTypeArguments (p);
5348 var qargs = TypeManager.GetTypeArguments (q);
5350 bool p_specific_at_least_once = false;
5351 bool q_specific_at_least_once = false;
5353 for (int i = 0; i < pargs.Length; i++) {
5354 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5355 if (specific == pargs[i])
5356 p_specific_at_least_once = true;
5357 if (specific == qargs[i])
5358 q_specific_at_least_once = true;
5361 if (p_specific_at_least_once && !q_specific_at_least_once)
5363 if (!p_specific_at_least_once && q_specific_at_least_once)
5371 // Find the best method from candidate list
5373 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5375 List<AmbiguousCandidate> ambiguous_candidates = null;
5377 MemberSpec best_candidate;
5378 Arguments best_candidate_args = null;
5379 bool best_candidate_params = false;
5380 bool best_candidate_dynamic = false;
5381 int best_candidate_rate;
5382 IParametersMember best_parameter_member = null;
5384 int args_count = args != null ? args.Count : 0;
5386 Arguments candidate_args = args;
5387 bool error_mode = false;
5388 MemberSpec invocable_member = null;
5389 int applicable_candidates = 0;
5392 best_candidate = null;
5393 best_candidate_rate = int.MaxValue;
5395 var type_members = members;
5397 for (int i = 0; i < type_members.Count; ++i) {
5398 var member = type_members[i];
5401 // Methods in a base class are not candidates if any method in a derived
5402 // class is applicable
5404 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5408 if (!member.IsAccessible (rc))
5411 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5414 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5415 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5420 IParametersMember pm = member as IParametersMember;
5423 // Will use it later to report ambiguity between best method and invocable member
5425 if (Invocation.IsMemberInvocable (member))
5426 invocable_member = member;
5432 // Overload resolution is looking for base member but using parameter names
5433 // and default values from the closest member. That means to do expensive lookup
5434 // for the closest override for virtual or abstract members
5436 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5437 var override_params = base_provider.GetOverrideMemberParameters (member);
5438 if (override_params != null)
5439 pm = override_params;
5443 // Check if the member candidate is applicable
5445 bool params_expanded_form = false;
5446 bool dynamic_argument = false;
5447 TypeSpec rt = pm.MemberType;
5448 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5450 if (lambda_conv_msgs != null)
5451 lambda_conv_msgs.EndSession ();
5454 // How does it score compare to others
5456 if (candidate_rate < best_candidate_rate) {
5458 // Fatal error (missing dependency), cannot continue
5459 if (candidate_rate < 0)
5462 applicable_candidates = 1;
5463 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5464 // Only parameterless methods are considered
5466 best_candidate_rate = candidate_rate;
5467 best_candidate = member;
5468 best_candidate_args = candidate_args;
5469 best_candidate_params = params_expanded_form;
5470 best_candidate_dynamic = dynamic_argument;
5471 best_parameter_member = pm;
5472 best_candidate_return_type = rt;
5474 } else if (candidate_rate == 0) {
5476 // The member look is done per type for most operations but sometimes
5477 // it's not possible like for binary operators overload because they
5478 // are unioned between 2 sides
5480 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5481 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5485 ++applicable_candidates;
5487 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5489 // We pack all interface members into top level type which makes the overload resolution
5490 // more complicated for interfaces. We compensate it by removing methods with same
5491 // signature when building the cache hence this path should not really be hit often
5494 // interface IA { void Foo (int arg); }
5495 // interface IB : IA { void Foo (params int[] args); }
5497 // IB::Foo is the best overload when calling IB.Foo (1)
5500 if (ambiguous_candidates != null) {
5501 foreach (var amb_cand in ambiguous_candidates) {
5502 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5511 ambiguous_candidates = null;
5514 // Is the new candidate better
5515 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5519 best_candidate = member;
5520 best_candidate_args = candidate_args;
5521 best_candidate_params = params_expanded_form;
5522 best_candidate_dynamic = dynamic_argument;
5523 best_parameter_member = pm;
5524 best_candidate_return_type = rt;
5526 // It's not better but any other found later could be but we are not sure yet
5527 if (ambiguous_candidates == null)
5528 ambiguous_candidates = new List<AmbiguousCandidate> ();
5530 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5534 // Restore expanded arguments
5535 candidate_args = args;
5537 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5540 // We've found exact match
5542 if (best_candidate_rate == 0)
5546 // Try extension methods lookup when no ordinary method match was found and provider enables it
5549 var emg = base_provider.LookupExtensionMethod (rc);
5551 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5553 best_candidate_extension_group = emg;
5554 return (T) (MemberSpec) emg.BestCandidate;
5559 // Don't run expensive error reporting mode for probing
5566 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5569 lambda_conv_msgs = null;
5574 // No best member match found, report an error
5576 if (best_candidate_rate != 0 || error_mode) {
5577 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5581 if (best_candidate_dynamic) {
5582 if (args[0].IsExtensionType) {
5583 rc.Report.Error (1973, loc,
5584 "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",
5585 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5589 // Check type constraints only when explicit type arguments are used
5591 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5592 MethodSpec bc = best_candidate as MethodSpec;
5593 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5594 ConstraintChecker cc = new ConstraintChecker (rc);
5595 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5599 BestCandidateIsDynamic = true;
5604 // These flags indicates we are running delegate probing conversion. No need to
5605 // do more expensive checks
5607 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5608 return (T) best_candidate;
5610 if (ambiguous_candidates != null) {
5612 // Now check that there are no ambiguities i.e the selected method
5613 // should be better than all the others
5615 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5616 var candidate = ambiguous_candidates [ix];
5618 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5619 var ambiguous = candidate.Member;
5620 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5621 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5622 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5623 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5624 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5627 return (T) best_candidate;
5632 if (invocable_member != null && !IsProbingOnly) {
5633 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5634 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5635 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5636 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5640 // And now check if the arguments are all
5641 // compatible, perform conversions if
5642 // necessary etc. and return if everything is
5645 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5648 if (best_candidate == null)
5652 // Don't run possibly expensive checks in probing mode
5654 if (!IsProbingOnly && !rc.IsInProbingMode) {
5656 // Check ObsoleteAttribute on the best method
5658 best_candidate.CheckObsoleteness (rc, loc);
5660 best_candidate.MemberDefinition.SetIsUsed ();
5663 args = best_candidate_args;
5664 return (T) best_candidate;
5667 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5669 return ResolveMember<MethodSpec> (rc, ref args);
5672 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5673 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5675 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5678 if (a.Type == InternalType.ErrorType)
5681 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5682 ec.Report.SymbolRelatedToPreviousError (method);
5683 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5684 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5685 TypeManager.CSharpSignature (method));
5688 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5689 TypeManager.CSharpSignature (method));
5690 } else if (IsDelegateInvoke) {
5691 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5692 DelegateType.GetSignatureForError ());
5694 ec.Report.SymbolRelatedToPreviousError (method);
5695 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5696 method.GetSignatureForError ());
5699 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5701 string index = (idx + 1).ToString ();
5702 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5703 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5704 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5705 index, Parameter.GetModifierSignature (a.Modifier));
5707 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5708 index, Parameter.GetModifierSignature (mod));
5710 string p1 = a.GetSignatureForError ();
5711 string p2 = paramType.GetSignatureForError ();
5714 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5715 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5718 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5719 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5720 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5723 ec.Report.Error (1503, a.Expr.Location,
5724 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5729 // We have failed to find exact match so we return error info about the closest match
5731 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5733 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5734 int arg_count = args == null ? 0 : args.Count;
5736 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5737 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5738 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5742 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5747 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5748 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5749 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5753 // For candidates which match on parameters count report more details about incorrect arguments
5756 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5757 // Reject any inaccessible member
5758 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5759 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5760 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5764 var ms = best_candidate as MethodSpec;
5765 if (ms != null && ms.IsGeneric) {
5766 bool constr_ok = true;
5767 if (ms.TypeArguments != null)
5768 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5770 if (ta_count == 0 && ms.TypeArguments == null) {
5771 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5775 rc.Report.Error (411, loc,
5776 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5777 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5784 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5790 // We failed to find any method with correct argument count, report best candidate
5792 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5795 if (best_candidate.Kind == MemberKind.Constructor) {
5796 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5797 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5798 } else if (IsDelegateInvoke) {
5799 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5800 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5801 DelegateType.GetSignatureForError (), arg_count.ToString ());
5803 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5804 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5805 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5806 name, arg_count.ToString ());
5810 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5812 var p = ((IParametersMember)best_candidate).Parameters;
5817 for (int i = p.Count - 1; i != 0; --i) {
5818 var fp = p.FixedParameters [i];
5819 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5829 foreach (var arg in args) {
5830 var na = arg as NamedArgument;
5834 if (na.Name == name) {
5843 return args.Count + 1 == pm.Parameters.Count;
5846 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5848 var pd = pm.Parameters;
5849 var cpd = ((IParametersMember) member).Parameters;
5850 var ptypes = cpd.Types;
5852 Parameter.Modifier p_mod = 0;
5854 int a_idx = 0, a_pos = 0;
5856 ArrayInitializer params_initializers = null;
5857 bool has_unsafe_arg = pm.MemberType.IsPointer;
5858 int arg_count = args == null ? 0 : args.Count;
5860 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5865 if (p_mod != Parameter.Modifier.PARAMS) {
5866 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5868 has_unsafe_arg |= pt.IsPointer;
5870 if (p_mod == Parameter.Modifier.PARAMS) {
5871 if (chose_params_expanded) {
5872 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5873 pt = TypeManager.GetElementType (pt);
5879 // Types have to be identical when ref or out modifer is used
5881 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5882 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5885 var arg_type = a.Type;
5889 if (arg_type == InternalType.VarOutType) {
5891 // Set underlying variable type based on parameter type
5893 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5897 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5901 NamedArgument na = a as NamedArgument;
5903 int name_index = pd.GetParameterIndexByName (na.Name);
5904 if (name_index < 0 || name_index >= pd.Count) {
5905 if (IsDelegateInvoke) {
5906 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5907 ec.Report.Error (1746, na.Location,
5908 "The delegate `{0}' does not contain a parameter named `{1}'",
5909 DelegateType.GetSignatureForError (), na.Name);
5911 ec.Report.SymbolRelatedToPreviousError (member);
5912 ec.Report.Error (1739, na.Location,
5913 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5914 TypeManager.CSharpSignature (member), na.Name);
5916 } else if (args[name_index] != a && args[name_index] != null) {
5917 if (IsDelegateInvoke)
5918 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5920 ec.Report.SymbolRelatedToPreviousError (member);
5922 ec.Report.Error (1744, na.Location,
5923 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5928 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5931 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5932 if (a.IsExtensionType) {
5933 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5934 // CS1061 but that still better than confusing CS0123
5935 var ma = new MemberAccess (a.Expr, member.Name, loc);
5936 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5938 custom_errors.NoArgumentMatch (ec, member);
5944 if (a.IsExtensionType) {
5945 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5948 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5950 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5953 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5960 // Convert params arguments to an array initializer
5962 if (params_initializers != null) {
5963 // we choose to use 'a.Expr' rather than 'conv' so that
5964 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5965 params_initializers.Add (a.Expr);
5966 args.RemoveAt (a_idx--);
5972 // Update the argument with the implicit conversion
5976 if (a_idx != arg_count) {
5978 // Convert all var out argument to error type for less confusing error reporting
5979 // when no matching overload is found
5981 for (; a_idx < arg_count; a_idx++) {
5982 var arg = args [a_idx];
5986 if (arg.Type == InternalType.VarOutType) {
5987 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5991 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5996 // Fill not provided arguments required by params modifier
5998 if (params_initializers == null && arg_count + 1 == pd.Count) {
6000 args = new Arguments (1);
6002 pt = ptypes[pd.Count - 1];
6003 pt = TypeManager.GetElementType (pt);
6004 has_unsafe_arg |= pt.IsPointer;
6005 params_initializers = new ArrayInitializer (0, loc);
6009 // Append an array argument with all params arguments
6011 if (params_initializers != null) {
6012 args.Add (new Argument (
6013 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
6017 if (has_unsafe_arg && !ec.IsUnsafe) {
6018 Expression.UnsafeError (ec, loc);
6022 // We could infer inaccesible type arguments
6024 if (type_arguments == null && member.IsGeneric) {
6025 var ms = (MethodSpec) member;
6026 foreach (var ta in ms.TypeArguments) {
6027 if (!ta.IsAccessible (ec)) {
6028 ec.Report.SymbolRelatedToPreviousError (ta);
6029 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6039 public class ConstantExpr : MemberExpr
6041 readonly ConstSpec constant;
6043 public ConstantExpr (ConstSpec constant, Location loc)
6045 this.constant = constant;
6049 public override string Name {
6050 get { throw new NotImplementedException (); }
6053 public override string KindName {
6054 get { return "constant"; }
6057 public override bool IsInstance {
6058 get { return !IsStatic; }
6061 public override bool IsStatic {
6062 get { return true; }
6065 protected override TypeSpec DeclaringType {
6066 get { return constant.DeclaringType; }
6069 public override Expression CreateExpressionTree (ResolveContext ec)
6071 throw new NotSupportedException ("ET");
6074 protected override Expression DoResolve (ResolveContext rc)
6076 ResolveInstanceExpression (rc, null);
6077 DoBestMemberChecks (rc, constant);
6079 if (rc.HasSet (ResolveContext.Options.NameOfScope)) {
6080 eclass = ExprClass.Value;
6081 type = constant.MemberType;
6085 var c = constant.GetConstant (rc);
6087 // Creates reference expression to the constant value
6088 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6091 public override void Emit (EmitContext ec)
6093 throw new NotSupportedException ();
6096 public override string GetSignatureForError ()
6098 return constant.GetSignatureForError ();
6101 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6103 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6108 // Fully resolved expression that references a Field
6110 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6112 protected FieldSpec spec;
6113 VariableInfo variable_info;
6115 LocalTemporary temp;
6118 protected FieldExpr (Location l)
6123 public FieldExpr (FieldSpec spec, Location loc)
6128 type = spec.MemberType;
6131 public FieldExpr (FieldBase fi, Location l)
6138 public override string Name {
6144 public bool IsHoisted {
6146 IVariableReference hv = InstanceExpression as IVariableReference;
6147 return hv != null && hv.IsHoisted;
6151 public override bool IsInstance {
6153 return !spec.IsStatic;
6157 public override bool IsStatic {
6159 return spec.IsStatic;
6163 public override string KindName {
6164 get { return "field"; }
6167 public FieldSpec Spec {
6173 protected override TypeSpec DeclaringType {
6175 return spec.DeclaringType;
6179 public VariableInfo VariableInfo {
6181 return variable_info;
6187 public override string GetSignatureForError ()
6189 return spec.GetSignatureForError ();
6192 public bool IsMarshalByRefAccess (ResolveContext rc)
6194 // Checks possible ldflda of field access expression
6195 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6196 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6197 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6200 public void SetHasAddressTaken ()
6202 IVariableReference vr = InstanceExpression as IVariableReference;
6204 vr.SetHasAddressTaken ();
6208 protected override void CloneTo (CloneContext clonectx, Expression target)
6210 var t = (FieldExpr) target;
6212 if (InstanceExpression != null)
6213 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6216 public override Expression CreateExpressionTree (ResolveContext ec)
6218 if (ConditionalAccess) {
6219 Error_NullShortCircuitInsideExpressionTree (ec);
6222 return CreateExpressionTree (ec, true);
6225 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6228 Expression instance;
6230 if (InstanceExpression == null) {
6231 instance = new NullLiteral (loc);
6232 } else if (convertInstance) {
6233 instance = InstanceExpression.CreateExpressionTree (ec);
6235 args = new Arguments (1);
6236 args.Add (new Argument (InstanceExpression));
6237 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6240 args = Arguments.CreateForExpressionTree (ec, null,
6242 CreateTypeOfExpression ());
6244 return CreateExpressionFactoryCall (ec, "Field", args);
6247 public Expression CreateTypeOfExpression ()
6249 return new TypeOfField (spec, loc);
6252 protected override Expression DoResolve (ResolveContext ec)
6254 spec.MemberDefinition.SetIsUsed ();
6256 return DoResolve (ec, null);
6259 Expression DoResolve (ResolveContext ec, Expression rhs)
6261 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6264 ResolveConditionalAccessReceiver (ec);
6266 if (ResolveInstanceExpression (ec, rhs)) {
6267 // Resolve the field's instance expression while flow analysis is turned
6268 // off: when accessing a field "a.b", we must check whether the field
6269 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6271 if (lvalue_instance) {
6272 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6274 Expression right_side =
6275 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6277 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6279 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6282 if (InstanceExpression == null)
6286 DoBestMemberChecks (ec, spec);
6288 if (conditional_access_receiver)
6289 ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, false);
6292 var fb = spec as FixedFieldSpec;
6293 IVariableReference var = InstanceExpression as IVariableReference;
6296 IFixedExpression fe = InstanceExpression as IFixedExpression;
6297 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6298 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6301 if (InstanceExpression.eclass != ExprClass.Variable) {
6302 ec.Report.SymbolRelatedToPreviousError (spec);
6303 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6304 TypeManager.GetFullNameSignature (spec));
6305 } else if (var != null && var.IsHoisted) {
6306 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6309 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6313 // Set flow-analysis variable info for struct member access. It will be check later
6314 // for precise error reporting
6316 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6317 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6320 if (conditional_access_receiver)
6321 type = LiftMemberType (ec, type);
6323 if (ConditionalAccess && InstanceExpression != null && InstanceExpression.IsNull)
6324 return Constant.CreateConstantFromValue (type, null, loc);
6326 eclass = ExprClass.Variable;
6330 public void SetFieldAssigned (FlowAnalysisContext fc)
6335 bool lvalue_instance = spec.DeclaringType.IsStruct;
6336 if (lvalue_instance) {
6337 var var = InstanceExpression as IVariableReference;
6338 if (var != null && var.VariableInfo != null) {
6339 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6343 var fe = InstanceExpression as FieldExpr;
6345 Expression instance;
6348 instance = fe.InstanceExpression;
6349 var fe_instance = instance as FieldExpr;
6350 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6351 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6352 var var = InstanceExpression as IVariableReference;
6353 if (var != null && var.VariableInfo == null) {
6354 var var_inst = instance as IVariableReference;
6355 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6356 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6360 if (fe_instance != null) {
6369 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6370 instance.FlowAnalysis (fc);
6372 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6373 InstanceExpression.FlowAnalysis (fc);
6377 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6379 // The return value is always null. Returning a value simplifies calling code.
6381 if (right_side == EmptyExpression.OutAccess) {
6383 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6384 GetSignatureForError ());
6386 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6387 GetSignatureForError ());
6393 if (right_side == EmptyExpression.LValueMemberAccess) {
6394 // Already reported as CS1648/CS1650
6398 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6400 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6401 GetSignatureForError ());
6403 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6404 GetSignatureForError ());
6410 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6411 GetSignatureForError ());
6413 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6414 GetSignatureForError ());
6420 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6422 if (HasConditionalAccess ())
6423 Error_NullPropagatingLValue (ec);
6425 if (spec is FixedFieldSpec) {
6426 // It could be much better error message but we want to be error compatible
6427 Error_ValueAssignment (ec, right_side);
6430 Expression e = DoResolve (ec, right_side);
6435 spec.MemberDefinition.SetIsAssigned ();
6437 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6438 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6439 ec.Report.Warning (420, 1, loc,
6440 "`{0}': A volatile field references will not be treated as volatile",
6441 spec.GetSignatureForError ());
6444 if (spec.IsReadOnly) {
6445 // InitOnly fields can only be assigned in constructors or initializers
6446 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6447 return Error_AssignToReadonly (ec, right_side);
6449 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6451 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6452 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6453 return Error_AssignToReadonly (ec, right_side);
6454 // static InitOnly fields cannot be assigned-to in an instance constructor
6455 if (IsStatic && !ec.IsStatic)
6456 return Error_AssignToReadonly (ec, right_side);
6457 // instance constructors can't modify InitOnly fields of other instances of the same type
6458 if (!IsStatic && !(InstanceExpression is This))
6459 return Error_AssignToReadonly (ec, right_side);
6463 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6464 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6465 ec.Report.Warning (197, 1, loc,
6466 "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",
6467 GetSignatureForError ());
6470 eclass = ExprClass.Variable;
6474 public override void FlowAnalysis (FlowAnalysisContext fc)
6476 var var = InstanceExpression as IVariableReference;
6478 var vi = var.VariableInfo;
6479 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6480 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6484 if (TypeSpec.IsValueType (InstanceExpression.Type)) {
6485 var le = SkipLeftValueTypeAccess (InstanceExpression);
6487 le.FlowAnalysis (fc);
6493 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
6495 base.FlowAnalysis (fc);
6497 if (conditional_access_receiver)
6498 fc.DefiniteAssignment = da;
6501 static Expression SkipLeftValueTypeAccess (Expression expr)
6503 if (!TypeSpec.IsValueType (expr.Type))
6506 if (expr is VariableReference)
6509 var fe = expr as FieldExpr;
6513 if (fe.InstanceExpression == null)
6516 return SkipLeftValueTypeAccess (fe.InstanceExpression);
6519 public override int GetHashCode ()
6521 return spec.GetHashCode ();
6524 public bool IsFixed {
6527 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6529 IVariableReference variable = InstanceExpression as IVariableReference;
6530 if (variable != null)
6531 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6533 IFixedExpression fe = InstanceExpression as IFixedExpression;
6534 return fe != null && fe.IsFixed;
6538 public override bool Equals (object obj)
6540 FieldExpr fe = obj as FieldExpr;
6544 if (spec != fe.spec)
6547 if (InstanceExpression == null || fe.InstanceExpression == null)
6550 return InstanceExpression.Equals (fe.InstanceExpression);
6553 public void Emit (EmitContext ec, bool leave_copy)
6555 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6559 ec.Emit (OpCodes.Volatile);
6561 ec.Emit (OpCodes.Ldsfld, spec);
6563 var ca = ec.ConditionalAccess;
6566 if (conditional_access_receiver)
6567 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6569 EmitInstance (ec, false);
6572 // Optimization for build-in types
6573 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6574 ec.EmitLoadFromPtr (type);
6576 var ff = spec as FixedFieldSpec;
6578 ec.Emit (OpCodes.Ldflda, spec);
6579 ec.Emit (OpCodes.Ldflda, ff.Element);
6582 ec.Emit (OpCodes.Volatile);
6584 ec.Emit (OpCodes.Ldfld, spec);
6588 if (conditional_access_receiver) {
6589 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6590 ec.ConditionalAccess = ca;
6595 ec.Emit (OpCodes.Dup);
6597 temp = new LocalTemporary (this.Type);
6603 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6605 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6606 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6611 if (ConditionalAccess)
6612 throw new NotImplementedException ("null operator assignment");
6614 if (has_await_source)
6615 source = source.EmitToField (ec);
6617 EmitInstance (ec, prepared);
6622 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6623 ec.Emit (OpCodes.Dup);
6625 temp = new LocalTemporary (this.Type);
6630 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6631 ec.Emit (OpCodes.Volatile);
6633 spec.MemberDefinition.SetIsAssigned ();
6636 ec.Emit (OpCodes.Stsfld, spec);
6638 ec.Emit (OpCodes.Stfld, spec);
6640 if (ec.NotifyEvaluatorOnStore) {
6642 throw new NotImplementedException ("instance field write");
6645 ec.Emit (OpCodes.Dup);
6647 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6658 // Emits store to field with prepared values on stack
6660 public void EmitAssignFromStack (EmitContext ec)
6663 ec.Emit (OpCodes.Stsfld, spec);
6665 ec.Emit (OpCodes.Stfld, spec);
6669 public override void Emit (EmitContext ec)
6674 public override void EmitSideEffect (EmitContext ec)
6676 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6678 if (is_volatile) // || is_marshal_by_ref ())
6679 base.EmitSideEffect (ec);
6682 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6684 if ((mode & AddressOp.Store) != 0)
6685 spec.MemberDefinition.SetIsAssigned ();
6686 if ((mode & AddressOp.Load) != 0)
6687 spec.MemberDefinition.SetIsUsed ();
6690 // Handle initonly fields specially: make a copy and then
6691 // get the address of the copy.
6694 if (spec.IsReadOnly){
6696 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6708 var temp = ec.GetTemporaryLocal (type);
6709 ec.Emit (OpCodes.Stloc, temp);
6710 ec.Emit (OpCodes.Ldloca, temp);
6716 ec.Emit (OpCodes.Ldsflda, spec);
6719 EmitInstance (ec, false);
6720 ec.Emit (OpCodes.Ldflda, spec);
6724 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6726 return MakeExpression (ctx);
6729 public override SLE.Expression MakeExpression (BuilderContext ctx)
6732 return base.MakeExpression (ctx);
6734 return SLE.Expression.Field (
6735 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6736 spec.GetMetaInfo ());
6740 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6742 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6748 // Expression that evaluates to a Property.
6750 // This is not an LValue because we need to re-write the expression. We
6751 // can not take data from the stack and store it.
6753 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6755 Arguments arguments;
6756 FieldExpr backing_field;
6758 public PropertyExpr (PropertySpec spec, Location l)
6761 best_candidate = spec;
6762 type = spec.MemberType;
6767 protected override Arguments Arguments {
6776 protected override TypeSpec DeclaringType {
6778 return best_candidate.DeclaringType;
6782 public override string Name {
6784 return best_candidate.Name;
6788 public bool IsAutoPropertyAccess {
6790 var prop = best_candidate.MemberDefinition as Property;
6791 return prop != null && prop.BackingField != null;
6795 public override bool IsInstance {
6801 public override bool IsStatic {
6803 return best_candidate.IsStatic;
6807 public override string KindName {
6808 get { return "property"; }
6811 public PropertySpec PropertyInfo {
6813 return best_candidate;
6819 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6821 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6824 var args_count = arguments == null ? 0 : arguments.Count;
6825 if (args_count != body.Parameters.Count && args_count == 0)
6828 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6829 mg.InstanceExpression = InstanceExpression;
6834 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6836 return new PropertyExpr (spec, loc) {
6842 public override Expression CreateExpressionTree (ResolveContext ec)
6844 if (ConditionalAccess) {
6845 Error_NullShortCircuitInsideExpressionTree (ec);
6849 if (IsSingleDimensionalArrayLength ()) {
6850 args = new Arguments (1);
6851 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6852 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6855 args = new Arguments (2);
6856 if (InstanceExpression == null)
6857 args.Add (new Argument (new NullLiteral (loc)));
6859 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6860 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6861 return CreateExpressionFactoryCall (ec, "Property", args);
6864 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6866 DoResolveLValue (rc, null);
6867 return new TypeOfMethod (Setter, loc);
6870 public override string GetSignatureForError ()
6872 return best_candidate.GetSignatureForError ();
6875 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6878 return base.MakeExpression (ctx);
6880 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6884 public override SLE.Expression MakeExpression (BuilderContext ctx)
6887 return base.MakeExpression (ctx);
6889 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6893 void Error_PropertyNotValid (ResolveContext ec)
6895 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6896 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6897 GetSignatureForError ());
6900 bool IsSingleDimensionalArrayLength ()
6902 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6905 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6906 return ac != null && ac.Rank == 1;
6909 public override void Emit (EmitContext ec, bool leave_copy)
6912 // Special case: length of single dimension array property is turned into ldlen
6914 if (IsSingleDimensionalArrayLength ()) {
6915 if (conditional_access_receiver) {
6916 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6919 EmitInstance (ec, false);
6921 ec.Emit (OpCodes.Ldlen);
6922 ec.Emit (OpCodes.Conv_I4);
6924 if (conditional_access_receiver) {
6925 ec.CloseConditionalAccess (type);
6931 base.Emit (ec, leave_copy);
6934 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6936 if (backing_field != null) {
6937 backing_field.EmitAssign (ec, source, false, false);
6942 LocalTemporary await_source_arg = null;
6944 if (isCompound && !(source is DynamicExpressionStatement)) {
6945 emitting_compound_assignment = true;
6948 if (has_await_arguments) {
6949 await_source_arg = new LocalTemporary (Type);
6950 await_source_arg.Store (ec);
6952 args = new Arguments (1);
6953 args.Add (new Argument (await_source_arg));
6956 temp = await_source_arg;
6959 has_await_arguments = false;
6964 ec.Emit (OpCodes.Dup);
6965 temp = new LocalTemporary (this.Type);
6970 args = arguments ?? new Arguments (1);
6974 temp = new LocalTemporary (this.Type);
6976 args.Add (new Argument (temp));
6978 args.Add (new Argument (source));
6982 emitting_compound_assignment = false;
6984 var call = new CallEmitter ();
6985 call.InstanceExpression = InstanceExpression;
6987 call.InstanceExpressionOnStack = true;
6989 if (ConditionalAccess) {
6990 call.ConditionalAccess = true;
6994 call.Emit (ec, Setter, args, loc);
6996 call.EmitStatement (ec, Setter, args, loc);
7003 if (await_source_arg != null) {
7004 await_source_arg.Release (ec);
7008 public override void FlowAnalysis (FlowAnalysisContext fc)
7010 var prop = best_candidate.MemberDefinition as Property;
7011 if (prop != null && prop.BackingField != null) {
7012 var var = InstanceExpression as IVariableReference;
7014 var vi = var.VariableInfo;
7015 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
7016 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
7020 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
7025 var da = conditional_access_receiver ? fc.BranchDefiniteAssignment () : null;
7027 base.FlowAnalysis (fc);
7029 if (conditional_access_receiver)
7030 fc.DefiniteAssignment = da;
7033 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
7035 eclass = ExprClass.PropertyAccess;
7037 if (best_candidate.IsNotCSharpCompatible) {
7038 Error_PropertyNotValid (rc);
7041 ResolveInstanceExpression (rc, right_side);
7043 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
7044 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
7045 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
7047 type = p.MemberType;
7051 DoBestMemberChecks (rc, best_candidate);
7053 // Handling of com-imported properties with any number of default property parameters
7054 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
7055 var p = best_candidate.Get.Parameters;
7056 arguments = new Arguments (p.Count);
7057 for (int i = 0; i < p.Count; ++i) {
7058 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7060 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
7061 var p = best_candidate.Set.Parameters;
7062 arguments = new Arguments (p.Count - 1);
7063 for (int i = 0; i < p.Count - 1; ++i) {
7064 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
7071 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7073 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7076 var prop = best_candidate.MemberDefinition as Property;
7077 if (prop == null || prop.Parent.PartialContainer != rc.CurrentMemberDefinition.Parent.PartialContainer) {
7078 var ps = MemberCache.FindMember (rc.CurrentType, MemberFilter.Property (best_candidate.Name, best_candidate.MemberType), BindingRestriction.DeclaredOnly) as PropertySpec;
7082 prop = (Property)ps.MemberDefinition;
7085 var spec = prop.BackingField;
7089 if (rc.IsStatic != spec.IsStatic)
7092 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7095 backing_field = new FieldExpr (prop.BackingField, loc);
7096 backing_field.ResolveLValue (rc, rhs);
7100 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7102 if (backing_field != null) {
7103 backing_field.SetFieldAssigned (fc);
7107 if (!IsAutoPropertyAccess)
7110 var prop = best_candidate.MemberDefinition as Property;
7111 if (prop != null && prop.BackingField != null) {
7112 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7113 if (lvalue_instance) {
7114 var var = InstanceExpression as IVariableReference;
7115 if (var != null && var.VariableInfo != null) {
7116 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7122 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7124 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7128 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7130 // getter and setter can be different for base calls
7131 MethodSpec getter, setter;
7132 protected T best_candidate;
7134 protected LocalTemporary temp;
7135 protected bool emitting_compound_assignment;
7136 protected bool has_await_arguments;
7138 protected PropertyOrIndexerExpr (Location l)
7145 protected abstract Arguments Arguments { get; set; }
7147 public MethodSpec Getter {
7156 public MethodSpec Setter {
7167 protected override Expression DoResolve (ResolveContext ec)
7169 if (eclass == ExprClass.Unresolved) {
7170 ResolveConditionalAccessReceiver (ec);
7172 var expr = OverloadResolve (ec, null);
7177 using (ec.With (ResolveContext.Options.DontSetConditionalAccessReceiver, conditional_access_receiver))
7178 return expr.Resolve (ec);
7181 if (conditional_access_receiver) {
7182 type = LiftMemberType (ec, type);
7186 if (!ResolveGetter (ec))
7192 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7194 if (HasConditionalAccess ())
7195 Error_NullPropagatingLValue (rc);
7197 if (right_side == EmptyExpression.OutAccess) {
7198 // TODO: best_candidate can be null at this point
7199 INamedBlockVariable variable = null;
7200 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7201 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7202 best_candidate.Name);
7204 right_side.DoResolveLValue (rc, this);
7209 if (eclass == ExprClass.Unresolved) {
7210 var expr = OverloadResolve (rc, right_side);
7215 return expr.ResolveLValue (rc, right_side);
7217 ResolveInstanceExpression (rc, right_side);
7220 if (!best_candidate.HasSet) {
7221 if (ResolveAutopropertyAssignment (rc, right_side))
7224 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7225 GetSignatureForError ());
7229 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7230 if (best_candidate.HasDifferentAccessibility) {
7231 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7232 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7233 GetSignatureForError ());
7235 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7236 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7240 if (best_candidate.HasDifferentAccessibility)
7241 CheckProtectedMemberAccess (rc, best_candidate.Set);
7243 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7247 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7249 var ca = ec.ConditionalAccess;
7250 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7252 call.Emit (ec, method, arguments, loc);
7254 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7255 ec.ConditionalAccess = ca;
7259 // Implements the IAssignMethod interface for assignments
7261 public virtual void Emit (EmitContext ec, bool leave_copy)
7263 var call = new CallEmitter ();
7264 call.ConditionalAccess = ConditionalAccess;
7265 call.InstanceExpression = InstanceExpression;
7266 if (has_await_arguments)
7267 call.HasAwaitArguments = true;
7269 call.DuplicateArguments = emitting_compound_assignment;
7271 if (conditional_access_receiver)
7272 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7274 call.Emit (ec, Getter, Arguments, loc);
7276 if (call.HasAwaitArguments) {
7277 InstanceExpression = call.InstanceExpression;
7278 Arguments = call.EmittedArguments;
7279 has_await_arguments = true;
7283 ec.Emit (OpCodes.Dup);
7284 temp = new LocalTemporary (Type);
7289 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7291 public override void Emit (EmitContext ec)
7296 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7298 has_await_arguments = true;
7303 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7305 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7307 bool ResolveGetter (ResolveContext rc)
7309 if (!best_candidate.HasGet) {
7310 if (InstanceExpression != EmptyExpression.Null) {
7311 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7312 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7313 best_candidate.GetSignatureForError ());
7316 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7317 if (best_candidate.HasDifferentAccessibility) {
7318 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7319 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7320 TypeManager.CSharpSignature (best_candidate));
7322 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7323 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7327 if (best_candidate.HasDifferentAccessibility) {
7328 CheckProtectedMemberAccess (rc, best_candidate.Get);
7331 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7335 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7342 /// Fully resolved expression that evaluates to an Event
7344 public class EventExpr : MemberExpr, IAssignMethod
7346 readonly EventSpec spec;
7349 public EventExpr (EventSpec spec, Location loc)
7357 protected override TypeSpec DeclaringType {
7359 return spec.DeclaringType;
7363 public override string Name {
7369 public override bool IsInstance {
7371 return !spec.IsStatic;
7375 public override bool IsStatic {
7377 return spec.IsStatic;
7381 public override string KindName {
7382 get { return "event"; }
7385 public MethodSpec Operator {
7393 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7396 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7398 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7399 if (spec.BackingField != null &&
7400 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7402 spec.MemberDefinition.SetIsUsed ();
7404 spec.CheckObsoleteness (ec, loc);
7406 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7407 Error_AssignmentEventOnly (ec);
7409 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7411 InstanceExpression = null;
7413 return ml.ResolveMemberAccess (ec, left, original);
7417 return base.ResolveMemberAccess (ec, left, original);
7420 public override Expression CreateExpressionTree (ResolveContext ec)
7422 throw new NotSupportedException ("ET");
7425 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7427 if (right_side == EmptyExpression.EventAddition) {
7428 op = spec.AccessorAdd;
7429 } else if (right_side == EmptyExpression.EventSubtraction) {
7430 op = spec.AccessorRemove;
7434 Error_AssignmentEventOnly (ec);
7438 if (HasConditionalAccess ())
7439 Error_NullPropagatingLValue (ec);
7441 op = CandidateToBaseOverride (ec, op);
7445 protected override Expression DoResolve (ResolveContext ec)
7447 eclass = ExprClass.EventAccess;
7448 type = spec.MemberType;
7450 ResolveInstanceExpression (ec, null);
7452 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7453 Error_AssignmentEventOnly (ec);
7456 DoBestMemberChecks (ec, spec);
7460 public override void Emit (EmitContext ec)
7462 throw new NotSupportedException ();
7463 //Error_CannotAssign ();
7466 #region IAssignMethod Members
7468 public void Emit (EmitContext ec, bool leave_copy)
7470 throw new NotImplementedException ();
7473 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7475 if (leave_copy || !isCompound)
7476 throw new NotImplementedException ("EventExpr::EmitAssign");
7478 Arguments args = new Arguments (1);
7479 args.Add (new Argument (source));
7481 // TODO: Wrong, needs receiver
7482 // if (NullShortCircuit) {
7483 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7486 var call = new CallEmitter ();
7487 call.InstanceExpression = InstanceExpression;
7488 call.ConditionalAccess = ConditionalAccess;
7489 call.EmitStatement (ec, op, args, loc);
7491 // if (NullShortCircuit)
7492 // ec.CloseConditionalAccess (null);
7497 void Error_AssignmentEventOnly (ResolveContext ec)
7499 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7500 ec.Report.Error (79, loc,
7501 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7502 GetSignatureForError ());
7504 ec.Report.Error (70, loc,
7505 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7506 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7510 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7512 name = name.Substring (0, name.LastIndexOf ('.'));
7513 base.Error_CannotCallAbstractBase (rc, name);
7516 public override string GetSignatureForError ()
7518 return TypeManager.CSharpSignature (spec);
7521 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7523 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7527 public class TemporaryVariableReference : VariableReference
7529 public class Declarator : Statement
7531 TemporaryVariableReference variable;
7533 public Declarator (TemporaryVariableReference variable)
7535 this.variable = variable;
7539 protected override void DoEmit (EmitContext ec)
7541 variable.li.CreateBuilder (ec);
7544 public override void Emit (EmitContext ec)
7546 // Don't create sequence point
7550 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7555 protected override void CloneTo (CloneContext clonectx, Statement target)
7563 public TemporaryVariableReference (LocalVariable li, Location loc)
7566 this.type = li.Type;
7570 public override bool IsLockedByStatement {
7578 public LocalVariable LocalInfo {
7584 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc, bool writeToSymbolFile = false)
7586 var li = LocalVariable.CreateCompilerGenerated (type, block, loc, writeToSymbolFile);
7587 return new TemporaryVariableReference (li, loc);
7590 protected override Expression DoResolve (ResolveContext ec)
7592 eclass = ExprClass.Variable;
7595 // Don't capture temporary variables except when using
7596 // state machine redirection and block yields
7598 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7599 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7600 ec.IsVariableCapturingRequired) {
7601 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7602 storey.CaptureLocalVariable (ec, li);
7608 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7610 return Resolve (ec);
7613 public override void Emit (EmitContext ec)
7615 li.CreateBuilder (ec);
7620 public void EmitAssign (EmitContext ec, Expression source)
7622 li.CreateBuilder (ec);
7624 EmitAssign (ec, source, false, false);
7627 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7629 return li.HoistedVariant;
7632 public override bool IsFixed {
7633 get { return true; }
7636 public override bool IsRef {
7637 get { return false; }
7640 public override string Name {
7641 get { throw new NotImplementedException (); }
7644 public override void SetHasAddressTaken ()
7646 throw new NotImplementedException ();
7649 protected override ILocalVariable Variable {
7653 public override VariableInfo VariableInfo {
7654 get { return null; }
7659 /// Handles `var' contextual keyword; var becomes a keyword only
7660 /// if no type called var exists in a variable scope
7662 class VarExpr : SimpleName
7664 public VarExpr (Location loc)
7669 public bool InferType (ResolveContext ec, Expression right_side)
7672 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7674 type = right_side.Type;
7675 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7676 ec.Report.Error (815, loc,
7677 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7678 type.GetSignatureForError ());
7679 type = InternalType.ErrorType;
7683 eclass = ExprClass.Variable;
7687 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7689 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7690 base.Error_TypeOrNamespaceNotFound (ec);
7692 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");