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,
827 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
828 // `qualifier_type' or null to lookup members in the current class.
830 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
832 var members = MemberCache.FindMembers (queried_type, name, false);
838 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
842 if (members [0].DeclaringType.BaseType == null)
845 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
846 } while (members != null);
851 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
853 MemberSpec non_method = null;
854 MemberSpec ambig_non_method = null;
856 for (int i = 0; i < members.Count; ++i) {
857 var member = members [i];
859 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
860 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
863 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
866 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
870 if (!member.IsAccessible (rc))
874 // With runtime binder we can have a situation where queried type is inaccessible
875 // because it came via dynamic object, the check about inconsisted accessibility
876 // had no effect as the type was unknown during compilation
879 // private class N { }
881 // public dynamic Foo ()
887 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
891 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
892 if (member is MethodSpec) {
894 // Interface members that are hidden by class members are removed from the set. This
895 // step only has an effect if T is a type parameter and T has both an effective base
896 // class other than object and a non-empty effective interface set
898 var tps = queried_type as TypeParameterSpec;
899 if (tps != null && tps.HasTypeConstraint)
900 members = RemoveHiddenTypeParameterMethods (members);
902 return new MethodGroupExpr (members, queried_type, loc);
905 if (!Invocation.IsMemberInvocable (member))
909 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
911 } else if (!errorMode && !member.IsNotCSharpCompatible) {
913 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
914 // T has both an effective base class other than object and a non-empty effective interface set.
916 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
918 var tps = queried_type as TypeParameterSpec;
919 if (tps != null && tps.HasTypeConstraint) {
920 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
923 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
929 ambig_non_method = member;
933 if (non_method != null) {
934 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
935 var report = rc.Module.Compiler.Report;
936 report.SymbolRelatedToPreviousError (non_method);
937 report.SymbolRelatedToPreviousError (ambig_non_method);
938 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
939 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
942 if (non_method is MethodSpec)
943 return new MethodGroupExpr (members, queried_type, loc);
945 return ExprClassFromMemberInfo (non_method, loc);
951 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
953 if (members.Count < 2)
957 // If M is a method, then all non-method members declared in an interface declaration
958 // are removed from the set, and all methods with the same signature as M declared in
959 // an interface declaration are removed from the set
963 for (int i = 0; i < members.Count; ++i) {
964 var method = members[i] as MethodSpec;
965 if (method == null) {
968 members = new List<MemberSpec> (members);
971 members.RemoveAt (i--);
975 if (!method.DeclaringType.IsInterface)
978 for (int ii = 0; ii < members.Count; ++ii) {
979 var candidate = members[ii] as MethodSpec;
980 if (candidate == null || !candidate.DeclaringType.IsClass)
983 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
986 if (!AParametersCollection.HasSameParameterDefaults (candidate.Parameters, method.Parameters))
991 members = new List<MemberSpec> (members);
994 members.RemoveAt (i--);
1002 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1004 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1007 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1009 throw new NotImplementedException ();
1012 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1014 if (t == InternalType.ErrorType)
1017 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1018 oper, t.GetSignatureForError ());
1021 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1023 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1026 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1028 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1031 protected void Error_NullPropagatingLValue (ResolveContext rc)
1033 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1036 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1041 // Special version of flow analysis for expressions which can return different
1042 // on-true and on-false result. Used by &&, ||, ?: expressions
1044 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1047 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1051 /// Returns an expression that can be used to invoke operator true
1052 /// on the expression if it exists.
1054 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1056 return GetOperatorTrueOrFalse (ec, e, true, loc);
1060 /// Returns an expression that can be used to invoke operator false
1061 /// on the expression if it exists.
1063 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1065 return GetOperatorTrueOrFalse (ec, e, false, loc);
1068 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1070 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1072 if (type.IsNullableType)
1073 type = Nullable.NullableInfo.GetUnderlyingType (type);
1075 var methods = MemberCache.GetUserOperator (type, op, false);
1076 if (methods == null)
1079 Arguments arguments = new Arguments (1);
1080 arguments.Add (new Argument (e));
1082 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1083 var oper = res.ResolveOperator (ec, ref arguments);
1088 return new UserOperatorCall (oper, arguments, null, loc);
1091 public virtual string ExprClassName
1095 case ExprClass.Unresolved:
1096 return "Unresolved";
1097 case ExprClass.Value:
1099 case ExprClass.Variable:
1101 case ExprClass.Namespace:
1103 case ExprClass.Type:
1105 case ExprClass.MethodGroup:
1106 return "method group";
1107 case ExprClass.PropertyAccess:
1108 return "property access";
1109 case ExprClass.EventAccess:
1110 return "event access";
1111 case ExprClass.IndexerAccess:
1112 return "indexer access";
1113 case ExprClass.Nothing:
1115 case ExprClass.TypeParameter:
1116 return "type parameter";
1118 throw new Exception ("Should not happen");
1123 /// Reports that we were expecting `expr' to be of class `expected'
1125 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1127 var name = memberExpr.GetSignatureForError ();
1129 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1132 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1134 string [] valid = new string [4];
1137 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1138 valid [count++] = "variable";
1139 valid [count++] = "value";
1142 if ((flags & ResolveFlags.Type) != 0)
1143 valid [count++] = "type";
1145 if ((flags & ResolveFlags.MethodGroup) != 0)
1146 valid [count++] = "method group";
1149 valid [count++] = "unknown";
1151 StringBuilder sb = new StringBuilder (valid [0]);
1152 for (int i = 1; i < count - 1; i++) {
1154 sb.Append (valid [i]);
1157 sb.Append ("' or `");
1158 sb.Append (valid [count - 1]);
1161 ec.Report.Error (119, loc,
1162 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1165 public static void UnsafeError (ResolveContext ec, Location loc)
1167 UnsafeError (ec.Report, loc);
1170 public static void UnsafeError (Report Report, Location loc)
1172 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1176 // Converts `source' to an int, uint, long or ulong.
1178 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1180 var btypes = ec.BuiltinTypes;
1182 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1183 Arguments args = new Arguments (1);
1184 args.Add (new Argument (source));
1185 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1188 Expression converted;
1190 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1191 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1192 if (converted == null)
1193 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1194 if (converted == null)
1195 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1196 if (converted == null)
1197 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1199 if (converted == null) {
1200 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1209 // Only positive constants are allowed at compile time
1211 Constant c = converted as Constant;
1212 if (c != null && c.IsNegative)
1213 Error_NegativeArrayIndex (ec, source.loc);
1215 // No conversion needed to array index
1216 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1219 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1222 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1224 if (args.Count != 1){
1225 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1230 if (arg is NamedArgument)
1231 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1233 var index = arg.Expr.Resolve (rc);
1237 index = ConvertExpressionToArrayIndex (rc, index, true);
1239 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1240 return new Indirection (p, loc);
1244 // Derived classes implement this method by cloning the fields that
1245 // could become altered during the Resolve stage
1247 // Only expressions that are created for the parser need to implement
1250 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1252 throw new NotImplementedException (
1254 "CloneTo not implemented for expression {0}", this.GetType ()));
1258 // Clones an expression created by the parser.
1260 // We only support expressions created by the parser so far, not
1261 // expressions that have been resolved (many more classes would need
1262 // to implement CloneTo).
1264 // This infrastructure is here merely for Lambda expressions which
1265 // compile the same code using different type values for the same
1266 // arguments to find the correct overload
1268 public virtual Expression Clone (CloneContext clonectx)
1270 Expression cloned = (Expression) MemberwiseClone ();
1271 CloneTo (clonectx, cloned);
1277 // Implementation of expression to expression tree conversion
1279 public abstract Expression CreateExpressionTree (ResolveContext ec);
1281 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1283 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1286 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1288 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1291 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1293 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1296 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1298 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1302 return new TypeExpression (t, loc);
1306 // Implemented by all expressions which support conversion from
1307 // compiler expression to invokable runtime expression. Used by
1308 // dynamic C# binder.
1310 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1312 throw new NotImplementedException ("MakeExpression for " + GetType ());
1315 public virtual object Accept (StructuralVisitor visitor)
1317 return visitor.Visit (this);
1322 /// This is just a base class for expressions that can
1323 /// appear on statements (invocations, object creation,
1324 /// assignments, post/pre increment and decrement). The idea
1325 /// being that they would support an extra Emition interface that
1326 /// does not leave a result on the stack.
1328 public abstract class ExpressionStatement : Expression
1330 public virtual void MarkReachable (Reachability rc)
1334 public ExpressionStatement ResolveStatement (BlockContext ec)
1336 Expression e = Resolve (ec);
1340 ExpressionStatement es = e as ExpressionStatement;
1341 if (es == null || e is AnonymousMethodBody)
1342 Error_InvalidExpressionStatement (ec);
1345 // This is quite expensive warning, try to limit the damage
1347 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1348 WarningAsyncWithoutWait (ec, e);
1354 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1356 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1357 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1362 // Need to do full resolve because GetAwaiter can be extension method
1363 // available only in this context
1365 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1369 var arguments = new Arguments (0);
1370 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1375 // Use same check rules as for real await
1377 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1378 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1381 bc.Report.Warning (4014, 1, e.Location,
1382 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1386 var inv = e as Invocation;
1387 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1388 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1389 bc.Report.Warning (4014, 1, e.Location,
1390 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1396 /// Requests the expression to be emitted in a `statement'
1397 /// context. This means that no new value is left on the
1398 /// stack after invoking this method (constrasted with
1399 /// Emit that will always leave a value on the stack).
1401 public abstract void EmitStatement (EmitContext ec);
1403 public override void EmitSideEffect (EmitContext ec)
1410 /// This kind of cast is used to encapsulate the child
1411 /// whose type is child.Type into an expression that is
1412 /// reported to return "return_type". This is used to encapsulate
1413 /// expressions which have compatible types, but need to be dealt
1414 /// at higher levels with.
1416 /// For example, a "byte" expression could be encapsulated in one
1417 /// of these as an "unsigned int". The type for the expression
1418 /// would be "unsigned int".
1421 public abstract class TypeCast : Expression
1423 protected readonly Expression child;
1425 protected TypeCast (Expression child, TypeSpec return_type)
1427 eclass = child.eclass;
1428 loc = child.Location;
1433 public Expression Child {
1439 public override bool ContainsEmitWithAwait ()
1441 return child.ContainsEmitWithAwait ();
1444 public override Expression CreateExpressionTree (ResolveContext ec)
1446 Arguments args = new Arguments (2);
1447 args.Add (new Argument (child.CreateExpressionTree (ec)));
1448 args.Add (new Argument (new TypeOf (type, loc)));
1450 if (type.IsPointer || child.Type.IsPointer)
1451 Error_PointerInsideExpressionTree (ec);
1453 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1456 protected override Expression DoResolve (ResolveContext ec)
1458 // This should never be invoked, we are born in fully
1459 // initialized state.
1464 public override void Emit (EmitContext ec)
1469 public override void FlowAnalysis (FlowAnalysisContext fc)
1471 child.FlowAnalysis (fc);
1474 public override SLE.Expression MakeExpression (BuilderContext ctx)
1477 return base.MakeExpression (ctx);
1479 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1480 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1481 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1485 protected override void CloneTo (CloneContext clonectx, Expression t)
1490 public override bool IsNull {
1491 get { return child.IsNull; }
1495 public class EmptyCast : TypeCast {
1496 EmptyCast (Expression child, TypeSpec target_type)
1497 : base (child, target_type)
1501 public static Expression Create (Expression child, TypeSpec type)
1503 Constant c = child as Constant;
1505 var enum_constant = c as EnumConstant;
1506 if (enum_constant != null)
1507 c = enum_constant.Child;
1509 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1513 var res = c.ConvertImplicitly (type);
1519 EmptyCast e = child as EmptyCast;
1521 return new EmptyCast (e.child, type);
1523 return new EmptyCast (child, type);
1526 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1528 child.EmitBranchable (ec, label, on_true);
1531 public override void EmitSideEffect (EmitContext ec)
1533 child.EmitSideEffect (ec);
1538 // Used for predefined type user operator (no obsolete check, etc.)
1540 public class OperatorCast : TypeCast
1542 readonly MethodSpec conversion_operator;
1544 public OperatorCast (Expression expr, TypeSpec target_type)
1545 : this (expr, target_type, target_type, false)
1549 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1550 : this (expr, target_type, target_type, find_explicit)
1554 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1555 : base (expr, returnType)
1557 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1558 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1561 foreach (MethodSpec oper in mi) {
1562 if (oper.ReturnType != returnType)
1565 if (oper.Parameters.Types[0] == expr.Type) {
1566 conversion_operator = oper;
1572 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1573 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1576 public override void Emit (EmitContext ec)
1579 ec.Emit (OpCodes.Call, conversion_operator);
1584 // Constant specialization of EmptyCast.
1585 // We need to special case this since an empty cast of
1586 // a constant is still a constant.
1588 public class EmptyConstantCast : Constant
1590 public readonly Constant child;
1592 public EmptyConstantCast (Constant child, TypeSpec type)
1593 : base (child.Location)
1596 throw new ArgumentNullException ("child");
1599 this.eclass = child.eclass;
1603 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1605 if (child.Type == target_type)
1608 // FIXME: check that 'type' can be converted to 'target_type' first
1609 return child.ConvertExplicitly (in_checked_context, target_type);
1612 public override Expression CreateExpressionTree (ResolveContext ec)
1614 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1615 child.CreateExpressionTree (ec),
1616 new TypeOf (type, loc));
1619 Error_PointerInsideExpressionTree (ec);
1621 return CreateExpressionFactoryCall (ec, "Convert", args);
1624 public override bool IsDefaultValue {
1625 get { return child.IsDefaultValue; }
1628 public override bool IsNegative {
1629 get { return child.IsNegative; }
1632 public override bool IsNull {
1633 get { return child.IsNull; }
1636 public override bool IsOneInteger {
1637 get { return child.IsOneInteger; }
1640 public override bool IsSideEffectFree {
1642 return child.IsSideEffectFree;
1646 public override bool IsZeroInteger {
1647 get { return child.IsZeroInteger; }
1650 public override void Emit (EmitContext ec)
1655 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1657 child.EmitBranchable (ec, label, on_true);
1659 // Only to make verifier happy
1660 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1661 ec.Emit (OpCodes.Unbox_Any, type);
1664 public override void EmitSideEffect (EmitContext ec)
1666 child.EmitSideEffect (ec);
1669 public override object GetValue ()
1671 return child.GetValue ();
1674 public override string GetValueAsLiteral ()
1676 return child.GetValueAsLiteral ();
1679 public override long GetValueAsLong ()
1681 return child.GetValueAsLong ();
1684 public override Constant ConvertImplicitly (TypeSpec target_type)
1686 if (type == target_type)
1689 // FIXME: Do we need to check user conversions?
1690 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1693 return child.ConvertImplicitly (target_type);
1698 /// This class is used to wrap literals which belong inside Enums
1700 public class EnumConstant : Constant
1702 public Constant Child;
1704 public EnumConstant (Constant child, TypeSpec enum_type)
1705 : base (child.Location)
1709 this.eclass = ExprClass.Value;
1710 this.type = enum_type;
1713 protected EnumConstant (Location loc)
1718 public override void Emit (EmitContext ec)
1723 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1725 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1728 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1730 Child.EmitBranchable (ec, label, on_true);
1733 public override void EmitSideEffect (EmitContext ec)
1735 Child.EmitSideEffect (ec);
1738 public override string GetSignatureForError()
1740 return Type.GetSignatureForError ();
1743 public override object GetValue ()
1745 return Child.GetValue ();
1749 public override object GetTypedValue ()
1752 // The method can be used in dynamic context only (on closed types)
1754 // System.Enum.ToObject cannot be called on dynamic types
1755 // EnumBuilder has to be used, but we cannot use EnumBuilder
1756 // because it does not properly support generics
1758 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1762 public override string GetValueAsLiteral ()
1764 return Child.GetValueAsLiteral ();
1767 public override long GetValueAsLong ()
1769 return Child.GetValueAsLong ();
1772 public EnumConstant Increment()
1774 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1777 public override bool IsDefaultValue {
1779 return Child.IsDefaultValue;
1783 public override bool IsSideEffectFree {
1785 return Child.IsSideEffectFree;
1789 public override bool IsZeroInteger {
1790 get { return Child.IsZeroInteger; }
1793 public override bool IsNegative {
1795 return Child.IsNegative;
1799 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1801 if (Child.Type == target_type)
1804 return Child.ConvertExplicitly (in_checked_context, target_type);
1807 public override Constant ConvertImplicitly (TypeSpec type)
1809 if (this.type == type) {
1813 if (!Convert.ImplicitStandardConversionExists (this, type)){
1817 return Child.ConvertImplicitly (type);
1822 /// This kind of cast is used to encapsulate Value Types in objects.
1824 /// The effect of it is to box the value type emitted by the previous
1827 public class BoxedCast : TypeCast {
1829 public BoxedCast (Expression expr, TypeSpec target_type)
1830 : base (expr, target_type)
1832 eclass = ExprClass.Value;
1835 protected override Expression DoResolve (ResolveContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1845 // Only boxing to object type is supported
1846 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1847 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1851 enc.Encode (child.Type);
1852 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1855 public override void Emit (EmitContext ec)
1859 ec.Emit (OpCodes.Box, child.Type);
1862 public override void EmitSideEffect (EmitContext ec)
1864 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1865 // so, we need to emit the box+pop instructions in most cases
1866 if (child.Type.IsStruct &&
1867 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1868 child.EmitSideEffect (ec);
1870 base.EmitSideEffect (ec);
1874 public class UnboxCast : TypeCast {
1875 public UnboxCast (Expression expr, TypeSpec return_type)
1876 : base (expr, return_type)
1880 protected override Expression DoResolve (ResolveContext ec)
1882 // This should never be invoked, we are born in fully
1883 // initialized state.
1888 public override void Emit (EmitContext ec)
1892 ec.Emit (OpCodes.Unbox_Any, type);
1897 /// This is used to perform explicit numeric conversions.
1899 /// Explicit numeric conversions might trigger exceptions in a checked
1900 /// context, so they should generate the conv.ovf opcodes instead of
1903 public class ConvCast : TypeCast {
1904 public enum Mode : byte {
1905 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1907 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1908 U2_I1, U2_U1, U2_I2, U2_CH,
1909 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1910 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1911 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1912 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1913 CH_I1, CH_U1, CH_I2,
1914 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1915 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1921 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1922 : base (child, return_type)
1927 protected override Expression DoResolve (ResolveContext ec)
1929 // This should never be invoked, we are born in fully
1930 // initialized state.
1935 public override string ToString ()
1937 return String.Format ("ConvCast ({0}, {1})", mode, child);
1940 public override void Emit (EmitContext ec)
1946 public static void Emit (EmitContext ec, Mode mode)
1948 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1950 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1951 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1952 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1953 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1954 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1957 case Mode.U1_CH: /* nothing */ break;
1959 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1960 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1963 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1964 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1966 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1967 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1968 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1969 case Mode.U2_CH: /* nothing */ break;
1971 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1972 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1973 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1974 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1975 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1977 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1979 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1980 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1981 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1982 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1983 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1984 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1986 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1987 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1988 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1989 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1991 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1992 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1993 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1996 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1997 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1998 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1999 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2000 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
2001 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
2002 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2003 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2004 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2006 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2007 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2008 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2010 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2011 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2012 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2013 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2014 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2015 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2016 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2017 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2018 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2021 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2022 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2023 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2024 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2025 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2026 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2027 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2028 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2029 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2031 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2035 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2036 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2037 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2038 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2039 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2042 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2045 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2046 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2048 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2049 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2051 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2052 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2053 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2054 case Mode.U2_CH: /* nothing */ break;
2056 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2057 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2058 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2059 case Mode.I4_U4: /* nothing */ break;
2060 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2061 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2062 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2064 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2065 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2066 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2067 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2068 case Mode.U4_I4: /* nothing */ break;
2069 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2071 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2072 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2073 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2074 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2076 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2077 case Mode.I8_U8: /* nothing */ break;
2078 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2079 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2081 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2082 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2083 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2084 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2085 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2086 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2087 case Mode.U8_I8: /* nothing */ break;
2088 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2089 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2091 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2092 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2093 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2096 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2097 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2098 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2099 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2100 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2101 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2102 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2103 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2106 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2107 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2108 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2109 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2110 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2111 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2112 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2113 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2114 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2116 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2122 class OpcodeCast : TypeCast
2126 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2127 : base (child, return_type)
2132 protected override Expression DoResolve (ResolveContext ec)
2134 // This should never be invoked, we are born in fully
2135 // initialized state.
2140 public override void Emit (EmitContext ec)
2146 public TypeSpec UnderlyingType {
2147 get { return child.Type; }
2152 // Opcode casts expression with 2 opcodes but only
2153 // single expression tree node
2155 class OpcodeCastDuplex : OpcodeCast
2157 readonly OpCode second;
2159 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2160 : base (child, returnType, first)
2162 this.second = second;
2165 public override void Emit (EmitContext ec)
2173 /// This kind of cast is used to encapsulate a child and cast it
2174 /// to the class requested
2176 public sealed class ClassCast : TypeCast {
2177 readonly bool forced;
2179 public ClassCast (Expression child, TypeSpec return_type)
2180 : base (child, return_type)
2184 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2185 : base (child, return_type)
2187 this.forced = forced;
2190 public override void Emit (EmitContext ec)
2194 bool gen = TypeManager.IsGenericParameter (child.Type);
2196 ec.Emit (OpCodes.Box, child.Type);
2198 if (type.IsGenericParameter) {
2199 ec.Emit (OpCodes.Unbox_Any, type);
2206 ec.Emit (OpCodes.Castclass, type);
2211 // Created during resolving pahse when an expression is wrapped or constantified
2212 // and original expression can be used later (e.g. for expression trees)
2214 public class ReducedExpression : Expression
2216 public sealed class ReducedConstantExpression : EmptyConstantCast
2218 readonly Expression orig_expr;
2220 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2221 : base (expr, expr.Type)
2223 this.orig_expr = orig_expr;
2226 public Expression OriginalExpression {
2232 public override Constant ConvertImplicitly (TypeSpec target_type)
2234 Constant c = base.ConvertImplicitly (target_type);
2236 c = new ReducedConstantExpression (c, orig_expr);
2241 public override Expression CreateExpressionTree (ResolveContext ec)
2243 return orig_expr.CreateExpressionTree (ec);
2246 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2248 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2250 c = new ReducedConstantExpression (c, orig_expr);
2254 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2257 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2259 if (orig_expr is Conditional)
2260 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2262 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2266 sealed class ReducedExpressionStatement : ExpressionStatement
2268 readonly Expression orig_expr;
2269 readonly ExpressionStatement stm;
2271 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2273 this.orig_expr = orig;
2275 this.eclass = stm.eclass;
2276 this.type = stm.Type;
2278 this.loc = orig.Location;
2281 public override bool ContainsEmitWithAwait ()
2283 return stm.ContainsEmitWithAwait ();
2286 public override Expression CreateExpressionTree (ResolveContext ec)
2288 return orig_expr.CreateExpressionTree (ec);
2291 protected override Expression DoResolve (ResolveContext ec)
2296 public override void Emit (EmitContext ec)
2301 public override void EmitStatement (EmitContext ec)
2303 stm.EmitStatement (ec);
2306 public override void FlowAnalysis (FlowAnalysisContext fc)
2308 stm.FlowAnalysis (fc);
2312 readonly Expression expr, orig_expr;
2314 private ReducedExpression (Expression expr, Expression orig_expr)
2317 this.eclass = expr.eclass;
2318 this.type = expr.Type;
2319 this.orig_expr = orig_expr;
2320 this.loc = orig_expr.Location;
2325 public override bool IsSideEffectFree {
2327 return expr.IsSideEffectFree;
2331 public Expression OriginalExpression {
2339 public override bool ContainsEmitWithAwait ()
2341 return expr.ContainsEmitWithAwait ();
2345 // Creates fully resolved expression switcher
2347 public static Constant Create (Constant expr, Expression original_expr)
2349 if (expr.eclass == ExprClass.Unresolved)
2350 throw new ArgumentException ("Unresolved expression");
2352 return new ReducedConstantExpression (expr, original_expr);
2355 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2357 return new ReducedExpressionStatement (s, orig);
2360 public static Expression Create (Expression expr, Expression original_expr)
2362 return Create (expr, original_expr, true);
2366 // Creates unresolved reduce expression. The original expression has to be
2367 // already resolved. Created expression is constant based based on `expr'
2368 // value unless canBeConstant is used
2370 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2372 if (canBeConstant) {
2373 Constant c = expr as Constant;
2375 return Create (c, original_expr);
2378 ExpressionStatement s = expr as ExpressionStatement;
2380 return Create (s, original_expr);
2382 if (expr.eclass == ExprClass.Unresolved)
2383 throw new ArgumentException ("Unresolved expression");
2385 return new ReducedExpression (expr, original_expr);
2388 public override Expression CreateExpressionTree (ResolveContext ec)
2390 return orig_expr.CreateExpressionTree (ec);
2393 protected override Expression DoResolve (ResolveContext ec)
2398 public override void Emit (EmitContext ec)
2403 public override Expression EmitToField (EmitContext ec)
2405 return expr.EmitToField(ec);
2408 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2410 expr.EmitBranchable (ec, target, on_true);
2413 public override void FlowAnalysis (FlowAnalysisContext fc)
2415 expr.FlowAnalysis (fc);
2418 public override SLE.Expression MakeExpression (BuilderContext ctx)
2420 return orig_expr.MakeExpression (ctx);
2425 // Standard composite pattern
2427 public abstract class CompositeExpression : Expression
2429 protected Expression expr;
2431 protected CompositeExpression (Expression expr)
2434 this.loc = expr.Location;
2437 public override bool ContainsEmitWithAwait ()
2439 return expr.ContainsEmitWithAwait ();
2442 public override Expression CreateExpressionTree (ResolveContext rc)
2444 return expr.CreateExpressionTree (rc);
2447 public Expression Child {
2448 get { return expr; }
2451 protected override Expression DoResolve (ResolveContext rc)
2453 expr = expr.Resolve (rc);
2458 eclass = expr.eclass;
2462 public override void Emit (EmitContext ec)
2467 public override bool IsNull {
2468 get { return expr.IsNull; }
2473 // Base of expressions used only to narrow resolve flow
2475 public abstract class ShimExpression : Expression
2477 protected Expression expr;
2479 protected ShimExpression (Expression expr)
2484 public Expression Expr {
2490 protected override void CloneTo (CloneContext clonectx, Expression t)
2495 ShimExpression target = (ShimExpression) t;
2496 target.expr = expr.Clone (clonectx);
2499 public override bool ContainsEmitWithAwait ()
2501 return expr.ContainsEmitWithAwait ();
2504 public override Expression CreateExpressionTree (ResolveContext ec)
2506 throw new NotSupportedException ("ET");
2509 public override void Emit (EmitContext ec)
2511 throw new InternalErrorException ("Missing Resolve call");
2515 public class UnreachableExpression : Expression
2517 public UnreachableExpression (Expression expr)
2519 this.loc = expr.Location;
2522 public override Expression CreateExpressionTree (ResolveContext ec)
2525 throw new NotImplementedException ();
2528 protected override Expression DoResolve (ResolveContext rc)
2530 throw new NotSupportedException ();
2533 public override void FlowAnalysis (FlowAnalysisContext fc)
2535 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2538 public override void Emit (EmitContext ec)
2542 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2548 // Unresolved type name expressions
2550 public abstract class ATypeNameExpression : FullNamedExpression
2553 protected TypeArguments targs;
2555 protected ATypeNameExpression (string name, Location l)
2561 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2568 protected ATypeNameExpression (string name, int arity, Location l)
2569 : this (name, new UnboundTypeArguments (arity, l), l)
2577 return targs == null ? 0 : targs.Count;
2581 public bool HasTypeArguments {
2583 return targs != null && !targs.IsEmpty;
2587 public string Name {
2596 public TypeArguments TypeArguments {
2604 public override bool Equals (object obj)
2606 ATypeNameExpression atne = obj as ATypeNameExpression;
2607 return atne != null && atne.Name == Name &&
2608 (targs == null || targs.Equals (atne.targs));
2611 public override int GetHashCode ()
2613 return Name.GetHashCode ();
2616 // TODO: Move it to MemberCore
2617 public static string GetMemberType (MemberCore mc)
2623 if (mc is FieldBase)
2625 if (mc is MethodCore)
2627 if (mc is EnumMember)
2635 public override string GetSignatureForError ()
2637 if (targs != null) {
2638 return Name + "<" + targs.GetSignatureForError () + ">";
2644 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2648 /// SimpleName expressions are formed of a single word and only happen at the beginning
2649 /// of a dotted-name.
2651 public class SimpleName : ATypeNameExpression
2653 public SimpleName (string name, Location l)
2658 public SimpleName (string name, TypeArguments args, Location l)
2659 : base (name, args, l)
2663 public SimpleName (string name, int arity, Location l)
2664 : base (name, arity, l)
2668 public SimpleName GetMethodGroup ()
2670 return new SimpleName (Name, targs, loc);
2673 protected override Expression DoResolve (ResolveContext rc)
2675 return SimpleNameResolve (rc, null);
2678 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2680 return SimpleNameResolve (ec, right_side);
2683 public void Error_NameDoesNotExist (ResolveContext rc)
2685 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2688 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2690 if (ctx.CurrentType != null) {
2691 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2692 if (member != null) {
2693 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2698 var report = ctx.Module.Compiler.Report;
2700 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2701 if (retval != null) {
2702 report.SymbolRelatedToPreviousError (retval.Type);
2703 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2707 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2708 if (retval != null) {
2709 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2713 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2714 if (ns_candidates != null) {
2715 if (ctx is UsingAliasNamespace.AliasContext) {
2716 report.Error (246, loc,
2717 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2718 ns_candidates[0], Name);
2720 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2721 report.Error (246, loc,
2722 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2726 report.Error (246, loc,
2727 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2732 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2734 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2737 if (fne.Type != null && Arity > 0) {
2738 if (HasTypeArguments) {
2739 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2740 if (ct.ResolveAsType (mc) == null)
2746 targs.Resolve (mc, allowUnboundTypeArguments);
2748 return new GenericOpenTypeExpr (fne.Type, loc);
2752 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2754 if (!(fne is NamespaceExpression))
2758 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2759 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2760 mc.Module.Compiler.Report.Error (1980, Location,
2761 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2762 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2765 fne = new DynamicTypeExpr (loc);
2766 fne.ResolveAsType (mc);
2772 Error_TypeOrNamespaceNotFound (mc);
2776 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2778 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2781 public bool IsPossibleType (IMemberContext mc)
2783 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) is TypeExpr;
2786 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2788 int lookup_arity = Arity;
2789 bool errorMode = false;
2791 Block current_block = rc.CurrentBlock;
2792 INamedBlockVariable variable = null;
2793 bool variable_found = false;
2797 // Stage 1: binding to local variables or parameters
2799 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2801 if (current_block != null && lookup_arity == 0) {
2802 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2803 if (!variable.IsDeclared) {
2804 // We found local name in accessible block but it's not
2805 // initialized yet, maybe the user wanted to bind to something else
2807 variable_found = true;
2809 e = variable.CreateReferenceExpression (rc, loc);
2812 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2821 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2823 TypeSpec member_type = rc.CurrentType;
2824 for (; member_type != null; member_type = member_type.DeclaringType) {
2825 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2829 var me = e as MemberExpr;
2831 // The name matches a type, defer to ResolveAsTypeStep
2839 if (variable != null) {
2840 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2841 rc.Report.Error (844, loc,
2842 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2843 Name, me.GetSignatureForError ());
2847 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2848 // Leave it to overload resolution to report correct error
2850 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2851 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2855 // MemberLookup does not check accessors availability, this is actually needed for properties only
2857 var pe = me as PropertyExpr;
2860 // Break as there is no other overload available anyway
2861 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2862 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2865 pe.Getter = pe.PropertyInfo.Get;
2867 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2870 pe.Setter = pe.PropertyInfo.Set;
2875 // TODO: It's used by EventExpr -> FieldExpr transformation only
2876 // TODO: Should go to MemberAccess
2877 me = me.ResolveMemberAccess (rc, null, null);
2880 targs.Resolve (rc, false);
2881 me.SetTypeArguments (rc, targs);
2888 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2890 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2891 if (IsPossibleTypeOrNamespace (rc)) {
2892 return ResolveAsTypeOrNamespace (rc, false);
2896 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2899 targs.Resolve (rc, false);
2901 var me = expr as MemberExpr;
2903 me.SetTypeArguments (rc, targs);
2908 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2909 return new NameOf (this);
2912 if (variable_found) {
2913 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2916 var tparams = rc.CurrentTypeParameters;
2917 if (tparams != null) {
2918 if (tparams.Find (Name) != null) {
2919 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2924 var ct = rc.CurrentType;
2926 if (ct.MemberDefinition.TypeParametersCount > 0) {
2927 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2928 if (ctp.Name == Name) {
2929 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2935 ct = ct.DeclaringType;
2936 } while (ct != null);
2939 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2940 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2942 rc.Report.SymbolRelatedToPreviousError (e.Type);
2943 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2947 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2949 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2950 return ErrorExpression.Instance;
2954 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2956 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2957 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2961 if (e is TypeExpr) {
2962 // TypeExpression does not have correct location
2963 if (e is TypeExpression)
2964 e = new TypeExpression (e.Type, loc);
2970 Error_NameDoesNotExist (rc);
2973 return ErrorExpression.Instance;
2976 if (rc.Module.Evaluator != null) {
2977 var fi = rc.Module.Evaluator.LookupField (Name);
2979 return new FieldExpr (fi.Item1, loc);
2987 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2989 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2994 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2995 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2999 if (right_side != null) {
3000 e = e.ResolveLValue (ec, right_side);
3008 public override object Accept (StructuralVisitor visitor)
3010 return visitor.Visit (this);
3015 /// Represents a namespace or a type. The name of the class was inspired by
3016 /// section 10.8.1 (Fully Qualified Names).
3018 public abstract class FullNamedExpression : Expression
3020 protected override void CloneTo (CloneContext clonectx, Expression target)
3022 // Do nothing, most unresolved type expressions cannot be
3023 // resolved to different type
3026 public override bool ContainsEmitWithAwait ()
3031 public override Expression CreateExpressionTree (ResolveContext ec)
3033 throw new NotSupportedException ("ET");
3036 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3039 // This is used to resolve the expression as a type, a null
3040 // value will be returned if the expression is not a type
3043 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3045 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3050 TypeExpr te = fne as TypeExpr;
3052 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3060 var dep = type.GetMissingDependencies ();
3062 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3065 if (type.Kind == MemberKind.Void) {
3066 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3070 // Obsolete checks cannot be done when resolving base context as they
3071 // require type dependencies to be set but we are in process of resolving them
3073 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3074 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3075 if (obsolete_attr != null && !mc.IsObsolete) {
3076 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3084 public override void Emit (EmitContext ec)
3086 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3087 GetSignatureForError ());
3092 /// Expression that evaluates to a type
3094 public abstract class TypeExpr : FullNamedExpression
3096 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3102 protected sealed override Expression DoResolve (ResolveContext ec)
3108 public override bool Equals (object obj)
3110 TypeExpr tobj = obj as TypeExpr;
3114 return Type == tobj.Type;
3117 public override int GetHashCode ()
3119 return Type.GetHashCode ();
3124 /// Fully resolved Expression that already evaluated to a type
3126 public class TypeExpression : TypeExpr
3128 public TypeExpression (TypeSpec t, Location l)
3131 eclass = ExprClass.Type;
3135 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3141 public class NamespaceExpression : FullNamedExpression
3143 readonly Namespace ns;
3145 public NamespaceExpression (Namespace ns, Location loc)
3148 this.Type = InternalType.Namespace;
3149 this.eclass = ExprClass.Namespace;
3153 public Namespace Namespace {
3159 protected override Expression DoResolve (ResolveContext rc)
3161 throw new NotImplementedException ();
3164 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3169 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3171 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3172 if (retval != null) {
3173 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3174 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3178 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3179 if (retval != null) {
3180 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3185 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3186 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3190 string assembly = null;
3191 string possible_name = Namespace.GetSignatureForError () + "." + name;
3193 // Only assembly unique name should be added
3194 switch (possible_name) {
3195 case "System.Drawing":
3196 case "System.Web.Services":
3199 case "System.Configuration":
3200 case "System.Data.Services":
3201 case "System.DirectoryServices":
3203 case "System.Net.Http":
3204 case "System.Numerics":
3205 case "System.Runtime.Caching":
3206 case "System.ServiceModel":
3207 case "System.Transactions":
3208 case "System.Web.Routing":
3209 case "System.Xml.Linq":
3211 assembly = possible_name;
3215 case "System.Linq.Expressions":
3216 assembly = "System.Core";
3219 case "System.Windows.Forms":
3220 case "System.Windows.Forms.Layout":
3221 assembly = "System.Windows.Forms";
3225 assembly = assembly == null ? "an" : "`" + assembly + "'";
3227 if (Namespace is GlobalRootNamespace) {
3228 ctx.Module.Compiler.Report.Error (400, loc,
3229 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3232 ctx.Module.Compiler.Report.Error (234, loc,
3233 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3234 name, GetSignatureForError (), assembly);
3238 public override string GetSignatureForError ()
3240 return ns.GetSignatureForError ();
3243 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3245 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3248 public override string ToString ()
3250 return Namespace.Name;
3255 /// This class denotes an expression which evaluates to a member
3256 /// of a struct or a class.
3258 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3260 protected bool conditional_access_receiver;
3263 // An instance expression associated with this member, if it's a
3264 // non-static member
3266 public Expression InstanceExpression;
3269 /// The name of this member.
3271 public abstract string Name {
3276 // When base.member is used
3278 public bool IsBase {
3279 get { return InstanceExpression is BaseThis; }
3283 /// Whether this is an instance member.
3285 public abstract bool IsInstance {
3290 /// Whether this is a static member.
3292 public abstract bool IsStatic {
3296 public abstract string KindName {
3300 public bool ConditionalAccess { get; set; }
3302 protected abstract TypeSpec DeclaringType {
3306 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3308 return InstanceExpression.Type;
3313 // Converts best base candidate for virtual method starting from QueriedBaseType
3315 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3318 // Only when base.member is used and method is virtual
3324 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3325 // means for base.member access we have to find the closest match after we found best candidate
3327 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3329 // The method could already be what we are looking for
3331 TypeSpec[] targs = null;
3332 if (method.DeclaringType != InstanceExpression.Type) {
3334 // Candidate can have inflated MVAR parameters and we need to find
3335 // base match for original definition not inflated parameter types
3337 var parameters = method.Parameters;
3338 if (method.Arity > 0) {
3339 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3340 var inflated = method.DeclaringType as InflatedTypeSpec;
3341 if (inflated != null) {
3342 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3346 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3347 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3348 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3349 if (base_override.IsGeneric)
3350 targs = method.TypeArguments;
3352 method = base_override;
3357 // When base access is used inside anonymous method/iterator/etc we need to
3358 // get back to the context of original type. We do it by emiting proxy
3359 // method in original class and rewriting base call to this compiler
3360 // generated method call which does the actual base invocation. This may
3361 // introduce redundant storey but with `this' only but it's tricky to avoid
3362 // at this stage as we don't know what expressions follow base
3364 if (rc.CurrentAnonymousMethod != null) {
3365 if (targs == null && method.IsGeneric) {
3366 targs = method.TypeArguments;
3367 method = method.GetGenericMethodDefinition ();
3370 if (method.Parameters.HasArglist)
3371 throw new NotImplementedException ("__arglist base call proxy");
3373 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3375 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3376 // get/set member expressions second call would fail to proxy because left expression
3377 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3378 // FIXME: The async check is another hack but will probably fail with mutators
3379 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3380 InstanceExpression = new This (loc).Resolve (rc);
3384 method = method.MakeGenericMethod (rc, targs);
3388 // Only base will allow this invocation to happen.
3390 if (method.IsAbstract) {
3391 rc.Report.SymbolRelatedToPreviousError (method);
3392 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3398 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3400 if (InstanceExpression == null)
3403 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3404 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3405 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3410 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3412 if (InstanceExpression == null)
3415 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3418 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3420 var ct = rc.CurrentType;
3421 if (ct == qualifier)
3424 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3427 qualifier = qualifier.GetDefinition ();
3428 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3435 public override bool ContainsEmitWithAwait ()
3437 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3440 public override bool HasConditionalAccess ()
3442 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3445 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3448 type = type.GetDefinition ();
3450 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3453 type = type.DeclaringType;
3454 } while (type != null);
3459 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3461 if (InstanceExpression != null) {
3462 InstanceExpression = InstanceExpression.Resolve (rc);
3463 CheckProtectedMemberAccess (rc, member);
3466 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3467 UnsafeError (rc, loc);
3470 var dep = member.GetMissingDependencies ();
3472 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3475 if (!rc.IsObsolete) {
3476 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3478 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3481 if (!(member is FieldSpec))
3482 member.MemberDefinition.SetIsUsed ();
3485 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3487 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3490 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3492 rc.Report.SymbolRelatedToPreviousError (member);
3493 rc.Report.Error (1540, loc,
3494 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3495 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3498 public override void FlowAnalysis (FlowAnalysisContext fc)
3500 if (InstanceExpression != null) {
3501 InstanceExpression.FlowAnalysis (fc);
3503 if (ConditionalAccess) {
3504 fc.BranchConditionalAccessDefiniteAssignment ();
3509 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3511 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3512 if (HasConditionalAccess ()) {
3513 conditional_access_receiver = true;
3514 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3519 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3521 if (!ResolveInstanceExpressionCore (rc, rhs))
3525 // Check intermediate value modification which won't have any effect
3527 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3528 var fexpr = InstanceExpression as FieldExpr;
3529 if (fexpr != null) {
3530 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3533 if (fexpr.IsStatic) {
3534 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3535 fexpr.GetSignatureForError ());
3537 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3538 fexpr.GetSignatureForError ());
3544 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3545 if (rc.CurrentInitializerVariable != null) {
3546 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3547 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3549 rc.Report.Error (1612, loc,
3550 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3551 InstanceExpression.GetSignatureForError ());
3557 var lvr = InstanceExpression as LocalVariableReference;
3560 if (!lvr.local_info.IsReadonly)
3563 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3564 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3571 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3574 if (InstanceExpression != null) {
3575 if (InstanceExpression is TypeExpr) {
3576 var t = InstanceExpression.Type;
3578 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3579 if (oa != null && !rc.IsObsolete) {
3580 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3583 t = t.DeclaringType;
3584 } while (t != null);
3586 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3587 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3588 rc.Report.Error (176, loc,
3589 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3590 GetSignatureForError ());
3594 InstanceExpression = null;
3600 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3601 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3602 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3603 rc.Report.Error (236, loc,
3604 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3605 GetSignatureForError ());
3607 var fe = this as FieldExpr;
3608 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3609 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3610 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3612 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3616 rc.Report.Error (120, loc,
3617 "An object reference is required to access non-static member `{0}'",
3618 GetSignatureForError ());
3622 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3626 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3627 rc.Report.Error (38, loc,
3628 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3629 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3632 InstanceExpression = new This (loc).Resolve (rc);
3636 var me = InstanceExpression as MemberExpr;
3638 me.ResolveInstanceExpressionCore (rc, rhs);
3640 var fe = me as FieldExpr;
3641 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3642 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3643 rc.Report.Warning (1690, 1, loc,
3644 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3645 me.GetSignatureForError ());
3652 // Additional checks for l-value member access
3655 if (InstanceExpression is UnboxCast) {
3656 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3663 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3665 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3666 ec.Report.Warning (1720, 1, left.Location,
3667 "Expression will always cause a `{0}'", "System.NullReferenceException");
3670 InstanceExpression = left;
3674 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3676 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3677 inst.Emit (ec, ConditionalAccess);
3679 if (prepare_for_load)
3680 ec.Emit (OpCodes.Dup);
3683 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3686 public class ExtensionMethodCandidates
3688 readonly NamespaceContainer container;
3689 readonly IList<MethodSpec> methods;
3691 readonly IMemberContext context;
3693 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3695 this.context = context;
3696 this.methods = methods;
3697 this.container = nsContainer;
3698 this.index = lookupIndex;
3701 public NamespaceContainer Container {
3707 public IMemberContext Context {
3713 public int LookupIndex {
3719 public IList<MethodSpec> Methods {
3727 // Represents a group of extension method candidates for whole namespace
3729 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3731 ExtensionMethodCandidates candidates;
3732 public Expression ExtensionExpression;
3734 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3735 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3737 this.candidates = candidates;
3738 this.ExtensionExpression = extensionExpr;
3741 public override bool IsStatic {
3742 get { return true; }
3745 public override void FlowAnalysis (FlowAnalysisContext fc)
3747 if (ConditionalAccess) {
3748 fc.BranchConditionalAccessDefiniteAssignment ();
3753 // For extension methodgroup we are not looking for base members but parent
3754 // namespace extension methods
3756 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3758 // TODO: candidates are null only when doing error reporting, that's
3759 // incorrect. We have to discover same extension methods in error mode
3760 if (candidates == null)
3763 int arity = type_arguments == null ? 0 : type_arguments.Count;
3765 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3766 if (candidates == null)
3769 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3772 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3775 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3777 // LAMESPEC: or implicit type parameter conversion
3779 return argType == extensionType ||
3780 TypeSpecComparer.IsEqual (argType, extensionType) ||
3781 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3782 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3785 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3787 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3789 // Not included in C#6
3791 ExtensionExpression = ExtensionExpression.Resolve (rc);
3792 if (ExtensionExpression == null)
3795 var argType = ExtensionExpression.Type;
3796 foreach (MethodSpec candidate in Candidates) {
3797 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3801 // TODO: Scan full hierarchy
3803 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3808 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3810 // We are already here
3814 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3816 if (arguments == null)
3817 arguments = new Arguments (1);
3819 ExtensionExpression = ExtensionExpression.Resolve (ec);
3820 if (ExtensionExpression == null)
3823 var cand = candidates;
3824 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3825 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3826 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3828 // Restore candidates in case we are running in probing mode
3831 // Store resolved argument and restore original arguments
3833 // Clean-up modified arguments for error reporting
3834 arguments.RemoveAt (0);
3838 var me = ExtensionExpression as MemberExpr;
3840 me.ResolveInstanceExpression (ec, null);
3841 var fe = me as FieldExpr;
3843 fe.Spec.MemberDefinition.SetIsUsed ();
3846 InstanceExpression = null;
3850 #region IErrorHandler Members
3852 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3857 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3859 rc.Report.SymbolRelatedToPreviousError (best);
3862 rc.Report.Error (1929, loc,
3863 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3864 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3866 rc.Report.Error (1928, loc,
3867 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3868 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3874 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3879 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3888 /// MethodGroupExpr represents a group of method candidates which
3889 /// can be resolved to the best method overload
3891 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3893 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3895 protected IList<MemberSpec> Methods;
3896 MethodSpec best_candidate;
3897 TypeSpec best_candidate_return;
3898 protected TypeArguments type_arguments;
3900 SimpleName simple_name;
3901 protected TypeSpec queried_type;
3903 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3907 this.type = InternalType.MethodGroup;
3909 eclass = ExprClass.MethodGroup;
3910 queried_type = type;
3913 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3914 : this (new MemberSpec[] { m }, type, loc)
3920 public MethodSpec BestCandidate {
3922 return best_candidate;
3926 public TypeSpec BestCandidateReturnType {
3928 return best_candidate_return;
3932 public IList<MemberSpec> Candidates {
3938 protected override TypeSpec DeclaringType {
3940 return queried_type;
3944 public bool IsConditionallyExcluded {
3946 return Methods == Excluded;
3950 public override bool IsInstance {
3952 if (best_candidate != null)
3953 return !best_candidate.IsStatic;
3959 public override bool IsSideEffectFree {
3961 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3965 public override bool IsStatic {
3967 if (best_candidate != null)
3968 return best_candidate.IsStatic;
3974 public override string KindName {
3975 get { return "method"; }
3978 public override string Name {
3980 if (best_candidate != null)
3981 return best_candidate.Name;
3984 return Methods.First ().Name;
3991 // When best candidate is already know this factory can be used
3992 // to avoid expensive overload resolution to be called
3994 // NOTE: InstanceExpression has to be set manually
3996 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3998 return new MethodGroupExpr (best, queriedType, loc) {
3999 best_candidate = best,
4000 best_candidate_return = best.ReturnType
4004 public override string GetSignatureForError ()
4006 if (best_candidate != null)
4007 return best_candidate.GetSignatureForError ();
4009 return Methods.First ().GetSignatureForError ();
4012 public override Expression CreateExpressionTree (ResolveContext ec)
4014 if (best_candidate == null) {
4015 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4019 if (IsConditionallyExcluded)
4020 ec.Report.Error (765, loc,
4021 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4023 if (ConditionalAccess)
4024 Error_NullShortCircuitInsideExpressionTree (ec);
4026 return new TypeOfMethod (best_candidate, loc);
4029 protected override Expression DoResolve (ResolveContext ec)
4031 this.eclass = ExprClass.MethodGroup;
4033 if (InstanceExpression != null) {
4034 InstanceExpression = InstanceExpression.Resolve (ec);
4035 if (InstanceExpression == null)
4042 public override void Emit (EmitContext ec)
4044 throw new NotSupportedException ();
4047 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4049 var call = new CallEmitter ();
4050 call.InstanceExpression = InstanceExpression;
4051 call.ConditionalAccess = ConditionalAccess;
4054 call.EmitStatement (ec, best_candidate, arguments, loc);
4056 call.Emit (ec, best_candidate, arguments, loc);
4059 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4061 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4062 Statement = statement
4065 EmitCall (ec, arguments, statement);
4067 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4070 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4072 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4073 Name, target.GetSignatureForError ());
4076 public bool HasAccessibleCandidate (ResolveContext rc)
4078 foreach (var candidate in Candidates) {
4079 if (candidate.IsAccessible (rc))
4086 public static bool IsExtensionMethodArgument (Expression expr)
4089 // LAMESPEC: No details about which expressions are not allowed
4091 return !(expr is TypeExpr) && !(expr is BaseThis);
4095 /// Find the Applicable Function Members (7.4.2.1)
4097 /// me: Method Group expression with the members to select.
4098 /// it might contain constructors or methods (or anything
4099 /// that maps to a method).
4101 /// Arguments: ArrayList containing resolved Argument objects.
4103 /// loc: The location if we want an error to be reported, or a Null
4104 /// location for "probing" purposes.
4106 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4107 /// that is the best match of me on Arguments.
4110 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4112 // TODO: causes issues with probing mode, remove explicit Kind check
4113 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4116 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4117 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4118 r.BaseMembersProvider = this;
4119 r.InstanceQualifier = this;
4122 if (cerrors != null)
4123 r.CustomErrors = cerrors;
4125 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4126 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4127 if (best_candidate == null) {
4128 if (!r.BestCandidateIsDynamic)
4131 if (simple_name != null && ec.IsStatic)
4132 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4137 // Overload resolver had to create a new method group, all checks bellow have already been executed
4138 if (r.BestCandidateNewMethodGroup != null)
4139 return r.BestCandidateNewMethodGroup;
4141 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4142 if (InstanceExpression != null) {
4143 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4144 InstanceExpression = null;
4146 if (simple_name != null && best_candidate.IsStatic) {
4147 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4150 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4154 ResolveInstanceExpression (ec, null);
4157 var base_override = CandidateToBaseOverride (ec, best_candidate);
4158 if (base_override == best_candidate) {
4159 best_candidate_return = r.BestCandidateReturnType;
4161 best_candidate = base_override;
4162 best_candidate_return = best_candidate.ReturnType;
4165 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4166 ConstraintChecker cc = new ConstraintChecker (ec);
4167 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4171 // Additional check for possible imported base override method which
4172 // could not be done during IsOverrideMethodBaseTypeAccessible
4174 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4175 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4176 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4177 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4180 // Speed up the check by not doing it on disallowed targets
4181 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4187 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4189 var fe = left as FieldExpr;
4192 // Using method-group on struct fields makes the struct assigned. I am not sure
4193 // why but that's what .net does
4195 fe.Spec.MemberDefinition.SetIsAssigned ();
4198 simple_name = original;
4199 return base.ResolveMemberAccess (ec, left, original);
4202 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4204 type_arguments = ta;
4207 #region IBaseMembersProvider Members
4209 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4211 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4214 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4216 if (queried_type == member.DeclaringType)
4219 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4220 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4224 // Extension methods lookup after ordinary methods candidates failed to apply
4226 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4228 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4231 if (!IsExtensionMethodArgument (InstanceExpression))
4234 int arity = type_arguments == null ? 0 : type_arguments.Count;
4235 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4236 if (methods == null)
4239 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4240 emg.SetTypeArguments (rc, type_arguments);
4247 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4249 public ConstructorInstanceQualifier (TypeSpec type)
4252 InstanceType = type;
4255 public TypeSpec InstanceType { get; private set; }
4257 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4259 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4263 public struct OverloadResolver
4266 public enum Restrictions
4270 ProbingOnly = 1 << 1,
4271 CovariantDelegate = 1 << 2,
4272 NoBaseMembers = 1 << 3,
4273 BaseMembersIncluded = 1 << 4,
4274 GetEnumeratorLookup = 1 << 5
4277 public interface IBaseMembersProvider
4279 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4280 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4281 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4284 public interface IErrorHandler
4286 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4287 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4288 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4289 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4292 public interface IInstanceQualifier
4294 TypeSpec InstanceType { get; }
4295 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4298 sealed class NoBaseMembers : IBaseMembersProvider
4300 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4302 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4307 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4312 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4318 struct AmbiguousCandidate
4320 public readonly MemberSpec Member;
4321 public readonly bool Expanded;
4322 public readonly AParametersCollection Parameters;
4324 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4327 Parameters = parameters;
4328 Expanded = expanded;
4333 IList<MemberSpec> members;
4334 TypeArguments type_arguments;
4335 IBaseMembersProvider base_provider;
4336 IErrorHandler custom_errors;
4337 IInstanceQualifier instance_qualifier;
4338 Restrictions restrictions;
4339 MethodGroupExpr best_candidate_extension_group;
4340 TypeSpec best_candidate_return_type;
4342 SessionReportPrinter lambda_conv_msgs;
4344 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4345 : this (members, null, restrictions, loc)
4349 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4352 if (members == null || members.Count == 0)
4353 throw new ArgumentException ("empty members set");
4355 this.members = members;
4357 type_arguments = targs;
4358 this.restrictions = restrictions;
4359 if (IsDelegateInvoke)
4360 this.restrictions |= Restrictions.NoBaseMembers;
4362 base_provider = NoBaseMembers.Instance;
4367 public IBaseMembersProvider BaseMembersProvider {
4369 return base_provider;
4372 base_provider = value;
4376 public bool BestCandidateIsDynamic { get; set; }
4379 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4381 public MethodGroupExpr BestCandidateNewMethodGroup {
4383 return best_candidate_extension_group;
4388 // Return type can be different between best candidate and closest override
4390 public TypeSpec BestCandidateReturnType {
4392 return best_candidate_return_type;
4396 public IErrorHandler CustomErrors {
4398 return custom_errors;
4401 custom_errors = value;
4405 TypeSpec DelegateType {
4407 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4408 throw new InternalErrorException ("Not running in delegate mode", loc);
4410 return members [0].DeclaringType;
4414 public IInstanceQualifier InstanceQualifier {
4416 return instance_qualifier;
4419 instance_qualifier = value;
4423 bool IsProbingOnly {
4425 return (restrictions & Restrictions.ProbingOnly) != 0;
4429 bool IsDelegateInvoke {
4431 return (restrictions & Restrictions.DelegateInvoke) != 0;
4438 // 7.4.3.3 Better conversion from expression
4439 // Returns : 1 if a->p is better,
4440 // 2 if a->q is better,
4441 // 0 if neither is better
4443 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4445 TypeSpec argument_type = a.Type;
4448 // If argument is an anonymous function
4450 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4452 // p and q are delegate types or expression tree types
4454 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4455 if (q.MemberDefinition != p.MemberDefinition) {
4460 // Uwrap delegate from Expression<T>
4462 q = TypeManager.GetTypeArguments (q)[0];
4463 p = TypeManager.GetTypeArguments (p)[0];
4466 var p_m = Delegate.GetInvokeMethod (p);
4467 var q_m = Delegate.GetInvokeMethod (q);
4470 // With identical parameter lists
4472 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4480 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4482 if (p.Kind == MemberKind.Void) {
4483 return q.Kind != MemberKind.Void ? 2 : 0;
4487 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4489 if (q.Kind == MemberKind.Void) {
4490 return p.Kind != MemberKind.Void ? 1: 0;
4493 var am = (AnonymousMethodExpression) a.Expr;
4496 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4497 // better conversion is performed between underlying types Y1 and Y2
4499 if (p.IsGenericTask || q.IsGenericTask) {
4500 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4501 q = q.TypeArguments[0];
4502 p = p.TypeArguments[0];
4508 // An inferred return type X exists for E in the context of that parameter list, and
4509 // the conversion from X to Y1 is better than the conversion from X to Y2
4511 argument_type = am.InferReturnType (ec, null, orig_q);
4512 if (argument_type == null) {
4513 // TODO: Can this be hit?
4517 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4518 argument_type = ec.BuiltinTypes.Object;
4522 if (argument_type == p)
4525 if (argument_type == q)
4529 // The parameters are identicial and return type is not void, use better type conversion
4530 // on return type to determine better one
4532 return BetterTypeConversion (ec, p, q);
4536 // 7.4.3.4 Better conversion from type
4538 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4540 if (p == null || q == null)
4541 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4543 switch (p.BuiltinType) {
4544 case BuiltinTypeSpec.Type.Int:
4545 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4548 case BuiltinTypeSpec.Type.Long:
4549 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4552 case BuiltinTypeSpec.Type.SByte:
4553 switch (q.BuiltinType) {
4554 case BuiltinTypeSpec.Type.Byte:
4555 case BuiltinTypeSpec.Type.UShort:
4556 case BuiltinTypeSpec.Type.UInt:
4557 case BuiltinTypeSpec.Type.ULong:
4561 case BuiltinTypeSpec.Type.Short:
4562 switch (q.BuiltinType) {
4563 case BuiltinTypeSpec.Type.UShort:
4564 case BuiltinTypeSpec.Type.UInt:
4565 case BuiltinTypeSpec.Type.ULong:
4569 case BuiltinTypeSpec.Type.Dynamic:
4570 // Dynamic is never better
4574 switch (q.BuiltinType) {
4575 case BuiltinTypeSpec.Type.Int:
4576 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4579 case BuiltinTypeSpec.Type.Long:
4580 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4583 case BuiltinTypeSpec.Type.SByte:
4584 switch (p.BuiltinType) {
4585 case BuiltinTypeSpec.Type.Byte:
4586 case BuiltinTypeSpec.Type.UShort:
4587 case BuiltinTypeSpec.Type.UInt:
4588 case BuiltinTypeSpec.Type.ULong:
4592 case BuiltinTypeSpec.Type.Short:
4593 switch (p.BuiltinType) {
4594 case BuiltinTypeSpec.Type.UShort:
4595 case BuiltinTypeSpec.Type.UInt:
4596 case BuiltinTypeSpec.Type.ULong:
4600 case BuiltinTypeSpec.Type.Dynamic:
4601 // Dynamic is never better
4605 // FIXME: handle lifted operators
4607 // TODO: this is expensive
4608 Expression p_tmp = new EmptyExpression (p);
4609 Expression q_tmp = new EmptyExpression (q);
4611 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4612 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4614 if (p_to_q && !q_to_p)
4617 if (q_to_p && !p_to_q)
4624 /// Determines "Better function" between candidate
4625 /// and the current best match
4628 /// Returns a boolean indicating :
4629 /// false if candidate ain't better
4630 /// true if candidate is better than the current best match
4632 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4633 MemberSpec best, AParametersCollection bparam, bool best_params)
4635 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4636 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4638 bool better_at_least_one = false;
4639 bool are_equivalent = true;
4640 int args_count = args == null ? 0 : args.Count;
4644 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4647 // Default arguments are ignored for better decision
4648 if (a.IsDefaultArgument)
4652 // When comparing named argument the parameter type index has to be looked up
4653 // in original parameter set (override version for virtual members)
4655 NamedArgument na = a as NamedArgument;
4657 int idx = cparam.GetParameterIndexByName (na.Name);
4658 ct = candidate_pd.Types[idx];
4659 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4660 ct = TypeManager.GetElementType (ct);
4662 idx = bparam.GetParameterIndexByName (na.Name);
4663 bt = best_pd.Types[idx];
4664 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4665 bt = TypeManager.GetElementType (bt);
4667 ct = candidate_pd.Types[c_idx];
4668 bt = best_pd.Types[b_idx];
4670 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4671 ct = TypeManager.GetElementType (ct);
4675 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4676 bt = TypeManager.GetElementType (bt);
4681 if (TypeSpecComparer.IsEqual (ct, bt))
4684 are_equivalent = false;
4685 int result = BetterExpressionConversion (ec, a, ct, bt);
4687 // for each argument, the conversion to 'ct' should be no worse than
4688 // the conversion to 'bt'.
4692 // for at least one argument, the conversion to 'ct' should be better than
4693 // the conversion to 'bt'.
4695 better_at_least_one = true;
4698 if (better_at_least_one)
4702 // Tie-breaking rules are applied only for equivalent parameter types
4704 if (!are_equivalent) {
4706 // LAMESPEC: A candidate with less default parameters is still better when there
4707 // is no better expression conversion
4709 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4717 // If candidate is applicable in its normal form and best has a params array and is applicable
4718 // only in its expanded form, then candidate is better
4720 if (candidate_params != best_params)
4721 return !candidate_params;
4724 // We have not reached end of parameters list due to params or used default parameters
4726 while (j < candidate_pd.Count && j < best_pd.Count) {
4727 var cand_param = candidate_pd.FixedParameters [j];
4728 var best_param = best_pd.FixedParameters [j];
4730 if (candidate_pd.Count == best_pd.Count) {
4734 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4735 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4737 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4738 return cand_param.HasDefaultValue;
4740 if (cand_param.HasDefaultValue) {
4746 // Neither is better when not all arguments are provided
4748 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4749 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4750 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4752 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4759 if (candidate_pd.Count != best_pd.Count)
4760 return candidate_pd.Count < best_pd.Count;
4763 // One is a non-generic method and second is a generic method, then non-generic is better
4765 if (best.IsGeneric != candidate.IsGeneric)
4766 return best.IsGeneric;
4769 // Both methods have the same number of parameters, and the parameters have equal types
4770 // Pick the "more specific" signature using rules over original (non-inflated) types
4772 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4773 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4775 bool specific_at_least_once = false;
4776 for (j = 0; j < args_count; ++j) {
4777 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4779 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4780 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4782 ct = candidate_def_pd.Types[j];
4783 bt = best_def_pd.Types[j];
4788 TypeSpec specific = MoreSpecific (ct, bt);
4792 specific_at_least_once = true;
4795 if (specific_at_least_once)
4801 static bool CheckInflatedArguments (MethodSpec ms)
4803 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4806 // Setup constraint checker for probing only
4807 ConstraintChecker cc = new ConstraintChecker (null);
4809 var mp = ms.Parameters.Types;
4810 for (int i = 0; i < mp.Length; ++i) {
4811 var type = mp[i] as InflatedTypeSpec;
4815 var targs = type.TypeArguments;
4816 if (targs.Length == 0)
4819 // TODO: Checking inflated MVAR arguments should be enough
4820 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4827 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4829 rc.Report.Error (1729, loc,
4830 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4831 type.GetSignatureForError (), argCount.ToString ());
4835 // Determines if the candidate method is applicable to the given set of arguments
4836 // There could be two different set of parameters for same candidate where one
4837 // is the closest override for default values and named arguments checks and second
4838 // one being the virtual base for the parameter types and modifiers.
4840 // A return value rates candidate method compatibility,
4842 // 0 = the best, int.MaxValue = the worst
4844 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)
4847 // Each step has allocated 10 values, it can overflow for
4848 // more than 10 arguments but that's ok as it's used for
4849 // better error reporting only
4851 const int ArgumentCountMismatch = 1000000000;
4852 const int NamedArgumentsMismatch = 100000000;
4853 const int DefaultArgumentMismatch = 10000000;
4854 const int UnexpectedTypeArguments = 1000000;
4855 const int TypeArgumentsMismatch = 100000;
4856 const int InflatedTypesMismatch = 10000;
4858 // Parameters of most-derived type used mainly for named and optional parameters
4859 var pd = pm.Parameters;
4861 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4862 // params modifier instead of most-derived type
4863 var cpd = ((IParametersMember) candidate).Parameters;
4864 int param_count = pd.Count;
4865 int optional_count = 0;
4867 Arguments orig_args = arguments;
4869 if (arg_count != param_count) {
4871 // No arguments expansion when doing exact match for delegates
4873 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4874 for (int i = 0; i < pd.Count; ++i) {
4875 if (pd.FixedParameters[i].HasDefaultValue) {
4876 optional_count = pd.Count - i;
4882 if (optional_count != 0) {
4883 // Readjust expected number when params used
4884 if (cpd.HasParams) {
4886 if (arg_count < param_count)
4888 } else if (arg_count > param_count) {
4889 int args_gap = System.Math.Abs (arg_count - param_count);
4890 return ArgumentCountMismatch + args_gap;
4891 } else if (arg_count < param_count - optional_count) {
4892 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4893 return ArgumentCountMismatch + args_gap;
4895 } else if (arg_count != param_count) {
4896 int args_gap = System.Math.Abs (arg_count - param_count);
4898 return ArgumentCountMismatch + args_gap;
4899 if (arg_count < param_count - 1)
4900 return ArgumentCountMismatch + args_gap;
4903 // Resize to fit optional arguments
4904 if (optional_count != 0) {
4905 if (arguments == null) {
4906 arguments = new Arguments (optional_count);
4908 // Have to create a new container, so the next run can do same
4909 var resized = new Arguments (param_count);
4910 resized.AddRange (arguments);
4911 arguments = resized;
4914 for (int i = arg_count; i < param_count; ++i)
4915 arguments.Add (null);
4919 if (arg_count > 0) {
4921 // Shuffle named arguments to the right positions if there are any
4923 if (arguments[arg_count - 1] is NamedArgument) {
4924 arg_count = arguments.Count;
4926 for (int i = 0; i < arg_count; ++i) {
4927 bool arg_moved = false;
4929 NamedArgument na = arguments[i] as NamedArgument;
4933 int index = pd.GetParameterIndexByName (na.Name);
4935 // Named parameter not found
4937 return NamedArgumentsMismatch - i;
4939 // already reordered
4944 if (index >= param_count) {
4945 // When using parameters which should not be available to the user
4946 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4949 arguments.Add (null);
4953 if (index == arg_count)
4954 return NamedArgumentsMismatch - i - 1;
4956 temp = arguments [index];
4958 // The slot has been taken by positional argument
4959 if (temp != null && !(temp is NamedArgument))
4964 arguments = arguments.MarkOrderedArgument (na);
4968 if (arguments == orig_args) {
4969 arguments = new Arguments (orig_args.Count);
4970 arguments.AddRange (orig_args);
4973 arguments[index] = arguments[i];
4974 arguments[i] = temp;
4981 arg_count = arguments.Count;
4983 } else if (arguments != null) {
4984 arg_count = arguments.Count;
4988 // Don't do any expensive checks when the candidate cannot succeed
4990 if (arg_count != param_count && !cpd.HasParams)
4991 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4993 var dep = candidate.GetMissingDependencies ();
4995 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
5000 // 1. Handle generic method using type arguments when specified or type inference
5003 var ms = candidate as MethodSpec;
5004 if (ms != null && ms.IsGeneric) {
5005 if (type_arguments != null) {
5006 var g_args_count = ms.Arity;
5007 if (g_args_count != type_arguments.Count)
5008 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5010 if (type_arguments.Arguments != null)
5011 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5014 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5015 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5016 // candidate was found use the set to report more details about what was wrong with lambda body.
5017 // The general idea is to distinguish between code errors and errors caused by
5018 // trial-and-error type inference
5020 if (lambda_conv_msgs == null) {
5021 for (int i = 0; i < arg_count; i++) {
5022 Argument a = arguments[i];
5026 var am = a.Expr as AnonymousMethodExpression;
5028 if (lambda_conv_msgs == null)
5029 lambda_conv_msgs = new SessionReportPrinter ();
5031 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5036 var ti = new TypeInference (arguments);
5037 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5040 return TypeArgumentsMismatch - ti.InferenceScore;
5043 // Clear any error messages when the result was success
5045 if (lambda_conv_msgs != null)
5046 lambda_conv_msgs.ClearSession ();
5048 if (i_args.Length != 0) {
5050 for (int i = 0; i < i_args.Length; ++i) {
5051 var ta = i_args [i];
5052 if (!ta.IsAccessible (ec))
5053 return TypeArgumentsMismatch - i;
5057 ms = ms.MakeGenericMethod (ec, i_args);
5062 // Type arguments constraints have to match for the method to be applicable
5064 if (!CheckInflatedArguments (ms)) {
5066 return InflatedTypesMismatch;
5070 // We have a generic return type and at same time the method is override which
5071 // means we have to also inflate override return type in case the candidate is
5072 // best candidate and override return type is different to base return type.
5074 // virtual Foo<T, object> with override Foo<T, dynamic>
5076 if (candidate != pm) {
5077 MethodSpec override_ms = (MethodSpec) pm;
5078 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5079 returnType = inflator.Inflate (returnType);
5081 returnType = ms.ReturnType;
5088 if (type_arguments != null)
5089 return UnexpectedTypeArguments;
5095 // 2. Each argument has to be implicitly convertible to method parameter
5097 Parameter.Modifier p_mod = 0;
5100 for (int i = 0; i < arg_count; i++) {
5101 Argument a = arguments[i];
5103 var fp = pd.FixedParameters[i];
5104 if (!fp.HasDefaultValue) {
5105 arguments = orig_args;
5106 return arg_count * 2 + 2;
5110 // Get the default value expression, we can use the same expression
5111 // if the type matches
5113 Expression e = fp.DefaultValue;
5115 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5117 // Restore for possible error reporting
5118 for (int ii = i; ii < arg_count; ++ii)
5119 arguments.RemoveAt (i);
5121 return (arg_count - i) * 2 + 1;
5125 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5127 // LAMESPEC: Attributes can be mixed together with build-in priority
5129 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5130 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5131 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5132 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5133 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5134 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5138 arguments[i] = new Argument (e, Argument.AType.Default);
5142 if (p_mod != Parameter.Modifier.PARAMS) {
5143 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5145 } else if (!params_expanded_form) {
5146 params_expanded_form = true;
5147 pt = ((ElementTypeSpec) pt).Element;
5153 if (!params_expanded_form) {
5154 if (a.IsExtensionType) {
5155 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5160 score = IsArgumentCompatible (ec, a, p_mod, pt);
5163 dynamicArgument = true;
5168 // It can be applicable in expanded form (when not doing exact match like for delegates)
5170 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5171 if (!params_expanded_form) {
5172 pt = ((ElementTypeSpec) pt).Element;
5176 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5179 params_expanded_form = true;
5180 dynamicArgument = true;
5181 } else if (score == 0 || arg_count > pd.Count) {
5182 params_expanded_form = true;
5187 if (params_expanded_form)
5189 return (arg_count - i) * 2 + score;
5194 // Restore original arguments for dynamic binder to keep the intention of original source code
5196 if (dynamicArgument)
5197 arguments = orig_args;
5202 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5204 if (e is Constant && e.Type == ptype)
5208 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5210 if (e == EmptyExpression.MissingValue && (ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)) {
5211 e = new MemberAccess (new MemberAccess (new MemberAccess (
5212 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5213 } else if (e is Constant) {
5215 // Handles int to int? conversions, DefaultParameterValue check
5217 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5221 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5224 return e.Resolve (ec);
5228 // Tests argument compatibility with the parameter
5229 // The possible return values are
5231 // 1 - modifier mismatch
5232 // 2 - type mismatch
5233 // -1 - dynamic binding required
5235 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5238 // Types have to be identical when ref or out modifer
5239 // is used and argument is not of dynamic type
5241 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5242 var arg_type = argument.Type;
5244 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5246 // Using dynamic for ref/out parameter can still succeed at runtime
5248 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5254 if (arg_type != parameter) {
5255 if (arg_type == InternalType.VarOutType)
5259 // Do full equality check after quick path
5261 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5263 // Using dynamic for ref/out parameter can still succeed at runtime
5265 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5273 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5277 // Use implicit conversion in all modes to return same candidates when the expression
5278 // is used as argument or delegate conversion
5280 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5281 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5288 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5290 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5292 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5295 var ac_p = p as ArrayContainer;
5297 var ac_q = q as ArrayContainer;
5301 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5302 if (specific == ac_p.Element)
5304 if (specific == ac_q.Element)
5306 } else if (p.IsGeneric && q.IsGeneric) {
5307 var pargs = TypeManager.GetTypeArguments (p);
5308 var qargs = TypeManager.GetTypeArguments (q);
5310 bool p_specific_at_least_once = false;
5311 bool q_specific_at_least_once = false;
5313 for (int i = 0; i < pargs.Length; i++) {
5314 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5315 if (specific == pargs[i])
5316 p_specific_at_least_once = true;
5317 if (specific == qargs[i])
5318 q_specific_at_least_once = true;
5321 if (p_specific_at_least_once && !q_specific_at_least_once)
5323 if (!p_specific_at_least_once && q_specific_at_least_once)
5331 // Find the best method from candidate list
5333 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5335 List<AmbiguousCandidate> ambiguous_candidates = null;
5337 MemberSpec best_candidate;
5338 Arguments best_candidate_args = null;
5339 bool best_candidate_params = false;
5340 bool best_candidate_dynamic = false;
5341 int best_candidate_rate;
5342 IParametersMember best_parameter_member = null;
5344 int args_count = args != null ? args.Count : 0;
5346 Arguments candidate_args = args;
5347 bool error_mode = false;
5348 MemberSpec invocable_member = null;
5349 int applicable_candidates = 0;
5352 best_candidate = null;
5353 best_candidate_rate = int.MaxValue;
5355 var type_members = members;
5357 for (int i = 0; i < type_members.Count; ++i) {
5358 var member = type_members[i];
5361 // Methods in a base class are not candidates if any method in a derived
5362 // class is applicable
5364 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5368 if (!member.IsAccessible (rc))
5371 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5374 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5375 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5380 IParametersMember pm = member as IParametersMember;
5383 // Will use it later to report ambiguity between best method and invocable member
5385 if (Invocation.IsMemberInvocable (member))
5386 invocable_member = member;
5392 // Overload resolution is looking for base member but using parameter names
5393 // and default values from the closest member. That means to do expensive lookup
5394 // for the closest override for virtual or abstract members
5396 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5397 var override_params = base_provider.GetOverrideMemberParameters (member);
5398 if (override_params != null)
5399 pm = override_params;
5403 // Check if the member candidate is applicable
5405 bool params_expanded_form = false;
5406 bool dynamic_argument = false;
5407 TypeSpec rt = pm.MemberType;
5408 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5410 if (lambda_conv_msgs != null)
5411 lambda_conv_msgs.EndSession ();
5414 // How does it score compare to others
5416 if (candidate_rate < best_candidate_rate) {
5418 // Fatal error (missing dependency), cannot continue
5419 if (candidate_rate < 0)
5422 applicable_candidates = 1;
5423 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5424 // Only parameterless methods are considered
5426 best_candidate_rate = candidate_rate;
5427 best_candidate = member;
5428 best_candidate_args = candidate_args;
5429 best_candidate_params = params_expanded_form;
5430 best_candidate_dynamic = dynamic_argument;
5431 best_parameter_member = pm;
5432 best_candidate_return_type = rt;
5434 } else if (candidate_rate == 0) {
5436 // The member look is done per type for most operations but sometimes
5437 // it's not possible like for binary operators overload because they
5438 // are unioned between 2 sides
5440 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5441 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5445 ++applicable_candidates;
5447 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5449 // We pack all interface members into top level type which makes the overload resolution
5450 // more complicated for interfaces. We compensate it by removing methods with same
5451 // signature when building the cache hence this path should not really be hit often
5454 // interface IA { void Foo (int arg); }
5455 // interface IB : IA { void Foo (params int[] args); }
5457 // IB::Foo is the best overload when calling IB.Foo (1)
5460 if (ambiguous_candidates != null) {
5461 foreach (var amb_cand in ambiguous_candidates) {
5462 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5471 ambiguous_candidates = null;
5474 // Is the new candidate better
5475 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5479 best_candidate = member;
5480 best_candidate_args = candidate_args;
5481 best_candidate_params = params_expanded_form;
5482 best_candidate_dynamic = dynamic_argument;
5483 best_parameter_member = pm;
5484 best_candidate_return_type = rt;
5486 // It's not better but any other found later could be but we are not sure yet
5487 if (ambiguous_candidates == null)
5488 ambiguous_candidates = new List<AmbiguousCandidate> ();
5490 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5494 // Restore expanded arguments
5495 candidate_args = args;
5497 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5500 // We've found exact match
5502 if (best_candidate_rate == 0)
5506 // Try extension methods lookup when no ordinary method match was found and provider enables it
5509 var emg = base_provider.LookupExtensionMethod (rc);
5511 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5513 best_candidate_extension_group = emg;
5514 return (T) (MemberSpec) emg.BestCandidate;
5519 // Don't run expensive error reporting mode for probing
5526 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5529 lambda_conv_msgs = null;
5534 // No best member match found, report an error
5536 if (best_candidate_rate != 0 || error_mode) {
5537 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5541 if (best_candidate_dynamic) {
5542 if (args[0].IsExtensionType) {
5543 rc.Report.Error (1973, loc,
5544 "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",
5545 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5549 // Check type constraints only when explicit type arguments are used
5551 if (applicable_candidates == 1 && best_candidate.IsGeneric && type_arguments != null) {
5552 MethodSpec bc = best_candidate as MethodSpec;
5553 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5554 ConstraintChecker cc = new ConstraintChecker (rc);
5555 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5559 BestCandidateIsDynamic = true;
5564 // These flags indicates we are running delegate probing conversion. No need to
5565 // do more expensive checks
5567 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5568 return (T) best_candidate;
5570 if (ambiguous_candidates != null) {
5572 // Now check that there are no ambiguities i.e the selected method
5573 // should be better than all the others
5575 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5576 var candidate = ambiguous_candidates [ix];
5578 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5579 var ambiguous = candidate.Member;
5580 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5581 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5582 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5583 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5584 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5587 return (T) best_candidate;
5592 if (invocable_member != null && !IsProbingOnly) {
5593 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5594 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5595 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5596 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5600 // And now check if the arguments are all
5601 // compatible, perform conversions if
5602 // necessary etc. and return if everything is
5605 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5608 if (best_candidate == null)
5612 // Don't run possibly expensive checks in probing mode
5614 if (!IsProbingOnly && !rc.IsInProbingMode) {
5616 // Check ObsoleteAttribute on the best method
5618 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5619 if (oa != null && !rc.IsObsolete)
5620 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5622 best_candidate.MemberDefinition.SetIsUsed ();
5625 args = best_candidate_args;
5626 return (T) best_candidate;
5629 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5631 return ResolveMember<MethodSpec> (rc, ref args);
5634 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5635 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5637 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5640 if (a.Type == InternalType.ErrorType)
5643 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5644 ec.Report.SymbolRelatedToPreviousError (method);
5645 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5646 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5647 TypeManager.CSharpSignature (method));
5650 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5651 TypeManager.CSharpSignature (method));
5652 } else if (IsDelegateInvoke) {
5653 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5654 DelegateType.GetSignatureForError ());
5656 ec.Report.SymbolRelatedToPreviousError (method);
5657 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5658 method.GetSignatureForError ());
5661 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5663 string index = (idx + 1).ToString ();
5664 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5665 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5666 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5667 index, Parameter.GetModifierSignature (a.Modifier));
5669 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5670 index, Parameter.GetModifierSignature (mod));
5672 string p1 = a.GetSignatureForError ();
5673 string p2 = paramType.GetSignatureForError ();
5676 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5677 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5680 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5681 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5682 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5685 ec.Report.Error (1503, a.Expr.Location,
5686 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5691 // We have failed to find exact match so we return error info about the closest match
5693 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5695 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5696 int arg_count = args == null ? 0 : args.Count;
5698 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5699 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5700 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5704 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5709 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5710 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5711 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5715 // For candidates which match on parameters count report more details about incorrect arguments
5718 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5719 // Reject any inaccessible member
5720 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5721 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5722 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5726 var ms = best_candidate as MethodSpec;
5727 if (ms != null && ms.IsGeneric) {
5728 bool constr_ok = true;
5729 if (ms.TypeArguments != null)
5730 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5732 if (ta_count == 0 && ms.TypeArguments == null) {
5733 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5737 rc.Report.Error (411, loc,
5738 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5739 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5746 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5752 // We failed to find any method with correct argument count, report best candidate
5754 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5757 if (best_candidate.Kind == MemberKind.Constructor) {
5758 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5759 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5760 } else if (IsDelegateInvoke) {
5761 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5762 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5763 DelegateType.GetSignatureForError (), arg_count.ToString ());
5765 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5766 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5767 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5768 name, arg_count.ToString ());
5772 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5774 var p = ((IParametersMember)best_candidate).Parameters;
5779 for (int i = p.Count - 1; i != 0; --i) {
5780 var fp = p.FixedParameters [i];
5781 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5791 foreach (var arg in args) {
5792 var na = arg as NamedArgument;
5796 if (na.Name == name) {
5805 return args.Count + 1 == pm.Parameters.Count;
5808 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5810 var pd = pm.Parameters;
5811 var cpd = ((IParametersMember) member).Parameters;
5812 var ptypes = cpd.Types;
5814 Parameter.Modifier p_mod = 0;
5816 int a_idx = 0, a_pos = 0;
5818 ArrayInitializer params_initializers = null;
5819 bool has_unsafe_arg = pm.MemberType.IsPointer;
5820 int arg_count = args == null ? 0 : args.Count;
5822 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5827 if (p_mod != Parameter.Modifier.PARAMS) {
5828 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5830 has_unsafe_arg |= pt.IsPointer;
5832 if (p_mod == Parameter.Modifier.PARAMS) {
5833 if (chose_params_expanded) {
5834 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5835 pt = TypeManager.GetElementType (pt);
5841 // Types have to be identical when ref or out modifer is used
5843 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5844 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5847 var arg_type = a.Type;
5851 if (arg_type == InternalType.VarOutType) {
5853 // Set underlying variable type based on parameter type
5855 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5859 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5863 NamedArgument na = a as NamedArgument;
5865 int name_index = pd.GetParameterIndexByName (na.Name);
5866 if (name_index < 0 || name_index >= pd.Count) {
5867 if (IsDelegateInvoke) {
5868 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5869 ec.Report.Error (1746, na.Location,
5870 "The delegate `{0}' does not contain a parameter named `{1}'",
5871 DelegateType.GetSignatureForError (), na.Name);
5873 ec.Report.SymbolRelatedToPreviousError (member);
5874 ec.Report.Error (1739, na.Location,
5875 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5876 TypeManager.CSharpSignature (member), na.Name);
5878 } else if (args[name_index] != a && args[name_index] != null) {
5879 if (IsDelegateInvoke)
5880 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5882 ec.Report.SymbolRelatedToPreviousError (member);
5884 ec.Report.Error (1744, na.Location,
5885 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5890 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5893 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5894 if (a.IsExtensionType) {
5895 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5896 // CS1061 but that still better than confusing CS0123
5897 var ma = new MemberAccess (a.Expr, member.Name, loc);
5898 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5900 custom_errors.NoArgumentMatch (ec, member);
5906 if (a.IsExtensionType) {
5907 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5910 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5912 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5915 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5922 // Convert params arguments to an array initializer
5924 if (params_initializers != null) {
5925 // we choose to use 'a.Expr' rather than 'conv' so that
5926 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5927 params_initializers.Add (a.Expr);
5928 args.RemoveAt (a_idx--);
5934 // Update the argument with the implicit conversion
5938 if (a_idx != arg_count) {
5940 // Convert all var out argument to error type for less confusing error reporting
5941 // when no matching overload is found
5943 for (; a_idx < arg_count; a_idx++) {
5944 var arg = args [a_idx];
5948 if (arg.Type == InternalType.VarOutType) {
5949 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5953 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5958 // Fill not provided arguments required by params modifier
5960 if (params_initializers == null && arg_count + 1 == pd.Count) {
5962 args = new Arguments (1);
5964 pt = ptypes[pd.Count - 1];
5965 pt = TypeManager.GetElementType (pt);
5966 has_unsafe_arg |= pt.IsPointer;
5967 params_initializers = new ArrayInitializer (0, loc);
5971 // Append an array argument with all params arguments
5973 if (params_initializers != null) {
5974 args.Add (new Argument (
5975 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5979 if (has_unsafe_arg && !ec.IsUnsafe) {
5980 Expression.UnsafeError (ec, loc);
5984 // We could infer inaccesible type arguments
5986 if (type_arguments == null && member.IsGeneric) {
5987 var ms = (MethodSpec) member;
5988 foreach (var ta in ms.TypeArguments) {
5989 if (!ta.IsAccessible (ec)) {
5990 ec.Report.SymbolRelatedToPreviousError (ta);
5991 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
6001 public class ConstantExpr : MemberExpr
6003 readonly ConstSpec constant;
6005 public ConstantExpr (ConstSpec constant, Location loc)
6007 this.constant = constant;
6011 public override string Name {
6012 get { throw new NotImplementedException (); }
6015 public override string KindName {
6016 get { return "constant"; }
6019 public override bool IsInstance {
6020 get { return !IsStatic; }
6023 public override bool IsStatic {
6024 get { return true; }
6027 protected override TypeSpec DeclaringType {
6028 get { return constant.DeclaringType; }
6031 public override Expression CreateExpressionTree (ResolveContext ec)
6033 throw new NotSupportedException ("ET");
6036 protected override Expression DoResolve (ResolveContext rc)
6038 ResolveInstanceExpression (rc, null);
6039 DoBestMemberChecks (rc, constant);
6041 var c = constant.GetConstant (rc);
6043 // Creates reference expression to the constant value
6044 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6047 public override void Emit (EmitContext ec)
6049 throw new NotSupportedException ();
6052 public override string GetSignatureForError ()
6054 return constant.GetSignatureForError ();
6057 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6059 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6064 // Fully resolved expression that references a Field
6066 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6068 protected FieldSpec spec;
6069 VariableInfo variable_info;
6071 LocalTemporary temp;
6074 protected FieldExpr (Location l)
6079 public FieldExpr (FieldSpec spec, Location loc)
6084 type = spec.MemberType;
6087 public FieldExpr (FieldBase fi, Location l)
6094 public override string Name {
6100 public bool IsHoisted {
6102 IVariableReference hv = InstanceExpression as IVariableReference;
6103 return hv != null && hv.IsHoisted;
6107 public override bool IsInstance {
6109 return !spec.IsStatic;
6113 public override bool IsStatic {
6115 return spec.IsStatic;
6119 public override string KindName {
6120 get { return "field"; }
6123 public FieldSpec Spec {
6129 protected override TypeSpec DeclaringType {
6131 return spec.DeclaringType;
6135 public VariableInfo VariableInfo {
6137 return variable_info;
6143 public override string GetSignatureForError ()
6145 return spec.GetSignatureForError ();
6148 public bool IsMarshalByRefAccess (ResolveContext rc)
6150 // Checks possible ldflda of field access expression
6151 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6152 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6153 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6156 public void SetHasAddressTaken ()
6158 IVariableReference vr = InstanceExpression as IVariableReference;
6160 vr.SetHasAddressTaken ();
6164 protected override void CloneTo (CloneContext clonectx, Expression target)
6166 var t = (FieldExpr) target;
6168 if (InstanceExpression != null)
6169 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6172 public override Expression CreateExpressionTree (ResolveContext ec)
6174 if (ConditionalAccess) {
6175 Error_NullShortCircuitInsideExpressionTree (ec);
6178 return CreateExpressionTree (ec, true);
6181 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6184 Expression instance;
6186 if (InstanceExpression == null) {
6187 instance = new NullLiteral (loc);
6188 } else if (convertInstance) {
6189 instance = InstanceExpression.CreateExpressionTree (ec);
6191 args = new Arguments (1);
6192 args.Add (new Argument (InstanceExpression));
6193 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6196 args = Arguments.CreateForExpressionTree (ec, null,
6198 CreateTypeOfExpression ());
6200 return CreateExpressionFactoryCall (ec, "Field", args);
6203 public Expression CreateTypeOfExpression ()
6205 return new TypeOfField (spec, loc);
6208 protected override Expression DoResolve (ResolveContext ec)
6210 spec.MemberDefinition.SetIsUsed ();
6212 return DoResolve (ec, null);
6215 Expression DoResolve (ResolveContext ec, Expression rhs)
6217 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6220 ResolveConditionalAccessReceiver (ec);
6222 if (ResolveInstanceExpression (ec, rhs)) {
6223 // Resolve the field's instance expression while flow analysis is turned
6224 // off: when accessing a field "a.b", we must check whether the field
6225 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6227 if (lvalue_instance) {
6228 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6230 Expression right_side =
6231 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6233 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6235 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6238 if (InstanceExpression == null)
6242 DoBestMemberChecks (ec, spec);
6244 if (conditional_access_receiver)
6245 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6248 var fb = spec as FixedFieldSpec;
6249 IVariableReference var = InstanceExpression as IVariableReference;
6252 IFixedExpression fe = InstanceExpression as IFixedExpression;
6253 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6254 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6257 if (InstanceExpression.eclass != ExprClass.Variable) {
6258 ec.Report.SymbolRelatedToPreviousError (spec);
6259 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6260 TypeManager.GetFullNameSignature (spec));
6261 } else if (var != null && var.IsHoisted) {
6262 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6265 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6269 // Set flow-analysis variable info for struct member access. It will be check later
6270 // for precise error reporting
6272 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6273 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6276 if (ConditionalAccess) {
6277 if (conditional_access_receiver)
6278 type = LiftMemberType (ec, type);
6280 if (InstanceExpression.IsNull)
6281 return Constant.CreateConstantFromValue (type, null, loc);
6284 eclass = ExprClass.Variable;
6288 public void SetFieldAssigned (FlowAnalysisContext fc)
6293 bool lvalue_instance = spec.DeclaringType.IsStruct;
6294 if (lvalue_instance) {
6295 var var = InstanceExpression as IVariableReference;
6296 if (var != null && var.VariableInfo != null) {
6297 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6301 var fe = InstanceExpression as FieldExpr;
6303 Expression instance;
6306 instance = fe.InstanceExpression;
6307 var fe_instance = instance as FieldExpr;
6308 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6309 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6310 var var = InstanceExpression as IVariableReference;
6311 if (var != null && var.VariableInfo == null) {
6312 var var_inst = instance as IVariableReference;
6313 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6314 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6318 if (fe_instance != null) {
6327 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6328 instance.FlowAnalysis (fc);
6330 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6331 InstanceExpression.FlowAnalysis (fc);
6335 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6337 // The return value is always null. Returning a value simplifies calling code.
6339 if (right_side == EmptyExpression.OutAccess) {
6341 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6342 GetSignatureForError ());
6344 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6345 GetSignatureForError ());
6351 if (right_side == EmptyExpression.LValueMemberAccess) {
6352 // Already reported as CS1648/CS1650
6356 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6358 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6359 GetSignatureForError ());
6361 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6362 GetSignatureForError ());
6368 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6369 GetSignatureForError ());
6371 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6372 GetSignatureForError ());
6378 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6380 if (ConditionalAccess)
6381 Error_NullPropagatingLValue (ec);
6383 if (spec is FixedFieldSpec) {
6384 // It could be much better error message but we want to be error compatible
6385 Error_ValueAssignment (ec, right_side);
6388 Expression e = DoResolve (ec, right_side);
6393 spec.MemberDefinition.SetIsAssigned ();
6395 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6396 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6397 ec.Report.Warning (420, 1, loc,
6398 "`{0}': A volatile field references will not be treated as volatile",
6399 spec.GetSignatureForError ());
6402 if (spec.IsReadOnly) {
6403 // InitOnly fields can only be assigned in constructors or initializers
6404 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6405 return Error_AssignToReadonly (ec, right_side);
6407 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6409 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6410 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6411 return Error_AssignToReadonly (ec, right_side);
6412 // static InitOnly fields cannot be assigned-to in an instance constructor
6413 if (IsStatic && !ec.IsStatic)
6414 return Error_AssignToReadonly (ec, right_side);
6415 // instance constructors can't modify InitOnly fields of other instances of the same type
6416 if (!IsStatic && !(InstanceExpression is This))
6417 return Error_AssignToReadonly (ec, right_side);
6421 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6422 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6423 ec.Report.Warning (197, 1, loc,
6424 "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",
6425 GetSignatureForError ());
6428 eclass = ExprClass.Variable;
6432 public override void FlowAnalysis (FlowAnalysisContext fc)
6434 var var = InstanceExpression as IVariableReference;
6436 var vi = var.VariableInfo;
6437 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6438 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6442 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6446 base.FlowAnalysis (fc);
6448 if (conditional_access_receiver)
6449 fc.ConditionalAccessEnd ();
6452 public override int GetHashCode ()
6454 return spec.GetHashCode ();
6457 public bool IsFixed {
6460 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6462 IVariableReference variable = InstanceExpression as IVariableReference;
6463 if (variable != null)
6464 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6466 IFixedExpression fe = InstanceExpression as IFixedExpression;
6467 return fe != null && fe.IsFixed;
6471 public override bool Equals (object obj)
6473 FieldExpr fe = obj as FieldExpr;
6477 if (spec != fe.spec)
6480 if (InstanceExpression == null || fe.InstanceExpression == null)
6483 return InstanceExpression.Equals (fe.InstanceExpression);
6486 public void Emit (EmitContext ec, bool leave_copy)
6488 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6492 ec.Emit (OpCodes.Volatile);
6494 ec.Emit (OpCodes.Ldsfld, spec);
6497 if (conditional_access_receiver)
6498 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6500 EmitInstance (ec, false);
6503 // Optimization for build-in types
6504 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6505 ec.EmitLoadFromPtr (type);
6507 var ff = spec as FixedFieldSpec;
6509 ec.Emit (OpCodes.Ldflda, spec);
6510 ec.Emit (OpCodes.Ldflda, ff.Element);
6513 ec.Emit (OpCodes.Volatile);
6515 ec.Emit (OpCodes.Ldfld, spec);
6519 if (conditional_access_receiver) {
6520 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6525 ec.Emit (OpCodes.Dup);
6527 temp = new LocalTemporary (this.Type);
6533 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6535 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6536 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6541 if (ConditionalAccess)
6542 throw new NotImplementedException ("null operator assignment");
6544 if (has_await_source)
6545 source = source.EmitToField (ec);
6547 EmitInstance (ec, prepared);
6552 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6553 ec.Emit (OpCodes.Dup);
6555 temp = new LocalTemporary (this.Type);
6560 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6561 ec.Emit (OpCodes.Volatile);
6563 spec.MemberDefinition.SetIsAssigned ();
6566 ec.Emit (OpCodes.Stsfld, spec);
6568 ec.Emit (OpCodes.Stfld, spec);
6570 if (ec.NotifyEvaluatorOnStore) {
6572 throw new NotImplementedException ("instance field write");
6575 ec.Emit (OpCodes.Dup);
6577 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6588 // Emits store to field with prepared values on stack
6590 public void EmitAssignFromStack (EmitContext ec)
6593 ec.Emit (OpCodes.Stsfld, spec);
6595 ec.Emit (OpCodes.Stfld, spec);
6599 public override void Emit (EmitContext ec)
6604 public override void EmitSideEffect (EmitContext ec)
6606 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6608 if (is_volatile) // || is_marshal_by_ref ())
6609 base.EmitSideEffect (ec);
6612 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6614 if ((mode & AddressOp.Store) != 0)
6615 spec.MemberDefinition.SetIsAssigned ();
6616 if ((mode & AddressOp.Load) != 0)
6617 spec.MemberDefinition.SetIsUsed ();
6620 // Handle initonly fields specially: make a copy and then
6621 // get the address of the copy.
6624 if (spec.IsReadOnly){
6626 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6638 var temp = ec.GetTemporaryLocal (type);
6639 ec.Emit (OpCodes.Stloc, temp);
6640 ec.Emit (OpCodes.Ldloca, temp);
6646 ec.Emit (OpCodes.Ldsflda, spec);
6649 EmitInstance (ec, false);
6650 ec.Emit (OpCodes.Ldflda, spec);
6654 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6656 return MakeExpression (ctx);
6659 public override SLE.Expression MakeExpression (BuilderContext ctx)
6662 return base.MakeExpression (ctx);
6664 return SLE.Expression.Field (
6665 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6666 spec.GetMetaInfo ());
6670 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6672 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6678 // Expression that evaluates to a Property.
6680 // This is not an LValue because we need to re-write the expression. We
6681 // can not take data from the stack and store it.
6683 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6685 Arguments arguments;
6686 FieldExpr backing_field;
6688 public PropertyExpr (PropertySpec spec, Location l)
6691 best_candidate = spec;
6692 type = spec.MemberType;
6697 protected override Arguments Arguments {
6706 protected override TypeSpec DeclaringType {
6708 return best_candidate.DeclaringType;
6712 public override string Name {
6714 return best_candidate.Name;
6718 public bool IsAutoPropertyAccess {
6720 var prop = best_candidate.MemberDefinition as Property;
6721 return prop != null && prop.BackingField != null;
6725 public override bool IsInstance {
6731 public override bool IsStatic {
6733 return best_candidate.IsStatic;
6737 public override string KindName {
6738 get { return "property"; }
6741 public PropertySpec PropertyInfo {
6743 return best_candidate;
6749 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6751 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6754 var args_count = arguments == null ? 0 : arguments.Count;
6755 if (args_count != body.Parameters.Count && args_count == 0)
6758 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6759 mg.InstanceExpression = InstanceExpression;
6764 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6766 return new PropertyExpr (spec, loc) {
6772 public override Expression CreateExpressionTree (ResolveContext ec)
6774 if (ConditionalAccess) {
6775 Error_NullShortCircuitInsideExpressionTree (ec);
6779 if (IsSingleDimensionalArrayLength ()) {
6780 args = new Arguments (1);
6781 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6782 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6785 args = new Arguments (2);
6786 if (InstanceExpression == null)
6787 args.Add (new Argument (new NullLiteral (loc)));
6789 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6790 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6791 return CreateExpressionFactoryCall (ec, "Property", args);
6794 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6796 DoResolveLValue (rc, null);
6797 return new TypeOfMethod (Setter, loc);
6800 public override string GetSignatureForError ()
6802 return best_candidate.GetSignatureForError ();
6805 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6808 return base.MakeExpression (ctx);
6810 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6814 public override SLE.Expression MakeExpression (BuilderContext ctx)
6817 return base.MakeExpression (ctx);
6819 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6823 void Error_PropertyNotValid (ResolveContext ec)
6825 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6826 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6827 GetSignatureForError ());
6830 bool IsSingleDimensionalArrayLength ()
6832 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6835 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6836 return ac != null && ac.Rank == 1;
6839 public override void Emit (EmitContext ec, bool leave_copy)
6842 // Special case: length of single dimension array property is turned into ldlen
6844 if (IsSingleDimensionalArrayLength ()) {
6845 if (conditional_access_receiver) {
6846 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6849 EmitInstance (ec, false);
6851 ec.Emit (OpCodes.Ldlen);
6852 ec.Emit (OpCodes.Conv_I4);
6854 if (conditional_access_receiver) {
6855 ec.CloseConditionalAccess (type);
6861 base.Emit (ec, leave_copy);
6864 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6866 if (backing_field != null) {
6867 backing_field.EmitAssign (ec, source, false, false);
6872 LocalTemporary await_source_arg = null;
6874 if (isCompound && !(source is DynamicExpressionStatement)) {
6875 emitting_compound_assignment = true;
6878 if (has_await_arguments) {
6879 await_source_arg = new LocalTemporary (Type);
6880 await_source_arg.Store (ec);
6882 args = new Arguments (1);
6883 args.Add (new Argument (await_source_arg));
6886 temp = await_source_arg;
6889 has_await_arguments = false;
6894 ec.Emit (OpCodes.Dup);
6895 temp = new LocalTemporary (this.Type);
6900 args = arguments ?? new Arguments (1);
6904 temp = new LocalTemporary (this.Type);
6906 args.Add (new Argument (temp));
6908 args.Add (new Argument (source));
6912 emitting_compound_assignment = false;
6914 var call = new CallEmitter ();
6915 call.InstanceExpression = InstanceExpression;
6917 call.InstanceExpressionOnStack = true;
6919 if (ConditionalAccess) {
6920 call.ConditionalAccess = true;
6924 call.Emit (ec, Setter, args, loc);
6926 call.EmitStatement (ec, Setter, args, loc);
6933 if (await_source_arg != null) {
6934 await_source_arg.Release (ec);
6938 public override void FlowAnalysis (FlowAnalysisContext fc)
6940 var prop = best_candidate.MemberDefinition as Property;
6941 if (prop != null && prop.BackingField != null) {
6942 var var = InstanceExpression as IVariableReference;
6944 var vi = var.VariableInfo;
6945 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6946 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6950 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6955 base.FlowAnalysis (fc);
6957 if (conditional_access_receiver)
6958 fc.ConditionalAccessEnd ();
6961 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6963 eclass = ExprClass.PropertyAccess;
6965 if (best_candidate.IsNotCSharpCompatible) {
6966 Error_PropertyNotValid (rc);
6969 ResolveInstanceExpression (rc, right_side);
6971 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6972 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6973 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6975 type = p.MemberType;
6979 DoBestMemberChecks (rc, best_candidate);
6981 // Handling of com-imported properties with any number of default property parameters
6982 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6983 var p = best_candidate.Get.Parameters;
6984 arguments = new Arguments (p.Count);
6985 for (int i = 0; i < p.Count; ++i) {
6986 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6988 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6989 var p = best_candidate.Set.Parameters;
6990 arguments = new Arguments (p.Count - 1);
6991 for (int i = 0; i < p.Count - 1; ++i) {
6992 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6999 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7001 var prop = best_candidate.MemberDefinition as Property;
7005 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
7008 var spec = prop.BackingField;
7012 if (rc.IsStatic != spec.IsStatic)
7015 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7018 backing_field = new FieldExpr (prop.BackingField, loc);
7019 backing_field.ResolveLValue (rc, rhs);
7023 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7025 if (backing_field != null) {
7026 backing_field.SetFieldAssigned (fc);
7030 if (!IsAutoPropertyAccess)
7033 var prop = best_candidate.MemberDefinition as Property;
7034 if (prop != null && prop.BackingField != null) {
7035 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7036 if (lvalue_instance) {
7037 var var = InstanceExpression as IVariableReference;
7038 if (var != null && var.VariableInfo != null) {
7039 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7045 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7047 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7051 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7053 // getter and setter can be different for base calls
7054 MethodSpec getter, setter;
7055 protected T best_candidate;
7057 protected LocalTemporary temp;
7058 protected bool emitting_compound_assignment;
7059 protected bool has_await_arguments;
7061 protected PropertyOrIndexerExpr (Location l)
7068 protected abstract Arguments Arguments { get; set; }
7070 public MethodSpec Getter {
7079 public MethodSpec Setter {
7090 protected override Expression DoResolve (ResolveContext ec)
7092 if (eclass == ExprClass.Unresolved) {
7093 ResolveConditionalAccessReceiver (ec);
7095 var expr = OverloadResolve (ec, null);
7100 return expr.Resolve (ec);
7102 if (conditional_access_receiver) {
7103 type = LiftMemberType (ec, type);
7104 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7108 if (!ResolveGetter (ec))
7114 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7116 if (ConditionalAccess)
7117 Error_NullPropagatingLValue (rc);
7119 if (right_side == EmptyExpression.OutAccess) {
7120 // TODO: best_candidate can be null at this point
7121 INamedBlockVariable variable = null;
7122 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7123 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7124 best_candidate.Name);
7126 right_side.DoResolveLValue (rc, this);
7131 if (eclass == ExprClass.Unresolved) {
7132 var expr = OverloadResolve (rc, right_side);
7137 return expr.ResolveLValue (rc, right_side);
7139 ResolveInstanceExpression (rc, right_side);
7142 if (!best_candidate.HasSet) {
7143 if (ResolveAutopropertyAssignment (rc, right_side))
7146 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7147 GetSignatureForError ());
7151 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7152 if (best_candidate.HasDifferentAccessibility) {
7153 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7154 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7155 GetSignatureForError ());
7157 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7158 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7162 if (best_candidate.HasDifferentAccessibility)
7163 CheckProtectedMemberAccess (rc, best_candidate.Set);
7165 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7169 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7171 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7173 call.Emit (ec, method, arguments, loc);
7175 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7179 // Implements the IAssignMethod interface for assignments
7181 public virtual void Emit (EmitContext ec, bool leave_copy)
7183 var call = new CallEmitter ();
7184 call.ConditionalAccess = ConditionalAccess;
7185 call.InstanceExpression = InstanceExpression;
7186 if (has_await_arguments)
7187 call.HasAwaitArguments = true;
7189 call.DuplicateArguments = emitting_compound_assignment;
7191 if (conditional_access_receiver)
7192 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7194 call.Emit (ec, Getter, Arguments, loc);
7196 if (call.HasAwaitArguments) {
7197 InstanceExpression = call.InstanceExpression;
7198 Arguments = call.EmittedArguments;
7199 has_await_arguments = true;
7203 ec.Emit (OpCodes.Dup);
7204 temp = new LocalTemporary (Type);
7209 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7211 public override void Emit (EmitContext ec)
7216 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7218 has_await_arguments = true;
7223 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7225 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7227 bool ResolveGetter (ResolveContext rc)
7229 if (!best_candidate.HasGet) {
7230 if (InstanceExpression != EmptyExpression.Null) {
7231 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7232 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7233 best_candidate.GetSignatureForError ());
7236 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7237 if (best_candidate.HasDifferentAccessibility) {
7238 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7239 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7240 TypeManager.CSharpSignature (best_candidate));
7242 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7243 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7247 if (best_candidate.HasDifferentAccessibility) {
7248 CheckProtectedMemberAccess (rc, best_candidate.Get);
7251 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7255 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7262 /// Fully resolved expression that evaluates to an Event
7264 public class EventExpr : MemberExpr, IAssignMethod
7266 readonly EventSpec spec;
7269 public EventExpr (EventSpec spec, Location loc)
7277 protected override TypeSpec DeclaringType {
7279 return spec.DeclaringType;
7283 public override string Name {
7289 public override bool IsInstance {
7291 return !spec.IsStatic;
7295 public override bool IsStatic {
7297 return spec.IsStatic;
7301 public override string KindName {
7302 get { return "event"; }
7305 public MethodSpec Operator {
7313 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7316 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7318 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7319 if (spec.BackingField != null &&
7320 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7322 spec.MemberDefinition.SetIsUsed ();
7324 if (!ec.IsObsolete) {
7325 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7327 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7330 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7331 Error_AssignmentEventOnly (ec);
7333 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7335 InstanceExpression = null;
7337 return ml.ResolveMemberAccess (ec, left, original);
7341 return base.ResolveMemberAccess (ec, left, original);
7344 public override Expression CreateExpressionTree (ResolveContext ec)
7346 throw new NotSupportedException ("ET");
7349 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7351 if (right_side == EmptyExpression.EventAddition) {
7352 op = spec.AccessorAdd;
7353 } else if (right_side == EmptyExpression.EventSubtraction) {
7354 op = spec.AccessorRemove;
7358 Error_AssignmentEventOnly (ec);
7362 if (ConditionalAccess)
7363 Error_NullPropagatingLValue (ec);
7365 op = CandidateToBaseOverride (ec, op);
7369 protected override Expression DoResolve (ResolveContext ec)
7371 eclass = ExprClass.EventAccess;
7372 type = spec.MemberType;
7374 ResolveInstanceExpression (ec, null);
7376 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7377 Error_AssignmentEventOnly (ec);
7380 DoBestMemberChecks (ec, spec);
7384 public override void Emit (EmitContext ec)
7386 throw new NotSupportedException ();
7387 //Error_CannotAssign ();
7390 #region IAssignMethod Members
7392 public void Emit (EmitContext ec, bool leave_copy)
7394 throw new NotImplementedException ();
7397 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7399 if (leave_copy || !isCompound)
7400 throw new NotImplementedException ("EventExpr::EmitAssign");
7402 Arguments args = new Arguments (1);
7403 args.Add (new Argument (source));
7405 // TODO: Wrong, needs receiver
7406 // if (NullShortCircuit) {
7407 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7410 var call = new CallEmitter ();
7411 call.InstanceExpression = InstanceExpression;
7412 call.ConditionalAccess = ConditionalAccess;
7413 call.EmitStatement (ec, op, args, loc);
7415 // if (NullShortCircuit)
7416 // ec.CloseConditionalAccess (null);
7421 void Error_AssignmentEventOnly (ResolveContext ec)
7423 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7424 ec.Report.Error (79, loc,
7425 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7426 GetSignatureForError ());
7428 ec.Report.Error (70, loc,
7429 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7430 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7434 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7436 name = name.Substring (0, name.LastIndexOf ('.'));
7437 base.Error_CannotCallAbstractBase (rc, name);
7440 public override string GetSignatureForError ()
7442 return TypeManager.CSharpSignature (spec);
7445 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7447 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7451 public class TemporaryVariableReference : VariableReference
7453 public class Declarator : Statement
7455 TemporaryVariableReference variable;
7457 public Declarator (TemporaryVariableReference variable)
7459 this.variable = variable;
7463 protected override void DoEmit (EmitContext ec)
7465 variable.li.CreateBuilder (ec);
7468 public override void Emit (EmitContext ec)
7470 // Don't create sequence point
7474 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7479 protected override void CloneTo (CloneContext clonectx, Statement target)
7487 public TemporaryVariableReference (LocalVariable li, Location loc)
7490 this.type = li.Type;
7494 public override bool IsLockedByStatement {
7502 public LocalVariable LocalInfo {
7508 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7510 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7511 return new TemporaryVariableReference (li, loc);
7514 protected override Expression DoResolve (ResolveContext ec)
7516 eclass = ExprClass.Variable;
7519 // Don't capture temporary variables except when using
7520 // state machine redirection and block yields
7522 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7523 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7524 ec.IsVariableCapturingRequired) {
7525 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7526 storey.CaptureLocalVariable (ec, li);
7532 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7534 return Resolve (ec);
7537 public override void Emit (EmitContext ec)
7539 li.CreateBuilder (ec);
7544 public void EmitAssign (EmitContext ec, Expression source)
7546 li.CreateBuilder (ec);
7548 EmitAssign (ec, source, false, false);
7551 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7553 return li.HoistedVariant;
7556 public override bool IsFixed {
7557 get { return true; }
7560 public override bool IsRef {
7561 get { return false; }
7564 public override string Name {
7565 get { throw new NotImplementedException (); }
7568 public override void SetHasAddressTaken ()
7570 throw new NotImplementedException ();
7573 protected override ILocalVariable Variable {
7577 public override VariableInfo VariableInfo {
7578 get { return null; }
7583 /// Handles `var' contextual keyword; var becomes a keyword only
7584 /// if no type called var exists in a variable scope
7586 class VarExpr : SimpleName
7588 public VarExpr (Location loc)
7593 public bool InferType (ResolveContext ec, Expression right_side)
7596 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7598 type = right_side.Type;
7599 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7600 ec.Report.Error (815, loc,
7601 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7602 type.GetSignatureForError ());
7606 eclass = ExprClass.Variable;
7610 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7612 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7613 base.Error_TypeOrNamespaceNotFound (ec);
7615 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");