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))
988 members = new List<MemberSpec> (members);
991 members.RemoveAt (i--);
999 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1001 throw new NotImplementedException ();
1004 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1006 if (t == InternalType.ErrorType)
1009 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1010 oper, t.GetSignatureForError ());
1013 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1015 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1018 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1020 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1023 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1028 // Special version of flow analysis for expressions which can return different
1029 // on-true and on-false result. Used by &&, ||, ?: expressions
1031 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1034 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1038 /// Returns an expression that can be used to invoke operator true
1039 /// on the expression if it exists.
1041 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1043 return GetOperatorTrueOrFalse (ec, e, true, loc);
1047 /// Returns an expression that can be used to invoke operator false
1048 /// on the expression if it exists.
1050 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1052 return GetOperatorTrueOrFalse (ec, e, false, loc);
1055 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1057 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1059 if (type.IsNullableType)
1060 type = Nullable.NullableInfo.GetUnderlyingType (type);
1062 var methods = MemberCache.GetUserOperator (type, op, false);
1063 if (methods == null)
1066 Arguments arguments = new Arguments (1);
1067 arguments.Add (new Argument (e));
1069 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1070 var oper = res.ResolveOperator (ec, ref arguments);
1075 return new UserOperatorCall (oper, arguments, null, loc);
1078 public virtual string ExprClassName
1082 case ExprClass.Unresolved:
1083 return "Unresolved";
1084 case ExprClass.Value:
1086 case ExprClass.Variable:
1088 case ExprClass.Namespace:
1090 case ExprClass.Type:
1092 case ExprClass.MethodGroup:
1093 return "method group";
1094 case ExprClass.PropertyAccess:
1095 return "property access";
1096 case ExprClass.EventAccess:
1097 return "event access";
1098 case ExprClass.IndexerAccess:
1099 return "indexer access";
1100 case ExprClass.Nothing:
1102 case ExprClass.TypeParameter:
1103 return "type parameter";
1105 throw new Exception ("Should not happen");
1110 /// Reports that we were expecting `expr' to be of class `expected'
1112 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1114 var name = memberExpr.GetSignatureForError ();
1116 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1119 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1121 string [] valid = new string [4];
1124 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1125 valid [count++] = "variable";
1126 valid [count++] = "value";
1129 if ((flags & ResolveFlags.Type) != 0)
1130 valid [count++] = "type";
1132 if ((flags & ResolveFlags.MethodGroup) != 0)
1133 valid [count++] = "method group";
1136 valid [count++] = "unknown";
1138 StringBuilder sb = new StringBuilder (valid [0]);
1139 for (int i = 1; i < count - 1; i++) {
1141 sb.Append (valid [i]);
1144 sb.Append ("' or `");
1145 sb.Append (valid [count - 1]);
1148 ec.Report.Error (119, loc,
1149 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1152 public static void UnsafeError (ResolveContext ec, Location loc)
1154 UnsafeError (ec.Report, loc);
1157 public static void UnsafeError (Report Report, Location loc)
1159 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1163 // Converts `source' to an int, uint, long or ulong.
1165 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1167 var btypes = ec.BuiltinTypes;
1169 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1170 Arguments args = new Arguments (1);
1171 args.Add (new Argument (source));
1172 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1175 Expression converted;
1177 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1178 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1179 if (converted == null)
1180 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1181 if (converted == null)
1182 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1183 if (converted == null)
1184 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1186 if (converted == null) {
1187 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1196 // Only positive constants are allowed at compile time
1198 Constant c = converted as Constant;
1199 if (c != null && c.IsNegative)
1200 Error_NegativeArrayIndex (ec, source.loc);
1202 // No conversion needed to array index
1203 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1206 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1210 // Derived classes implement this method by cloning the fields that
1211 // could become altered during the Resolve stage
1213 // Only expressions that are created for the parser need to implement
1216 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1218 throw new NotImplementedException (
1220 "CloneTo not implemented for expression {0}", this.GetType ()));
1224 // Clones an expression created by the parser.
1226 // We only support expressions created by the parser so far, not
1227 // expressions that have been resolved (many more classes would need
1228 // to implement CloneTo).
1230 // This infrastructure is here merely for Lambda expressions which
1231 // compile the same code using different type values for the same
1232 // arguments to find the correct overload
1234 public virtual Expression Clone (CloneContext clonectx)
1236 Expression cloned = (Expression) MemberwiseClone ();
1237 CloneTo (clonectx, cloned);
1243 // Implementation of expression to expression tree conversion
1245 public abstract Expression CreateExpressionTree (ResolveContext ec);
1247 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1249 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1252 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1254 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1257 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1259 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1262 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1264 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1268 return new TypeExpression (t, loc);
1272 // Implemented by all expressions which support conversion from
1273 // compiler expression to invokable runtime expression. Used by
1274 // dynamic C# binder.
1276 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1278 throw new NotImplementedException ("MakeExpression for " + GetType ());
1281 public virtual object Accept (StructuralVisitor visitor)
1283 return visitor.Visit (this);
1288 /// This is just a base class for expressions that can
1289 /// appear on statements (invocations, object creation,
1290 /// assignments, post/pre increment and decrement). The idea
1291 /// being that they would support an extra Emition interface that
1292 /// does not leave a result on the stack.
1294 public abstract class ExpressionStatement : Expression
1296 public virtual void MarkReachable (Reachability rc)
1300 public ExpressionStatement ResolveStatement (BlockContext ec)
1302 Expression e = Resolve (ec);
1306 ExpressionStatement es = e as ExpressionStatement;
1307 if (es == null || e is AnonymousMethodBody)
1308 Error_InvalidExpressionStatement (ec);
1311 // This is quite expensive warning, try to limit the damage
1313 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1314 WarningAsyncWithoutWait (ec, e);
1320 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1322 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1323 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1328 // Need to do full resolve because GetAwaiter can be extension method
1329 // available only in this context
1331 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1335 var arguments = new Arguments (0);
1336 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1341 // Use same check rules as for real await
1343 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1344 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1347 bc.Report.Warning (4014, 1, e.Location,
1348 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1352 var inv = e as Invocation;
1353 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1354 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1355 bc.Report.Warning (4014, 1, e.Location,
1356 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1362 /// Requests the expression to be emitted in a `statement'
1363 /// context. This means that no new value is left on the
1364 /// stack after invoking this method (constrasted with
1365 /// Emit that will always leave a value on the stack).
1367 public abstract void EmitStatement (EmitContext ec);
1369 public override void EmitSideEffect (EmitContext ec)
1376 /// This kind of cast is used to encapsulate the child
1377 /// whose type is child.Type into an expression that is
1378 /// reported to return "return_type". This is used to encapsulate
1379 /// expressions which have compatible types, but need to be dealt
1380 /// at higher levels with.
1382 /// For example, a "byte" expression could be encapsulated in one
1383 /// of these as an "unsigned int". The type for the expression
1384 /// would be "unsigned int".
1387 public abstract class TypeCast : Expression
1389 protected readonly Expression child;
1391 protected TypeCast (Expression child, TypeSpec return_type)
1393 eclass = child.eclass;
1394 loc = child.Location;
1399 public Expression Child {
1405 public override bool ContainsEmitWithAwait ()
1407 return child.ContainsEmitWithAwait ();
1410 public override Expression CreateExpressionTree (ResolveContext ec)
1412 Arguments args = new Arguments (2);
1413 args.Add (new Argument (child.CreateExpressionTree (ec)));
1414 args.Add (new Argument (new TypeOf (type, loc)));
1416 if (type.IsPointer || child.Type.IsPointer)
1417 Error_PointerInsideExpressionTree (ec);
1419 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1422 protected override Expression DoResolve (ResolveContext ec)
1424 // This should never be invoked, we are born in fully
1425 // initialized state.
1430 public override void Emit (EmitContext ec)
1435 public override void FlowAnalysis (FlowAnalysisContext fc)
1437 child.FlowAnalysis (fc);
1440 public override SLE.Expression MakeExpression (BuilderContext ctx)
1443 return base.MakeExpression (ctx);
1445 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1446 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1447 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1451 protected override void CloneTo (CloneContext clonectx, Expression t)
1456 public override bool IsNull {
1457 get { return child.IsNull; }
1461 public class EmptyCast : TypeCast {
1462 EmptyCast (Expression child, TypeSpec target_type)
1463 : base (child, target_type)
1467 public static Expression Create (Expression child, TypeSpec type)
1469 Constant c = child as Constant;
1471 var enum_constant = c as EnumConstant;
1472 if (enum_constant != null)
1473 c = enum_constant.Child;
1475 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1479 var res = c.ConvertImplicitly (type);
1485 EmptyCast e = child as EmptyCast;
1487 return new EmptyCast (e.child, type);
1489 return new EmptyCast (child, type);
1492 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1494 child.EmitBranchable (ec, label, on_true);
1497 public override void EmitSideEffect (EmitContext ec)
1499 child.EmitSideEffect (ec);
1504 // Used for predefined type user operator (no obsolete check, etc.)
1506 public class OperatorCast : TypeCast
1508 readonly MethodSpec conversion_operator;
1510 public OperatorCast (Expression expr, TypeSpec target_type)
1511 : this (expr, target_type, target_type, false)
1515 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1516 : this (expr, target_type, target_type, find_explicit)
1520 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1521 : base (expr, returnType)
1523 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1524 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1527 foreach (MethodSpec oper in mi) {
1528 if (oper.ReturnType != returnType)
1531 if (oper.Parameters.Types[0] == expr.Type) {
1532 conversion_operator = oper;
1538 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1539 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1542 public override void Emit (EmitContext ec)
1545 ec.Emit (OpCodes.Call, conversion_operator);
1550 // Constant specialization of EmptyCast.
1551 // We need to special case this since an empty cast of
1552 // a constant is still a constant.
1554 public class EmptyConstantCast : Constant
1556 public readonly Constant child;
1558 public EmptyConstantCast (Constant child, TypeSpec type)
1559 : base (child.Location)
1562 throw new ArgumentNullException ("child");
1565 this.eclass = child.eclass;
1569 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1571 if (child.Type == target_type)
1574 // FIXME: check that 'type' can be converted to 'target_type' first
1575 return child.ConvertExplicitly (in_checked_context, target_type);
1578 public override Expression CreateExpressionTree (ResolveContext ec)
1580 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1581 child.CreateExpressionTree (ec),
1582 new TypeOf (type, loc));
1585 Error_PointerInsideExpressionTree (ec);
1587 return CreateExpressionFactoryCall (ec, "Convert", args);
1590 public override bool IsDefaultValue {
1591 get { return child.IsDefaultValue; }
1594 public override bool IsNegative {
1595 get { return child.IsNegative; }
1598 public override bool IsNull {
1599 get { return child.IsNull; }
1602 public override bool IsOneInteger {
1603 get { return child.IsOneInteger; }
1606 public override bool IsSideEffectFree {
1608 return child.IsSideEffectFree;
1612 public override bool IsZeroInteger {
1613 get { return child.IsZeroInteger; }
1616 public override void Emit (EmitContext ec)
1621 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1623 child.EmitBranchable (ec, label, on_true);
1625 // Only to make verifier happy
1626 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1627 ec.Emit (OpCodes.Unbox_Any, type);
1630 public override void EmitSideEffect (EmitContext ec)
1632 child.EmitSideEffect (ec);
1635 public override object GetValue ()
1637 return child.GetValue ();
1640 public override string GetValueAsLiteral ()
1642 return child.GetValueAsLiteral ();
1645 public override long GetValueAsLong ()
1647 return child.GetValueAsLong ();
1650 public override Constant ConvertImplicitly (TypeSpec target_type)
1652 if (type == target_type)
1655 // FIXME: Do we need to check user conversions?
1656 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1659 return child.ConvertImplicitly (target_type);
1664 /// This class is used to wrap literals which belong inside Enums
1666 public class EnumConstant : Constant
1668 public Constant Child;
1670 public EnumConstant (Constant child, TypeSpec enum_type)
1671 : base (child.Location)
1675 this.eclass = ExprClass.Value;
1676 this.type = enum_type;
1679 protected EnumConstant (Location loc)
1684 public override void Emit (EmitContext ec)
1689 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1691 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1694 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1696 Child.EmitBranchable (ec, label, on_true);
1699 public override void EmitSideEffect (EmitContext ec)
1701 Child.EmitSideEffect (ec);
1704 public override string GetSignatureForError()
1706 return Type.GetSignatureForError ();
1709 public override object GetValue ()
1711 return Child.GetValue ();
1715 public override object GetTypedValue ()
1718 // The method can be used in dynamic context only (on closed types)
1720 // System.Enum.ToObject cannot be called on dynamic types
1721 // EnumBuilder has to be used, but we cannot use EnumBuilder
1722 // because it does not properly support generics
1724 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1728 public override string GetValueAsLiteral ()
1730 return Child.GetValueAsLiteral ();
1733 public override long GetValueAsLong ()
1735 return Child.GetValueAsLong ();
1738 public EnumConstant Increment()
1740 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1743 public override bool IsDefaultValue {
1745 return Child.IsDefaultValue;
1749 public override bool IsSideEffectFree {
1751 return Child.IsSideEffectFree;
1755 public override bool IsZeroInteger {
1756 get { return Child.IsZeroInteger; }
1759 public override bool IsNegative {
1761 return Child.IsNegative;
1765 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1767 if (Child.Type == target_type)
1770 return Child.ConvertExplicitly (in_checked_context, target_type);
1773 public override Constant ConvertImplicitly (TypeSpec type)
1775 if (this.type == type) {
1779 if (!Convert.ImplicitStandardConversionExists (this, type)){
1783 return Child.ConvertImplicitly (type);
1788 /// This kind of cast is used to encapsulate Value Types in objects.
1790 /// The effect of it is to box the value type emitted by the previous
1793 public class BoxedCast : TypeCast {
1795 public BoxedCast (Expression expr, TypeSpec target_type)
1796 : base (expr, target_type)
1798 eclass = ExprClass.Value;
1801 protected override Expression DoResolve (ResolveContext ec)
1803 // This should never be invoked, we are born in fully
1804 // initialized state.
1809 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1811 // Only boxing to object type is supported
1812 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1813 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1817 enc.Encode (child.Type);
1818 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1821 public override void Emit (EmitContext ec)
1825 ec.Emit (OpCodes.Box, child.Type);
1828 public override void EmitSideEffect (EmitContext ec)
1830 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1831 // so, we need to emit the box+pop instructions in most cases
1832 if (child.Type.IsStruct &&
1833 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1834 child.EmitSideEffect (ec);
1836 base.EmitSideEffect (ec);
1840 public class UnboxCast : TypeCast {
1841 public UnboxCast (Expression expr, TypeSpec return_type)
1842 : base (expr, return_type)
1846 protected override Expression DoResolve (ResolveContext ec)
1848 // This should never be invoked, we are born in fully
1849 // initialized state.
1854 public override void Emit (EmitContext ec)
1858 ec.Emit (OpCodes.Unbox_Any, type);
1863 /// This is used to perform explicit numeric conversions.
1865 /// Explicit numeric conversions might trigger exceptions in a checked
1866 /// context, so they should generate the conv.ovf opcodes instead of
1869 public class ConvCast : TypeCast {
1870 public enum Mode : byte {
1871 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1873 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1874 U2_I1, U2_U1, U2_I2, U2_CH,
1875 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1876 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1877 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1878 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1879 CH_I1, CH_U1, CH_I2,
1880 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1881 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1887 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1888 : base (child, return_type)
1893 protected override Expression DoResolve (ResolveContext ec)
1895 // This should never be invoked, we are born in fully
1896 // initialized state.
1901 public override string ToString ()
1903 return String.Format ("ConvCast ({0}, {1})", mode, child);
1906 public override void Emit (EmitContext ec)
1912 public static void Emit (EmitContext ec, Mode mode)
1914 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1916 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1917 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1918 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1919 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1920 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1922 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1923 case Mode.U1_CH: /* nothing */ break;
1925 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1926 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1927 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1929 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1930 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1932 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1933 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1934 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1935 case Mode.U2_CH: /* nothing */ break;
1937 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1938 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1939 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1940 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1941 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1942 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1943 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1945 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1946 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1947 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1948 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1949 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1950 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1952 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1953 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1954 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1955 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1956 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1957 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1958 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1959 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1960 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1962 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1963 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1964 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1965 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1966 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1967 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1968 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1969 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1970 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1972 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1973 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1974 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1976 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1977 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1978 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1979 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1980 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1981 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1982 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1983 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1986 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1987 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1988 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1989 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1991 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1992 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1993 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1994 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1995 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1997 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2001 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2002 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2003 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2004 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2005 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2007 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2008 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2011 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2012 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2013 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2014 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2015 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2017 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2018 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2019 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2020 case Mode.U2_CH: /* nothing */ break;
2022 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2023 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2024 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2025 case Mode.I4_U4: /* nothing */ break;
2026 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2027 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2028 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2030 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2031 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2032 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2033 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.U4_I4: /* nothing */ break;
2035 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2037 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2038 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2039 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2040 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2041 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2042 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2043 case Mode.I8_U8: /* nothing */ break;
2044 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2045 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2047 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2048 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2049 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2050 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2051 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2052 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2053 case Mode.U8_I8: /* nothing */ break;
2054 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2055 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2057 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2058 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2059 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2061 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2071 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2072 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2073 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2074 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2076 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2077 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2078 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2079 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2082 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2088 class OpcodeCast : TypeCast
2092 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2093 : base (child, return_type)
2098 protected override Expression DoResolve (ResolveContext ec)
2100 // This should never be invoked, we are born in fully
2101 // initialized state.
2106 public override void Emit (EmitContext ec)
2112 public TypeSpec UnderlyingType {
2113 get { return child.Type; }
2118 // Opcode casts expression with 2 opcodes but only
2119 // single expression tree node
2121 class OpcodeCastDuplex : OpcodeCast
2123 readonly OpCode second;
2125 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2126 : base (child, returnType, first)
2128 this.second = second;
2131 public override void Emit (EmitContext ec)
2139 /// This kind of cast is used to encapsulate a child and cast it
2140 /// to the class requested
2142 public sealed class ClassCast : TypeCast {
2143 readonly bool forced;
2145 public ClassCast (Expression child, TypeSpec return_type)
2146 : base (child, return_type)
2150 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2151 : base (child, return_type)
2153 this.forced = forced;
2156 public override void Emit (EmitContext ec)
2160 bool gen = TypeManager.IsGenericParameter (child.Type);
2162 ec.Emit (OpCodes.Box, child.Type);
2164 if (type.IsGenericParameter) {
2165 ec.Emit (OpCodes.Unbox_Any, type);
2172 ec.Emit (OpCodes.Castclass, type);
2177 // Created during resolving pahse when an expression is wrapped or constantified
2178 // and original expression can be used later (e.g. for expression trees)
2180 public class ReducedExpression : Expression
2182 public sealed class ReducedConstantExpression : EmptyConstantCast
2184 readonly Expression orig_expr;
2186 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2187 : base (expr, expr.Type)
2189 this.orig_expr = orig_expr;
2192 public Expression OriginalExpression {
2198 public override Constant ConvertImplicitly (TypeSpec target_type)
2200 Constant c = base.ConvertImplicitly (target_type);
2202 c = new ReducedConstantExpression (c, orig_expr);
2207 public override Expression CreateExpressionTree (ResolveContext ec)
2209 return orig_expr.CreateExpressionTree (ec);
2212 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2214 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2216 c = new ReducedConstantExpression (c, orig_expr);
2220 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2223 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2225 if (orig_expr is Conditional)
2226 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2228 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2232 sealed class ReducedExpressionStatement : ExpressionStatement
2234 readonly Expression orig_expr;
2235 readonly ExpressionStatement stm;
2237 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2239 this.orig_expr = orig;
2241 this.eclass = stm.eclass;
2242 this.type = stm.Type;
2244 this.loc = orig.Location;
2247 public override bool ContainsEmitWithAwait ()
2249 return stm.ContainsEmitWithAwait ();
2252 public override Expression CreateExpressionTree (ResolveContext ec)
2254 return orig_expr.CreateExpressionTree (ec);
2257 protected override Expression DoResolve (ResolveContext ec)
2262 public override void Emit (EmitContext ec)
2267 public override void EmitStatement (EmitContext ec)
2269 stm.EmitStatement (ec);
2272 public override void FlowAnalysis (FlowAnalysisContext fc)
2274 stm.FlowAnalysis (fc);
2278 readonly Expression expr, orig_expr;
2280 private ReducedExpression (Expression expr, Expression orig_expr)
2283 this.eclass = expr.eclass;
2284 this.type = expr.Type;
2285 this.orig_expr = orig_expr;
2286 this.loc = orig_expr.Location;
2291 public override bool IsSideEffectFree {
2293 return expr.IsSideEffectFree;
2297 public Expression OriginalExpression {
2305 public override bool ContainsEmitWithAwait ()
2307 return expr.ContainsEmitWithAwait ();
2311 // Creates fully resolved expression switcher
2313 public static Constant Create (Constant expr, Expression original_expr)
2315 if (expr.eclass == ExprClass.Unresolved)
2316 throw new ArgumentException ("Unresolved expression");
2318 return new ReducedConstantExpression (expr, original_expr);
2321 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2323 return new ReducedExpressionStatement (s, orig);
2326 public static Expression Create (Expression expr, Expression original_expr)
2328 return Create (expr, original_expr, true);
2332 // Creates unresolved reduce expression. The original expression has to be
2333 // already resolved. Created expression is constant based based on `expr'
2334 // value unless canBeConstant is used
2336 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2338 if (canBeConstant) {
2339 Constant c = expr as Constant;
2341 return Create (c, original_expr);
2344 ExpressionStatement s = expr as ExpressionStatement;
2346 return Create (s, original_expr);
2348 if (expr.eclass == ExprClass.Unresolved)
2349 throw new ArgumentException ("Unresolved expression");
2351 return new ReducedExpression (expr, original_expr);
2354 public override Expression CreateExpressionTree (ResolveContext ec)
2356 return orig_expr.CreateExpressionTree (ec);
2359 protected override Expression DoResolve (ResolveContext ec)
2364 public override void Emit (EmitContext ec)
2369 public override Expression EmitToField (EmitContext ec)
2371 return expr.EmitToField(ec);
2374 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2376 expr.EmitBranchable (ec, target, on_true);
2379 public override void FlowAnalysis (FlowAnalysisContext fc)
2381 expr.FlowAnalysis (fc);
2384 public override SLE.Expression MakeExpression (BuilderContext ctx)
2386 return orig_expr.MakeExpression (ctx);
2391 // Standard composite pattern
2393 public abstract class CompositeExpression : Expression
2395 protected Expression expr;
2397 protected CompositeExpression (Expression expr)
2400 this.loc = expr.Location;
2403 public override bool ContainsEmitWithAwait ()
2405 return expr.ContainsEmitWithAwait ();
2408 public override Expression CreateExpressionTree (ResolveContext rc)
2410 return expr.CreateExpressionTree (rc);
2413 public Expression Child {
2414 get { return expr; }
2417 protected override Expression DoResolve (ResolveContext rc)
2419 expr = expr.Resolve (rc);
2424 eclass = expr.eclass;
2428 public override void Emit (EmitContext ec)
2433 public override bool IsNull {
2434 get { return expr.IsNull; }
2439 // Base of expressions used only to narrow resolve flow
2441 public abstract class ShimExpression : Expression
2443 protected Expression expr;
2445 protected ShimExpression (Expression expr)
2450 public Expression Expr {
2456 protected override void CloneTo (CloneContext clonectx, Expression t)
2461 ShimExpression target = (ShimExpression) t;
2462 target.expr = expr.Clone (clonectx);
2465 public override bool ContainsEmitWithAwait ()
2467 return expr.ContainsEmitWithAwait ();
2470 public override Expression CreateExpressionTree (ResolveContext ec)
2472 throw new NotSupportedException ("ET");
2475 public override void Emit (EmitContext ec)
2477 throw new InternalErrorException ("Missing Resolve call");
2481 public class UnreachableExpression : Expression
2483 public UnreachableExpression (Expression expr)
2485 this.loc = expr.Location;
2488 public override Expression CreateExpressionTree (ResolveContext ec)
2491 throw new NotImplementedException ();
2494 protected override Expression DoResolve (ResolveContext rc)
2496 throw new NotSupportedException ();
2499 public override void FlowAnalysis (FlowAnalysisContext fc)
2501 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2504 public override void Emit (EmitContext ec)
2508 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2514 // Unresolved type name expressions
2516 public abstract class ATypeNameExpression : FullNamedExpression
2519 protected TypeArguments targs;
2521 protected ATypeNameExpression (string name, Location l)
2527 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2534 protected ATypeNameExpression (string name, int arity, Location l)
2535 : this (name, new UnboundTypeArguments (arity, l), l)
2543 return targs == null ? 0 : targs.Count;
2547 public bool HasTypeArguments {
2549 return targs != null && !targs.IsEmpty;
2553 public string Name {
2562 public TypeArguments TypeArguments {
2570 public override bool Equals (object obj)
2572 ATypeNameExpression atne = obj as ATypeNameExpression;
2573 return atne != null && atne.Name == Name &&
2574 (targs == null || targs.Equals (atne.targs));
2577 public override int GetHashCode ()
2579 return Name.GetHashCode ();
2582 // TODO: Move it to MemberCore
2583 public static string GetMemberType (MemberCore mc)
2589 if (mc is FieldBase)
2591 if (mc is MethodCore)
2593 if (mc is EnumMember)
2601 public override string GetSignatureForError ()
2603 if (targs != null) {
2604 return Name + "<" + targs.GetSignatureForError () + ">";
2610 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2614 /// SimpleName expressions are formed of a single word and only happen at the beginning
2615 /// of a dotted-name.
2617 public class SimpleName : ATypeNameExpression
2619 public SimpleName (string name, Location l)
2624 public SimpleName (string name, TypeArguments args, Location l)
2625 : base (name, args, l)
2629 public SimpleName (string name, int arity, Location l)
2630 : base (name, arity, l)
2634 public SimpleName GetMethodGroup ()
2636 return new SimpleName (Name, targs, loc);
2639 protected override Expression DoResolve (ResolveContext rc)
2641 return SimpleNameResolve (rc, null);
2644 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2646 return SimpleNameResolve (ec, right_side);
2649 public void Error_NameDoesNotExist (ResolveContext rc)
2651 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2654 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2656 if (ctx.CurrentType != null) {
2657 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2658 if (member != null) {
2659 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2664 var report = ctx.Module.Compiler.Report;
2666 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2667 if (retval != null) {
2668 report.SymbolRelatedToPreviousError (retval.Type);
2669 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2673 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2674 if (retval != null) {
2675 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2679 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2680 if (ns_candidates != null) {
2681 if (ctx is UsingAliasNamespace.AliasContext) {
2682 report.Error (246, loc,
2683 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2684 ns_candidates[0], Name);
2686 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2687 report.Error (246, loc,
2688 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2692 report.Error (246, loc,
2693 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2698 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2700 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2703 if (fne.Type != null && Arity > 0) {
2704 if (HasTypeArguments) {
2705 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2706 if (ct.ResolveAsType (mc) == null)
2712 targs.Resolve (mc, allowUnboundTypeArguments);
2714 return new GenericOpenTypeExpr (fne.Type, loc);
2718 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2720 if (!(fne is NamespaceExpression))
2724 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2725 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2726 mc.Module.Compiler.Report.Error (1980, Location,
2727 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2728 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2731 fne = new DynamicTypeExpr (loc);
2732 fne.ResolveAsType (mc);
2738 Error_TypeOrNamespaceNotFound (mc);
2742 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2744 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2747 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2749 int lookup_arity = Arity;
2750 bool errorMode = false;
2752 Block current_block = rc.CurrentBlock;
2753 INamedBlockVariable variable = null;
2754 bool variable_found = false;
2758 // Stage 1: binding to local variables or parameters
2760 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2762 if (current_block != null && lookup_arity == 0) {
2763 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2764 if (!variable.IsDeclared) {
2765 // We found local name in accessible block but it's not
2766 // initialized yet, maybe the user wanted to bind to something else
2768 variable_found = true;
2770 e = variable.CreateReferenceExpression (rc, loc);
2773 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2782 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2784 TypeSpec member_type = rc.CurrentType;
2785 for (; member_type != null; member_type = member_type.DeclaringType) {
2786 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2790 var me = e as MemberExpr;
2792 // The name matches a type, defer to ResolveAsTypeStep
2800 if (variable != null) {
2801 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2802 rc.Report.Error (844, loc,
2803 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2804 Name, me.GetSignatureForError ());
2808 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2809 // Leave it to overload resolution to report correct error
2811 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2812 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2815 // LAMESPEC: again, ignores InvocableOnly
2816 if (variable != null) {
2817 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2818 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2822 // MemberLookup does not check accessors availability, this is actually needed for properties only
2824 var pe = me as PropertyExpr;
2827 // Break as there is no other overload available anyway
2828 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2829 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2832 pe.Getter = pe.PropertyInfo.Get;
2834 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2837 pe.Setter = pe.PropertyInfo.Set;
2842 // TODO: It's used by EventExpr -> FieldExpr transformation only
2843 // TODO: Should go to MemberAccess
2844 me = me.ResolveMemberAccess (rc, null, null);
2847 targs.Resolve (rc, false);
2848 me.SetTypeArguments (rc, targs);
2855 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2857 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2858 if (IsPossibleTypeOrNamespace (rc)) {
2859 if (variable != null) {
2860 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2861 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2864 return ResolveAsTypeOrNamespace (rc, false);
2868 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2871 targs.Resolve (rc, false);
2873 var me = expr as MemberExpr;
2875 me.SetTypeArguments (rc, targs);
2880 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2881 return new NameOf (this);
2884 if (variable_found) {
2885 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2888 var tparams = rc.CurrentTypeParameters;
2889 if (tparams != null) {
2890 if (tparams.Find (Name) != null) {
2891 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2896 var ct = rc.CurrentType;
2898 if (ct.MemberDefinition.TypeParametersCount > 0) {
2899 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2900 if (ctp.Name == Name) {
2901 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2907 ct = ct.DeclaringType;
2908 } while (ct != null);
2911 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2912 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2914 rc.Report.SymbolRelatedToPreviousError (e.Type);
2915 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2919 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2921 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2922 return ErrorExpression.Instance;
2926 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2928 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2929 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2933 if (e is TypeExpr) {
2934 // TypeExpression does not have correct location
2935 if (e is TypeExpression)
2936 e = new TypeExpression (e.Type, loc);
2942 Error_NameDoesNotExist (rc);
2945 return ErrorExpression.Instance;
2948 if (rc.Module.Evaluator != null) {
2949 var fi = rc.Module.Evaluator.LookupField (Name);
2951 return new FieldExpr (fi.Item1, loc);
2959 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2961 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2966 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2967 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2971 if (right_side != null) {
2972 e = e.ResolveLValue (ec, right_side);
2980 public override object Accept (StructuralVisitor visitor)
2982 return visitor.Visit (this);
2987 /// Represents a namespace or a type. The name of the class was inspired by
2988 /// section 10.8.1 (Fully Qualified Names).
2990 public abstract class FullNamedExpression : Expression
2992 protected override void CloneTo (CloneContext clonectx, Expression target)
2994 // Do nothing, most unresolved type expressions cannot be
2995 // resolved to different type
2998 public override bool ContainsEmitWithAwait ()
3003 public override Expression CreateExpressionTree (ResolveContext ec)
3005 throw new NotSupportedException ("ET");
3008 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3011 // This is used to resolve the expression as a type, a null
3012 // value will be returned if the expression is not a type
3015 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3017 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3022 TypeExpr te = fne as TypeExpr;
3024 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3032 var dep = type.GetMissingDependencies ();
3034 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3037 if (type.Kind == MemberKind.Void) {
3038 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3042 // Obsolete checks cannot be done when resolving base context as they
3043 // require type dependencies to be set but we are in process of resolving them
3045 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3046 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3047 if (obsolete_attr != null && !mc.IsObsolete) {
3048 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3056 public override void Emit (EmitContext ec)
3058 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3059 GetSignatureForError ());
3064 /// Expression that evaluates to a type
3066 public abstract class TypeExpr : FullNamedExpression
3068 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3074 protected sealed override Expression DoResolve (ResolveContext ec)
3080 public override bool Equals (object obj)
3082 TypeExpr tobj = obj as TypeExpr;
3086 return Type == tobj.Type;
3089 public override int GetHashCode ()
3091 return Type.GetHashCode ();
3096 /// Fully resolved Expression that already evaluated to a type
3098 public class TypeExpression : TypeExpr
3100 public TypeExpression (TypeSpec t, Location l)
3103 eclass = ExprClass.Type;
3107 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3113 public class NamespaceExpression : FullNamedExpression
3115 readonly Namespace ns;
3117 public NamespaceExpression (Namespace ns, Location loc)
3120 this.Type = InternalType.Namespace;
3121 this.eclass = ExprClass.Namespace;
3125 public Namespace Namespace {
3131 protected override Expression DoResolve (ResolveContext rc)
3133 throw new NotImplementedException ();
3136 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3141 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3143 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3144 if (retval != null) {
3145 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3146 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3150 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3151 if (retval != null) {
3152 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3157 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3158 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3162 string assembly = null;
3163 string possible_name = Namespace.GetSignatureForError () + "." + name;
3165 // Only assembly unique name should be added
3166 switch (possible_name) {
3167 case "System.Drawing":
3168 case "System.Web.Services":
3171 case "System.Configuration":
3172 case "System.Data.Services":
3173 case "System.DirectoryServices":
3175 case "System.Net.Http":
3176 case "System.Numerics":
3177 case "System.Runtime.Caching":
3178 case "System.ServiceModel":
3179 case "System.Transactions":
3180 case "System.Web.Routing":
3181 case "System.Xml.Linq":
3183 assembly = possible_name;
3187 case "System.Linq.Expressions":
3188 assembly = "System.Core";
3191 case "System.Windows.Forms":
3192 case "System.Windows.Forms.Layout":
3193 assembly = "System.Windows.Forms";
3197 assembly = assembly == null ? "an" : "`" + assembly + "'";
3199 if (Namespace is GlobalRootNamespace) {
3200 ctx.Module.Compiler.Report.Error (400, loc,
3201 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3204 ctx.Module.Compiler.Report.Error (234, loc,
3205 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3206 name, GetSignatureForError (), assembly);
3210 public override string GetSignatureForError ()
3212 return ns.GetSignatureForError ();
3215 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3217 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3220 public override string ToString ()
3222 return Namespace.Name;
3227 /// This class denotes an expression which evaluates to a member
3228 /// of a struct or a class.
3230 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3232 protected bool conditional_access_receiver;
3235 // An instance expression associated with this member, if it's a
3236 // non-static member
3238 public Expression InstanceExpression;
3241 /// The name of this member.
3243 public abstract string Name {
3248 // When base.member is used
3250 public bool IsBase {
3251 get { return InstanceExpression is BaseThis; }
3255 /// Whether this is an instance member.
3257 public abstract bool IsInstance {
3262 /// Whether this is a static member.
3264 public abstract bool IsStatic {
3268 public abstract string KindName {
3272 public bool ConditionalAccess { get; set; }
3274 protected abstract TypeSpec DeclaringType {
3278 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3280 return InstanceExpression.Type;
3285 // Converts best base candidate for virtual method starting from QueriedBaseType
3287 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3290 // Only when base.member is used and method is virtual
3296 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3297 // means for base.member access we have to find the closest match after we found best candidate
3299 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3301 // The method could already be what we are looking for
3303 TypeSpec[] targs = null;
3304 if (method.DeclaringType != InstanceExpression.Type) {
3306 // Candidate can have inflated MVAR parameters and we need to find
3307 // base match for original definition not inflated parameter types
3309 var parameters = method.Parameters;
3310 if (method.Arity > 0) {
3311 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3312 var inflated = method.DeclaringType as InflatedTypeSpec;
3313 if (inflated != null) {
3314 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3318 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3319 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3320 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3321 if (base_override.IsGeneric)
3322 targs = method.TypeArguments;
3324 method = base_override;
3329 // When base access is used inside anonymous method/iterator/etc we need to
3330 // get back to the context of original type. We do it by emiting proxy
3331 // method in original class and rewriting base call to this compiler
3332 // generated method call which does the actual base invocation. This may
3333 // introduce redundant storey but with `this' only but it's tricky to avoid
3334 // at this stage as we don't know what expressions follow base
3336 if (rc.CurrentAnonymousMethod != null) {
3337 if (targs == null && method.IsGeneric) {
3338 targs = method.TypeArguments;
3339 method = method.GetGenericMethodDefinition ();
3342 if (method.Parameters.HasArglist)
3343 throw new NotImplementedException ("__arglist base call proxy");
3345 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3347 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3348 // get/set member expressions second call would fail to proxy because left expression
3349 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3350 // FIXME: The async check is another hack but will probably fail with mutators
3351 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3352 InstanceExpression = new This (loc).Resolve (rc);
3356 method = method.MakeGenericMethod (rc, targs);
3360 // Only base will allow this invocation to happen.
3362 if (method.IsAbstract) {
3363 rc.Report.SymbolRelatedToPreviousError (method);
3364 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3370 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3372 if (InstanceExpression == null)
3375 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3376 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3377 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3382 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3384 if (InstanceExpression == null)
3387 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3390 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3392 var ct = rc.CurrentType;
3393 if (ct == qualifier)
3396 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3399 qualifier = qualifier.GetDefinition ();
3400 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3407 public override bool ContainsEmitWithAwait ()
3409 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3412 public override bool HasConditionalAccess ()
3414 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3417 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3420 type = type.GetDefinition ();
3422 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3425 type = type.DeclaringType;
3426 } while (type != null);
3431 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3433 if (InstanceExpression != null) {
3434 InstanceExpression = InstanceExpression.Resolve (rc);
3435 CheckProtectedMemberAccess (rc, member);
3438 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3439 UnsafeError (rc, loc);
3442 var dep = member.GetMissingDependencies ();
3444 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3447 if (!rc.IsObsolete) {
3448 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3450 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3453 if (!(member is FieldSpec))
3454 member.MemberDefinition.SetIsUsed ();
3457 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3459 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3462 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3464 rc.Report.SymbolRelatedToPreviousError (member);
3465 rc.Report.Error (1540, loc,
3466 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3467 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3470 public override void FlowAnalysis (FlowAnalysisContext fc)
3472 if (InstanceExpression != null) {
3473 InstanceExpression.FlowAnalysis (fc);
3475 if (ConditionalAccess) {
3476 fc.BranchConditionalAccessDefiniteAssignment ();
3481 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3483 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3484 if (HasConditionalAccess ()) {
3485 conditional_access_receiver = true;
3486 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3491 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3493 if (!ResolveInstanceExpressionCore (rc, rhs))
3497 // Check intermediate value modification which won't have any effect
3499 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3500 var fexpr = InstanceExpression as FieldExpr;
3501 if (fexpr != null) {
3502 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3505 if (fexpr.IsStatic) {
3506 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3507 fexpr.GetSignatureForError ());
3509 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3510 fexpr.GetSignatureForError ());
3516 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3517 if (rc.CurrentInitializerVariable != null) {
3518 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3519 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3521 rc.Report.Error (1612, loc,
3522 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3523 InstanceExpression.GetSignatureForError ());
3529 var lvr = InstanceExpression as LocalVariableReference;
3532 if (!lvr.local_info.IsReadonly)
3535 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3536 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3543 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3546 if (InstanceExpression != null) {
3547 if (InstanceExpression is TypeExpr) {
3548 var t = InstanceExpression.Type;
3550 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3551 if (oa != null && !rc.IsObsolete) {
3552 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3555 t = t.DeclaringType;
3556 } while (t != null);
3558 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3559 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3560 rc.Report.Error (176, loc,
3561 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3562 GetSignatureForError ());
3566 InstanceExpression = null;
3572 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3573 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3574 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3575 rc.Report.Error (236, loc,
3576 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3577 GetSignatureForError ());
3579 var fe = this as FieldExpr;
3580 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3581 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3582 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3584 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3588 rc.Report.Error (120, loc,
3589 "An object reference is required to access non-static member `{0}'",
3590 GetSignatureForError ());
3594 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3598 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3599 rc.Report.Error (38, loc,
3600 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3601 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3604 InstanceExpression = new This (loc).Resolve (rc);
3608 var me = InstanceExpression as MemberExpr;
3610 me.ResolveInstanceExpressionCore (rc, rhs);
3612 var fe = me as FieldExpr;
3613 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3614 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3615 rc.Report.Warning (1690, 1, loc,
3616 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3617 me.GetSignatureForError ());
3624 // Additional checks for l-value member access
3627 if (InstanceExpression is UnboxCast) {
3628 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3635 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3637 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3638 ec.Report.Warning (1720, 1, left.Location,
3639 "Expression will always cause a `{0}'", "System.NullReferenceException");
3642 InstanceExpression = left;
3646 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3648 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3649 inst.Emit (ec, ConditionalAccess);
3651 if (prepare_for_load)
3652 ec.Emit (OpCodes.Dup);
3655 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3658 public class ExtensionMethodCandidates
3660 readonly NamespaceContainer container;
3661 readonly IList<MethodSpec> methods;
3663 readonly IMemberContext context;
3665 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3667 this.context = context;
3668 this.methods = methods;
3669 this.container = nsContainer;
3670 this.index = lookupIndex;
3673 public NamespaceContainer Container {
3679 public IMemberContext Context {
3685 public int LookupIndex {
3691 public IList<MethodSpec> Methods {
3699 // Represents a group of extension method candidates for whole namespace
3701 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3703 ExtensionMethodCandidates candidates;
3704 public Expression ExtensionExpression;
3706 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3707 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3709 this.candidates = candidates;
3710 this.ExtensionExpression = extensionExpr;
3713 public override bool IsStatic {
3714 get { return true; }
3717 public override void FlowAnalysis (FlowAnalysisContext fc)
3719 if (ConditionalAccess) {
3720 fc.BranchConditionalAccessDefiniteAssignment ();
3725 // For extension methodgroup we are not looking for base members but parent
3726 // namespace extension methods
3728 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3730 // TODO: candidates are null only when doing error reporting, that's
3731 // incorrect. We have to discover same extension methods in error mode
3732 if (candidates == null)
3735 int arity = type_arguments == null ? 0 : type_arguments.Count;
3737 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3738 if (candidates == null)
3741 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3744 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3747 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3749 // LAMESPEC: or implicit type parameter conversion
3751 return argType == extensionType ||
3752 TypeSpecComparer.IsEqual (argType, extensionType) ||
3753 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3754 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3757 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3759 ExtensionExpression = ExtensionExpression.Resolve (rc);
3760 if (ExtensionExpression == null)
3763 var argType = ExtensionExpression.Type;
3764 foreach (MethodSpec candidate in Candidates) {
3765 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3769 // TODO: Scan full hierarchy
3771 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3775 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3777 // We are already here
3781 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3783 if (arguments == null)
3784 arguments = new Arguments (1);
3786 ExtensionExpression = ExtensionExpression.Resolve (ec);
3787 if (ExtensionExpression == null)
3790 var cand = candidates;
3791 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3792 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3793 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3795 // Restore candidates in case we are running in probing mode
3798 // Store resolved argument and restore original arguments
3800 // Clean-up modified arguments for error reporting
3801 arguments.RemoveAt (0);
3805 var me = ExtensionExpression as MemberExpr;
3807 me.ResolveInstanceExpression (ec, null);
3808 var fe = me as FieldExpr;
3810 fe.Spec.MemberDefinition.SetIsUsed ();
3813 InstanceExpression = null;
3817 #region IErrorHandler Members
3819 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3824 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3826 rc.Report.SymbolRelatedToPreviousError (best);
3829 rc.Report.Error (1929, loc,
3830 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3831 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3833 rc.Report.Error (1928, loc,
3834 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3835 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3841 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3846 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3855 /// MethodGroupExpr represents a group of method candidates which
3856 /// can be resolved to the best method overload
3858 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3860 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3862 protected IList<MemberSpec> Methods;
3863 MethodSpec best_candidate;
3864 TypeSpec best_candidate_return;
3865 protected TypeArguments type_arguments;
3867 SimpleName simple_name;
3868 protected TypeSpec queried_type;
3870 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3874 this.type = InternalType.MethodGroup;
3876 eclass = ExprClass.MethodGroup;
3877 queried_type = type;
3880 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3881 : this (new MemberSpec[] { m }, type, loc)
3887 public MethodSpec BestCandidate {
3889 return best_candidate;
3893 public TypeSpec BestCandidateReturnType {
3895 return best_candidate_return;
3899 public IList<MemberSpec> Candidates {
3905 protected override TypeSpec DeclaringType {
3907 return queried_type;
3911 public bool IsConditionallyExcluded {
3913 return Methods == Excluded;
3917 public override bool IsInstance {
3919 if (best_candidate != null)
3920 return !best_candidate.IsStatic;
3926 public override bool IsSideEffectFree {
3928 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3932 public override bool IsStatic {
3934 if (best_candidate != null)
3935 return best_candidate.IsStatic;
3941 public override string KindName {
3942 get { return "method"; }
3945 public override string Name {
3947 if (best_candidate != null)
3948 return best_candidate.Name;
3951 return Methods.First ().Name;
3958 // When best candidate is already know this factory can be used
3959 // to avoid expensive overload resolution to be called
3961 // NOTE: InstanceExpression has to be set manually
3963 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3965 return new MethodGroupExpr (best, queriedType, loc) {
3966 best_candidate = best,
3967 best_candidate_return = best.ReturnType
3971 public override string GetSignatureForError ()
3973 if (best_candidate != null)
3974 return best_candidate.GetSignatureForError ();
3976 return Methods.First ().GetSignatureForError ();
3979 public override Expression CreateExpressionTree (ResolveContext ec)
3981 if (best_candidate == null) {
3982 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3986 if (IsConditionallyExcluded)
3987 ec.Report.Error (765, loc,
3988 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3990 if (ConditionalAccess)
3991 Error_NullShortCircuitInsideExpressionTree (ec);
3993 return new TypeOfMethod (best_candidate, loc);
3996 protected override Expression DoResolve (ResolveContext ec)
3998 this.eclass = ExprClass.MethodGroup;
4000 if (InstanceExpression != null) {
4001 InstanceExpression = InstanceExpression.Resolve (ec);
4002 if (InstanceExpression == null)
4009 public override void Emit (EmitContext ec)
4011 throw new NotSupportedException ();
4014 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4016 var call = new CallEmitter ();
4017 call.InstanceExpression = InstanceExpression;
4018 call.ConditionalAccess = ConditionalAccess;
4021 call.EmitStatement (ec, best_candidate, arguments, loc);
4023 call.Emit (ec, best_candidate, arguments, loc);
4026 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4028 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4029 Statement = statement
4032 EmitCall (ec, arguments, statement);
4034 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4037 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4039 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4040 Name, target.GetSignatureForError ());
4043 public bool HasAccessibleCandidate (ResolveContext rc)
4045 foreach (var candidate in Candidates) {
4046 if (candidate.IsAccessible (rc))
4053 public static bool IsExtensionMethodArgument (Expression expr)
4056 // LAMESPEC: No details about which expressions are not allowed
4058 return !(expr is TypeExpr) && !(expr is BaseThis);
4062 /// Find the Applicable Function Members (7.4.2.1)
4064 /// me: Method Group expression with the members to select.
4065 /// it might contain constructors or methods (or anything
4066 /// that maps to a method).
4068 /// Arguments: ArrayList containing resolved Argument objects.
4070 /// loc: The location if we want an error to be reported, or a Null
4071 /// location for "probing" purposes.
4073 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4074 /// that is the best match of me on Arguments.
4077 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4079 // TODO: causes issues with probing mode, remove explicit Kind check
4080 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4083 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4084 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4085 r.BaseMembersProvider = this;
4086 r.InstanceQualifier = this;
4089 if (cerrors != null)
4090 r.CustomErrors = cerrors;
4092 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4093 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4094 if (best_candidate == null) {
4095 if (!r.BestCandidateIsDynamic)
4098 if (simple_name != null && ec.IsStatic)
4099 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4104 // Overload resolver had to create a new method group, all checks bellow have already been executed
4105 if (r.BestCandidateNewMethodGroup != null)
4106 return r.BestCandidateNewMethodGroup;
4108 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4109 if (InstanceExpression != null) {
4110 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4111 InstanceExpression = null;
4113 if (simple_name != null && best_candidate.IsStatic) {
4114 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4117 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4121 ResolveInstanceExpression (ec, null);
4124 var base_override = CandidateToBaseOverride (ec, best_candidate);
4125 if (base_override == best_candidate) {
4126 best_candidate_return = r.BestCandidateReturnType;
4128 best_candidate = base_override;
4129 best_candidate_return = best_candidate.ReturnType;
4132 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4133 ConstraintChecker cc = new ConstraintChecker (ec);
4134 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4138 // Additional check for possible imported base override method which
4139 // could not be done during IsOverrideMethodBaseTypeAccessible
4141 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4142 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4143 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4144 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4147 // Speed up the check by not doing it on disallowed targets
4148 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4154 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4156 var fe = left as FieldExpr;
4159 // Using method-group on struct fields makes the struct assigned. I am not sure
4160 // why but that's what .net does
4162 fe.Spec.MemberDefinition.SetIsAssigned ();
4165 simple_name = original;
4166 return base.ResolveMemberAccess (ec, left, original);
4169 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4171 type_arguments = ta;
4174 #region IBaseMembersProvider Members
4176 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4178 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4181 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4183 if (queried_type == member.DeclaringType)
4186 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4187 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4191 // Extension methods lookup after ordinary methods candidates failed to apply
4193 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4195 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4198 if (!IsExtensionMethodArgument (InstanceExpression))
4201 int arity = type_arguments == null ? 0 : type_arguments.Count;
4202 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4203 if (methods == null)
4206 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4207 emg.SetTypeArguments (rc, type_arguments);
4214 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4216 public ConstructorInstanceQualifier (TypeSpec type)
4219 InstanceType = type;
4222 public TypeSpec InstanceType { get; private set; }
4224 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4226 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4230 public struct OverloadResolver
4233 public enum Restrictions
4237 ProbingOnly = 1 << 1,
4238 CovariantDelegate = 1 << 2,
4239 NoBaseMembers = 1 << 3,
4240 BaseMembersIncluded = 1 << 4,
4241 GetEnumeratorLookup = 1 << 5
4244 public interface IBaseMembersProvider
4246 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4247 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4248 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4251 public interface IErrorHandler
4253 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4254 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4255 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4256 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4259 public interface IInstanceQualifier
4261 TypeSpec InstanceType { get; }
4262 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4265 sealed class NoBaseMembers : IBaseMembersProvider
4267 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4269 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4274 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4279 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4285 struct AmbiguousCandidate
4287 public readonly MemberSpec Member;
4288 public readonly bool Expanded;
4289 public readonly AParametersCollection Parameters;
4291 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4294 Parameters = parameters;
4295 Expanded = expanded;
4300 IList<MemberSpec> members;
4301 TypeArguments type_arguments;
4302 IBaseMembersProvider base_provider;
4303 IErrorHandler custom_errors;
4304 IInstanceQualifier instance_qualifier;
4305 Restrictions restrictions;
4306 MethodGroupExpr best_candidate_extension_group;
4307 TypeSpec best_candidate_return_type;
4309 SessionReportPrinter lambda_conv_msgs;
4311 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4312 : this (members, null, restrictions, loc)
4316 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4319 if (members == null || members.Count == 0)
4320 throw new ArgumentException ("empty members set");
4322 this.members = members;
4324 type_arguments = targs;
4325 this.restrictions = restrictions;
4326 if (IsDelegateInvoke)
4327 this.restrictions |= Restrictions.NoBaseMembers;
4329 base_provider = NoBaseMembers.Instance;
4334 public IBaseMembersProvider BaseMembersProvider {
4336 return base_provider;
4339 base_provider = value;
4343 public bool BestCandidateIsDynamic { get; set; }
4346 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4348 public MethodGroupExpr BestCandidateNewMethodGroup {
4350 return best_candidate_extension_group;
4355 // Return type can be different between best candidate and closest override
4357 public TypeSpec BestCandidateReturnType {
4359 return best_candidate_return_type;
4363 public IErrorHandler CustomErrors {
4365 return custom_errors;
4368 custom_errors = value;
4372 TypeSpec DelegateType {
4374 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4375 throw new InternalErrorException ("Not running in delegate mode", loc);
4377 return members [0].DeclaringType;
4381 public IInstanceQualifier InstanceQualifier {
4383 return instance_qualifier;
4386 instance_qualifier = value;
4390 bool IsProbingOnly {
4392 return (restrictions & Restrictions.ProbingOnly) != 0;
4396 bool IsDelegateInvoke {
4398 return (restrictions & Restrictions.DelegateInvoke) != 0;
4405 // 7.4.3.3 Better conversion from expression
4406 // Returns : 1 if a->p is better,
4407 // 2 if a->q is better,
4408 // 0 if neither is better
4410 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4412 TypeSpec argument_type = a.Type;
4415 // If argument is an anonymous function
4417 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4419 // p and q are delegate types or expression tree types
4421 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4422 if (q.MemberDefinition != p.MemberDefinition) {
4427 // Uwrap delegate from Expression<T>
4429 q = TypeManager.GetTypeArguments (q)[0];
4430 p = TypeManager.GetTypeArguments (p)[0];
4433 var p_m = Delegate.GetInvokeMethod (p);
4434 var q_m = Delegate.GetInvokeMethod (q);
4437 // With identical parameter lists
4439 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4447 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4449 if (p.Kind == MemberKind.Void) {
4450 return q.Kind != MemberKind.Void ? 2 : 0;
4454 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4456 if (q.Kind == MemberKind.Void) {
4457 return p.Kind != MemberKind.Void ? 1: 0;
4460 var am = (AnonymousMethodExpression) a.Expr;
4463 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4464 // better conversion is performed between underlying types Y1 and Y2
4466 if (p.IsGenericTask || q.IsGenericTask) {
4467 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4468 q = q.TypeArguments[0];
4469 p = p.TypeArguments[0];
4475 // An inferred return type X exists for E in the context of that parameter list, and
4476 // the conversion from X to Y1 is better than the conversion from X to Y2
4478 argument_type = am.InferReturnType (ec, null, orig_q);
4479 if (argument_type == null) {
4480 // TODO: Can this be hit?
4484 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4485 argument_type = ec.BuiltinTypes.Object;
4489 if (argument_type == p)
4492 if (argument_type == q)
4496 // The parameters are identicial and return type is not void, use better type conversion
4497 // on return type to determine better one
4499 return BetterTypeConversion (ec, p, q);
4503 // 7.4.3.4 Better conversion from type
4505 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4507 if (p == null || q == null)
4508 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4510 switch (p.BuiltinType) {
4511 case BuiltinTypeSpec.Type.Int:
4512 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4515 case BuiltinTypeSpec.Type.Long:
4516 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4519 case BuiltinTypeSpec.Type.SByte:
4520 switch (q.BuiltinType) {
4521 case BuiltinTypeSpec.Type.Byte:
4522 case BuiltinTypeSpec.Type.UShort:
4523 case BuiltinTypeSpec.Type.UInt:
4524 case BuiltinTypeSpec.Type.ULong:
4528 case BuiltinTypeSpec.Type.Short:
4529 switch (q.BuiltinType) {
4530 case BuiltinTypeSpec.Type.UShort:
4531 case BuiltinTypeSpec.Type.UInt:
4532 case BuiltinTypeSpec.Type.ULong:
4536 case BuiltinTypeSpec.Type.Dynamic:
4537 // Dynamic is never better
4541 switch (q.BuiltinType) {
4542 case BuiltinTypeSpec.Type.Int:
4543 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4546 case BuiltinTypeSpec.Type.Long:
4547 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4550 case BuiltinTypeSpec.Type.SByte:
4551 switch (p.BuiltinType) {
4552 case BuiltinTypeSpec.Type.Byte:
4553 case BuiltinTypeSpec.Type.UShort:
4554 case BuiltinTypeSpec.Type.UInt:
4555 case BuiltinTypeSpec.Type.ULong:
4559 case BuiltinTypeSpec.Type.Short:
4560 switch (p.BuiltinType) {
4561 case BuiltinTypeSpec.Type.UShort:
4562 case BuiltinTypeSpec.Type.UInt:
4563 case BuiltinTypeSpec.Type.ULong:
4567 case BuiltinTypeSpec.Type.Dynamic:
4568 // Dynamic is never better
4572 // FIXME: handle lifted operators
4574 // TODO: this is expensive
4575 Expression p_tmp = new EmptyExpression (p);
4576 Expression q_tmp = new EmptyExpression (q);
4578 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4579 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4581 if (p_to_q && !q_to_p)
4584 if (q_to_p && !p_to_q)
4591 /// Determines "Better function" between candidate
4592 /// and the current best match
4595 /// Returns a boolean indicating :
4596 /// false if candidate ain't better
4597 /// true if candidate is better than the current best match
4599 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4600 MemberSpec best, AParametersCollection bparam, bool best_params)
4602 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4603 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4605 bool better_at_least_one = false;
4606 bool are_equivalent = true;
4607 int args_count = args == null ? 0 : args.Count;
4611 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4614 // Default arguments are ignored for better decision
4615 if (a.IsDefaultArgument)
4619 // When comparing named argument the parameter type index has to be looked up
4620 // in original parameter set (override version for virtual members)
4622 NamedArgument na = a as NamedArgument;
4624 int idx = cparam.GetParameterIndexByName (na.Name);
4625 ct = candidate_pd.Types[idx];
4626 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4627 ct = TypeManager.GetElementType (ct);
4629 idx = bparam.GetParameterIndexByName (na.Name);
4630 bt = best_pd.Types[idx];
4631 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4632 bt = TypeManager.GetElementType (bt);
4634 ct = candidate_pd.Types[c_idx];
4635 bt = best_pd.Types[b_idx];
4637 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4638 ct = TypeManager.GetElementType (ct);
4642 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4643 bt = TypeManager.GetElementType (bt);
4648 if (TypeSpecComparer.IsEqual (ct, bt))
4651 are_equivalent = false;
4652 int result = BetterExpressionConversion (ec, a, ct, bt);
4654 // for each argument, the conversion to 'ct' should be no worse than
4655 // the conversion to 'bt'.
4659 // for at least one argument, the conversion to 'ct' should be better than
4660 // the conversion to 'bt'.
4662 better_at_least_one = true;
4665 if (better_at_least_one)
4669 // Tie-breaking rules are applied only for equivalent parameter types
4671 if (!are_equivalent) {
4673 // LAMESPEC: A candidate with less default parameters is still better when there
4674 // is no better expression conversion
4676 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4684 // If candidate is applicable in its normal form and best has a params array and is applicable
4685 // only in its expanded form, then candidate is better
4687 if (candidate_params != best_params)
4688 return !candidate_params;
4691 // We have not reached end of parameters list due to params or used default parameters
4693 while (j < candidate_pd.Count && j < best_pd.Count) {
4694 var cand_param = candidate_pd.FixedParameters [j];
4695 var best_param = best_pd.FixedParameters [j];
4697 if (candidate_pd.Count == best_pd.Count) {
4701 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4702 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4704 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4705 return cand_param.HasDefaultValue;
4707 if (cand_param.HasDefaultValue) {
4713 // Neither is better when not all arguments are provided
4715 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4716 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4717 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4719 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4726 if (candidate_pd.Count != best_pd.Count)
4727 return candidate_pd.Count < best_pd.Count;
4730 // One is a non-generic method and second is a generic method, then non-generic is better
4732 if (best.IsGeneric != candidate.IsGeneric)
4733 return best.IsGeneric;
4736 // Both methods have the same number of parameters, and the parameters have equal types
4737 // Pick the "more specific" signature using rules over original (non-inflated) types
4739 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4740 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4742 bool specific_at_least_once = false;
4743 for (j = 0; j < args_count; ++j) {
4744 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4746 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4747 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4749 ct = candidate_def_pd.Types[j];
4750 bt = best_def_pd.Types[j];
4755 TypeSpec specific = MoreSpecific (ct, bt);
4759 specific_at_least_once = true;
4762 if (specific_at_least_once)
4768 static bool CheckInflatedArguments (MethodSpec ms)
4770 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4773 // Setup constraint checker for probing only
4774 ConstraintChecker cc = new ConstraintChecker (null);
4776 var mp = ms.Parameters.Types;
4777 for (int i = 0; i < mp.Length; ++i) {
4778 var type = mp[i] as InflatedTypeSpec;
4782 var targs = type.TypeArguments;
4783 if (targs.Length == 0)
4786 // TODO: Checking inflated MVAR arguments should be enough
4787 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4794 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4796 rc.Report.Error (1729, loc,
4797 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4798 type.GetSignatureForError (), argCount.ToString ());
4802 // Determines if the candidate method is applicable to the given set of arguments
4803 // There could be two different set of parameters for same candidate where one
4804 // is the closest override for default values and named arguments checks and second
4805 // one being the virtual base for the parameter types and modifiers.
4807 // A return value rates candidate method compatibility,
4809 // 0 = the best, int.MaxValue = the worst
4811 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)
4814 // Each step has allocated 10 values, it can overflow for
4815 // more than 10 arguments but that's ok as it's used for
4816 // better error reporting only
4818 const int ArgumentCountMismatch = 1000000000;
4819 const int NamedArgumentsMismatch = 100000000;
4820 const int DefaultArgumentMismatch = 10000000;
4821 const int UnexpectedTypeArguments = 1000000;
4822 const int TypeArgumentsMismatch = 100000;
4823 const int InflatedTypesMismatch = 10000;
4825 // Parameters of most-derived type used mainly for named and optional parameters
4826 var pd = pm.Parameters;
4828 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4829 // params modifier instead of most-derived type
4830 var cpd = ((IParametersMember) candidate).Parameters;
4831 int param_count = pd.Count;
4832 int optional_count = 0;
4834 Arguments orig_args = arguments;
4836 if (arg_count != param_count) {
4838 // No arguments expansion when doing exact match for delegates
4840 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4841 for (int i = 0; i < pd.Count; ++i) {
4842 if (pd.FixedParameters[i].HasDefaultValue) {
4843 optional_count = pd.Count - i;
4849 if (optional_count != 0) {
4850 // Readjust expected number when params used
4851 if (cpd.HasParams) {
4853 if (arg_count < param_count)
4855 } else if (arg_count > param_count) {
4856 int args_gap = System.Math.Abs (arg_count - param_count);
4857 return ArgumentCountMismatch + args_gap;
4858 } else if (arg_count < param_count - optional_count) {
4859 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4860 return ArgumentCountMismatch + args_gap;
4862 } else if (arg_count != param_count) {
4863 int args_gap = System.Math.Abs (arg_count - param_count);
4865 return ArgumentCountMismatch + args_gap;
4866 if (arg_count < param_count - 1)
4867 return ArgumentCountMismatch + args_gap;
4870 // Resize to fit optional arguments
4871 if (optional_count != 0) {
4872 if (arguments == null) {
4873 arguments = new Arguments (optional_count);
4875 // Have to create a new container, so the next run can do same
4876 var resized = new Arguments (param_count);
4877 resized.AddRange (arguments);
4878 arguments = resized;
4881 for (int i = arg_count; i < param_count; ++i)
4882 arguments.Add (null);
4886 if (arg_count > 0) {
4888 // Shuffle named arguments to the right positions if there are any
4890 if (arguments[arg_count - 1] is NamedArgument) {
4891 arg_count = arguments.Count;
4893 for (int i = 0; i < arg_count; ++i) {
4894 bool arg_moved = false;
4896 NamedArgument na = arguments[i] as NamedArgument;
4900 int index = pd.GetParameterIndexByName (na.Name);
4902 // Named parameter not found
4904 return NamedArgumentsMismatch - i;
4906 // already reordered
4911 if (index >= param_count) {
4912 // When using parameters which should not be available to the user
4913 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4916 arguments.Add (null);
4920 if (index == arg_count)
4921 return NamedArgumentsMismatch - i - 1;
4923 temp = arguments [index];
4925 // The slot has been taken by positional argument
4926 if (temp != null && !(temp is NamedArgument))
4931 arguments = arguments.MarkOrderedArgument (na);
4935 if (arguments == orig_args) {
4936 arguments = new Arguments (orig_args.Count);
4937 arguments.AddRange (orig_args);
4940 arguments[index] = arguments[i];
4941 arguments[i] = temp;
4948 arg_count = arguments.Count;
4950 } else if (arguments != null) {
4951 arg_count = arguments.Count;
4955 // Don't do any expensive checks when the candidate cannot succeed
4957 if (arg_count != param_count && !cpd.HasParams)
4958 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4960 var dep = candidate.GetMissingDependencies ();
4962 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4967 // 1. Handle generic method using type arguments when specified or type inference
4970 var ms = candidate as MethodSpec;
4971 if (ms != null && ms.IsGeneric) {
4972 if (type_arguments != null) {
4973 var g_args_count = ms.Arity;
4974 if (g_args_count != type_arguments.Count)
4975 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4977 if (type_arguments.Arguments != null)
4978 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4981 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4982 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4983 // candidate was found use the set to report more details about what was wrong with lambda body.
4984 // The general idea is to distinguish between code errors and errors caused by
4985 // trial-and-error type inference
4987 if (lambda_conv_msgs == null) {
4988 for (int i = 0; i < arg_count; i++) {
4989 Argument a = arguments[i];
4993 var am = a.Expr as AnonymousMethodExpression;
4995 if (lambda_conv_msgs == null)
4996 lambda_conv_msgs = new SessionReportPrinter ();
4998 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5003 var ti = new TypeInference (arguments);
5004 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5007 return TypeArgumentsMismatch - ti.InferenceScore;
5010 // Clear any error messages when the result was success
5012 if (lambda_conv_msgs != null)
5013 lambda_conv_msgs.ClearSession ();
5015 if (i_args.Length != 0) {
5017 for (int i = 0; i < i_args.Length; ++i) {
5018 var ta = i_args [i];
5019 if (!ta.IsAccessible (ec))
5020 return TypeArgumentsMismatch - i;
5024 ms = ms.MakeGenericMethod (ec, i_args);
5029 // Type arguments constraints have to match for the method to be applicable
5031 if (!CheckInflatedArguments (ms)) {
5033 return InflatedTypesMismatch;
5037 // We have a generic return type and at same time the method is override which
5038 // means we have to also inflate override return type in case the candidate is
5039 // best candidate and override return type is different to base return type.
5041 // virtual Foo<T, object> with override Foo<T, dynamic>
5043 if (candidate != pm) {
5044 MethodSpec override_ms = (MethodSpec) pm;
5045 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5046 returnType = inflator.Inflate (returnType);
5048 returnType = ms.ReturnType;
5055 if (type_arguments != null)
5056 return UnexpectedTypeArguments;
5062 // 2. Each argument has to be implicitly convertible to method parameter
5064 Parameter.Modifier p_mod = 0;
5067 for (int i = 0; i < arg_count; i++) {
5068 Argument a = arguments[i];
5070 var fp = pd.FixedParameters[i];
5071 if (!fp.HasDefaultValue) {
5072 arguments = orig_args;
5073 return arg_count * 2 + 2;
5077 // Get the default value expression, we can use the same expression
5078 // if the type matches
5080 Expression e = fp.DefaultValue;
5082 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5084 // Restore for possible error reporting
5085 for (int ii = i; ii < arg_count; ++ii)
5086 arguments.RemoveAt (i);
5088 return (arg_count - i) * 2 + 1;
5092 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5094 // LAMESPEC: Attributes can be mixed together with build-in priority
5096 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5097 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5098 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5099 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5100 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5101 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5105 arguments[i] = new Argument (e, Argument.AType.Default);
5109 if (p_mod != Parameter.Modifier.PARAMS) {
5110 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5112 } else if (!params_expanded_form) {
5113 params_expanded_form = true;
5114 pt = ((ElementTypeSpec) pt).Element;
5120 if (!params_expanded_form) {
5121 if (a.IsExtensionType) {
5122 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5127 score = IsArgumentCompatible (ec, a, p_mod, pt);
5130 dynamicArgument = true;
5135 // It can be applicable in expanded form (when not doing exact match like for delegates)
5137 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5138 if (!params_expanded_form) {
5139 pt = ((ElementTypeSpec) pt).Element;
5143 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5146 params_expanded_form = true;
5147 dynamicArgument = true;
5148 } else if (score == 0 || arg_count > pd.Count) {
5149 params_expanded_form = true;
5154 if (params_expanded_form)
5156 return (arg_count - i) * 2 + score;
5161 // Restore original arguments for dynamic binder to keep the intention of original source code
5163 if (dynamicArgument)
5164 arguments = orig_args;
5169 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5171 if (e is Constant && e.Type == ptype)
5175 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5177 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5178 e = new MemberAccess (new MemberAccess (new MemberAccess (
5179 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5180 } else if (e is Constant) {
5182 // Handles int to int? conversions, DefaultParameterValue check
5184 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5188 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5191 return e.Resolve (ec);
5195 // Tests argument compatibility with the parameter
5196 // The possible return values are
5198 // 1 - modifier mismatch
5199 // 2 - type mismatch
5200 // -1 - dynamic binding required
5202 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5205 // Types have to be identical when ref or out modifer
5206 // is used and argument is not of dynamic type
5208 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5209 var arg_type = argument.Type;
5211 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5213 // Using dynamic for ref/out parameter can still succeed at runtime
5215 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5221 if (arg_type != parameter) {
5222 if (arg_type == InternalType.VarOutType)
5226 // Do full equality check after quick path
5228 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5230 // Using dynamic for ref/out parameter can still succeed at runtime
5232 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5240 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5244 // Use implicit conversion in all modes to return same candidates when the expression
5245 // is used as argument or delegate conversion
5247 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5248 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5255 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5257 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5259 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5262 var ac_p = p as ArrayContainer;
5264 var ac_q = q as ArrayContainer;
5268 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5269 if (specific == ac_p.Element)
5271 if (specific == ac_q.Element)
5273 } else if (p.IsGeneric && q.IsGeneric) {
5274 var pargs = TypeManager.GetTypeArguments (p);
5275 var qargs = TypeManager.GetTypeArguments (q);
5277 bool p_specific_at_least_once = false;
5278 bool q_specific_at_least_once = false;
5280 for (int i = 0; i < pargs.Length; i++) {
5281 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5282 if (specific == pargs[i])
5283 p_specific_at_least_once = true;
5284 if (specific == qargs[i])
5285 q_specific_at_least_once = true;
5288 if (p_specific_at_least_once && !q_specific_at_least_once)
5290 if (!p_specific_at_least_once && q_specific_at_least_once)
5298 // Find the best method from candidate list
5300 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5302 List<AmbiguousCandidate> ambiguous_candidates = null;
5304 MemberSpec best_candidate;
5305 Arguments best_candidate_args = null;
5306 bool best_candidate_params = false;
5307 bool best_candidate_dynamic = false;
5308 int best_candidate_rate;
5309 IParametersMember best_parameter_member = null;
5311 int args_count = args != null ? args.Count : 0;
5313 Arguments candidate_args = args;
5314 bool error_mode = false;
5315 MemberSpec invocable_member = null;
5318 best_candidate = null;
5319 best_candidate_rate = int.MaxValue;
5321 var type_members = members;
5323 for (int i = 0; i < type_members.Count; ++i) {
5324 var member = type_members[i];
5327 // Methods in a base class are not candidates if any method in a derived
5328 // class is applicable
5330 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5334 if (!member.IsAccessible (rc))
5337 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5340 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5341 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5346 IParametersMember pm = member as IParametersMember;
5349 // Will use it later to report ambiguity between best method and invocable member
5351 if (Invocation.IsMemberInvocable (member))
5352 invocable_member = member;
5358 // Overload resolution is looking for base member but using parameter names
5359 // and default values from the closest member. That means to do expensive lookup
5360 // for the closest override for virtual or abstract members
5362 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5363 var override_params = base_provider.GetOverrideMemberParameters (member);
5364 if (override_params != null)
5365 pm = override_params;
5369 // Check if the member candidate is applicable
5371 bool params_expanded_form = false;
5372 bool dynamic_argument = false;
5373 TypeSpec rt = pm.MemberType;
5374 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5376 if (lambda_conv_msgs != null)
5377 lambda_conv_msgs.EndSession ();
5380 // How does it score compare to others
5382 if (candidate_rate < best_candidate_rate) {
5384 // Fatal error (missing dependency), cannot continue
5385 if (candidate_rate < 0)
5388 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5389 // Only parameterless methods are considered
5391 best_candidate_rate = candidate_rate;
5392 best_candidate = member;
5393 best_candidate_args = candidate_args;
5394 best_candidate_params = params_expanded_form;
5395 best_candidate_dynamic = dynamic_argument;
5396 best_parameter_member = pm;
5397 best_candidate_return_type = rt;
5399 } else if (candidate_rate == 0) {
5401 // The member look is done per type for most operations but sometimes
5402 // it's not possible like for binary operators overload because they
5403 // are unioned between 2 sides
5405 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5406 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5411 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5413 // We pack all interface members into top level type which makes the overload resolution
5414 // more complicated for interfaces. We compensate it by removing methods with same
5415 // signature when building the cache hence this path should not really be hit often
5418 // interface IA { void Foo (int arg); }
5419 // interface IB : IA { void Foo (params int[] args); }
5421 // IB::Foo is the best overload when calling IB.Foo (1)
5424 if (ambiguous_candidates != null) {
5425 foreach (var amb_cand in ambiguous_candidates) {
5426 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5435 ambiguous_candidates = null;
5438 // Is the new candidate better
5439 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5443 best_candidate = member;
5444 best_candidate_args = candidate_args;
5445 best_candidate_params = params_expanded_form;
5446 best_candidate_dynamic = dynamic_argument;
5447 best_parameter_member = pm;
5448 best_candidate_return_type = rt;
5450 // It's not better but any other found later could be but we are not sure yet
5451 if (ambiguous_candidates == null)
5452 ambiguous_candidates = new List<AmbiguousCandidate> ();
5454 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5458 // Restore expanded arguments
5459 candidate_args = args;
5461 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5464 // We've found exact match
5466 if (best_candidate_rate == 0)
5470 // Try extension methods lookup when no ordinary method match was found and provider enables it
5473 var emg = base_provider.LookupExtensionMethod (rc);
5475 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5477 best_candidate_extension_group = emg;
5478 return (T) (MemberSpec) emg.BestCandidate;
5483 // Don't run expensive error reporting mode for probing
5490 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5493 lambda_conv_msgs = null;
5498 // No best member match found, report an error
5500 if (best_candidate_rate != 0 || error_mode) {
5501 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5505 if (best_candidate_dynamic) {
5506 if (args[0].IsExtensionType) {
5507 rc.Report.Error (1973, loc,
5508 "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",
5509 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5513 // Check type constraints only when explicit type arguments are used
5515 if (best_candidate.IsGeneric && type_arguments != null) {
5516 MethodSpec bc = best_candidate as MethodSpec;
5517 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5518 ConstraintChecker cc = new ConstraintChecker (rc);
5519 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5523 BestCandidateIsDynamic = true;
5528 // These flags indicates we are running delegate probing conversion. No need to
5529 // do more expensive checks
5531 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5532 return (T) best_candidate;
5534 if (ambiguous_candidates != null) {
5536 // Now check that there are no ambiguities i.e the selected method
5537 // should be better than all the others
5539 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5540 var candidate = ambiguous_candidates [ix];
5542 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5543 var ambiguous = candidate.Member;
5544 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5545 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5546 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5547 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5548 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5551 return (T) best_candidate;
5556 if (invocable_member != null && !IsProbingOnly) {
5557 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5558 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5559 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5560 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5564 // And now check if the arguments are all
5565 // compatible, perform conversions if
5566 // necessary etc. and return if everything is
5569 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5572 if (best_candidate == null)
5576 // Don't run possibly expensive checks in probing mode
5578 if (!IsProbingOnly && !rc.IsInProbingMode) {
5580 // Check ObsoleteAttribute on the best method
5582 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5583 if (oa != null && !rc.IsObsolete)
5584 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5586 best_candidate.MemberDefinition.SetIsUsed ();
5589 args = best_candidate_args;
5590 return (T) best_candidate;
5593 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5595 return ResolveMember<MethodSpec> (rc, ref args);
5598 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5599 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5601 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5604 if (a.Type == InternalType.ErrorType)
5607 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5608 ec.Report.SymbolRelatedToPreviousError (method);
5609 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5610 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5611 TypeManager.CSharpSignature (method));
5614 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5615 TypeManager.CSharpSignature (method));
5616 } else if (IsDelegateInvoke) {
5617 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5618 DelegateType.GetSignatureForError ());
5620 ec.Report.SymbolRelatedToPreviousError (method);
5621 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5622 method.GetSignatureForError ());
5625 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5627 string index = (idx + 1).ToString ();
5628 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5629 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5630 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5631 index, Parameter.GetModifierSignature (a.Modifier));
5633 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5634 index, Parameter.GetModifierSignature (mod));
5636 string p1 = a.GetSignatureForError ();
5637 string p2 = paramType.GetSignatureForError ();
5640 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5641 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5644 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5645 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5646 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5649 ec.Report.Error (1503, a.Expr.Location,
5650 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5655 // We have failed to find exact match so we return error info about the closest match
5657 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5659 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5660 int arg_count = args == null ? 0 : args.Count;
5662 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5663 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5664 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5668 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5673 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5674 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5675 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5679 // For candidates which match on parameters count report more details about incorrect arguments
5682 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5683 // Reject any inaccessible member
5684 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5685 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5686 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5690 var ms = best_candidate as MethodSpec;
5691 if (ms != null && ms.IsGeneric) {
5692 bool constr_ok = true;
5693 if (ms.TypeArguments != null)
5694 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5696 if (ta_count == 0 && ms.TypeArguments == null) {
5697 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5701 rc.Report.Error (411, loc,
5702 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5703 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5710 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5716 // We failed to find any method with correct argument count, report best candidate
5718 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5721 if (best_candidate.Kind == MemberKind.Constructor) {
5722 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5723 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5724 } else if (IsDelegateInvoke) {
5725 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5726 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5727 DelegateType.GetSignatureForError (), arg_count.ToString ());
5729 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5730 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5731 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5732 name, arg_count.ToString ());
5736 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5738 var p = ((IParametersMember)best_candidate).Parameters;
5743 for (int i = p.Count - 1; i != 0; --i) {
5744 var fp = p.FixedParameters [i];
5745 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5755 foreach (var arg in args) {
5756 var na = arg as NamedArgument;
5760 if (na.Name == name) {
5769 return args.Count + 1 == pm.Parameters.Count;
5772 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5774 var pd = pm.Parameters;
5775 var cpd = ((IParametersMember) member).Parameters;
5776 var ptypes = cpd.Types;
5778 Parameter.Modifier p_mod = 0;
5780 int a_idx = 0, a_pos = 0;
5782 ArrayInitializer params_initializers = null;
5783 bool has_unsafe_arg = pm.MemberType.IsPointer;
5784 int arg_count = args == null ? 0 : args.Count;
5786 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5791 if (p_mod != Parameter.Modifier.PARAMS) {
5792 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5794 has_unsafe_arg |= pt.IsPointer;
5796 if (p_mod == Parameter.Modifier.PARAMS) {
5797 if (chose_params_expanded) {
5798 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5799 pt = TypeManager.GetElementType (pt);
5805 // Types have to be identical when ref or out modifer is used
5807 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5808 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5811 var arg_type = a.Type;
5815 if (arg_type == InternalType.VarOutType) {
5817 // Set underlying variable type based on parameter type
5819 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5823 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5827 NamedArgument na = a as NamedArgument;
5829 int name_index = pd.GetParameterIndexByName (na.Name);
5830 if (name_index < 0 || name_index >= pd.Count) {
5831 if (IsDelegateInvoke) {
5832 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5833 ec.Report.Error (1746, na.Location,
5834 "The delegate `{0}' does not contain a parameter named `{1}'",
5835 DelegateType.GetSignatureForError (), na.Name);
5837 ec.Report.SymbolRelatedToPreviousError (member);
5838 ec.Report.Error (1739, na.Location,
5839 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5840 TypeManager.CSharpSignature (member), na.Name);
5842 } else if (args[name_index] != a && args[name_index] != null) {
5843 if (IsDelegateInvoke)
5844 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5846 ec.Report.SymbolRelatedToPreviousError (member);
5848 ec.Report.Error (1744, na.Location,
5849 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5854 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5857 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5858 if (a.IsExtensionType) {
5859 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5860 // CS1061 but that still better than confusing CS0123
5861 var ma = new MemberAccess (a.Expr, member.Name, loc);
5862 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5864 custom_errors.NoArgumentMatch (ec, member);
5870 if (a.IsExtensionType) {
5871 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5874 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5876 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5879 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5886 // Convert params arguments to an array initializer
5888 if (params_initializers != null) {
5889 // we choose to use 'a.Expr' rather than 'conv' so that
5890 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5891 params_initializers.Add (a.Expr);
5892 args.RemoveAt (a_idx--);
5898 // Update the argument with the implicit conversion
5902 if (a_idx != arg_count) {
5904 // Convert all var out argument to error type for less confusing error reporting
5905 // when no matching overload is found
5907 for (; a_idx < arg_count; a_idx++) {
5908 var arg = args [a_idx];
5912 if (arg.Type == InternalType.VarOutType) {
5913 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5917 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5922 // Fill not provided arguments required by params modifier
5924 if (params_initializers == null && arg_count + 1 == pd.Count) {
5926 args = new Arguments (1);
5928 pt = ptypes[pd.Count - 1];
5929 pt = TypeManager.GetElementType (pt);
5930 has_unsafe_arg |= pt.IsPointer;
5931 params_initializers = new ArrayInitializer (0, loc);
5935 // Append an array argument with all params arguments
5937 if (params_initializers != null) {
5938 args.Add (new Argument (
5939 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5943 if (has_unsafe_arg && !ec.IsUnsafe) {
5944 Expression.UnsafeError (ec, loc);
5948 // We could infer inaccesible type arguments
5950 if (type_arguments == null && member.IsGeneric) {
5951 var ms = (MethodSpec) member;
5952 foreach (var ta in ms.TypeArguments) {
5953 if (!ta.IsAccessible (ec)) {
5954 ec.Report.SymbolRelatedToPreviousError (ta);
5955 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5965 public class ConstantExpr : MemberExpr
5967 readonly ConstSpec constant;
5969 public ConstantExpr (ConstSpec constant, Location loc)
5971 this.constant = constant;
5975 public override string Name {
5976 get { throw new NotImplementedException (); }
5979 public override string KindName {
5980 get { return "constant"; }
5983 public override bool IsInstance {
5984 get { return !IsStatic; }
5987 public override bool IsStatic {
5988 get { return true; }
5991 protected override TypeSpec DeclaringType {
5992 get { return constant.DeclaringType; }
5995 public override Expression CreateExpressionTree (ResolveContext ec)
5997 throw new NotSupportedException ("ET");
6000 protected override Expression DoResolve (ResolveContext rc)
6002 ResolveInstanceExpression (rc, null);
6003 DoBestMemberChecks (rc, constant);
6005 var c = constant.GetConstant (rc);
6007 // Creates reference expression to the constant value
6008 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6011 public override void Emit (EmitContext ec)
6013 throw new NotSupportedException ();
6016 public override string GetSignatureForError ()
6018 return constant.GetSignatureForError ();
6021 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6023 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6028 // Fully resolved expression that references a Field
6030 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6032 protected FieldSpec spec;
6033 VariableInfo variable_info;
6035 LocalTemporary temp;
6038 protected FieldExpr (Location l)
6043 public FieldExpr (FieldSpec spec, Location loc)
6048 type = spec.MemberType;
6051 public FieldExpr (FieldBase fi, Location l)
6058 public override string Name {
6064 public bool IsHoisted {
6066 IVariableReference hv = InstanceExpression as IVariableReference;
6067 return hv != null && hv.IsHoisted;
6071 public override bool IsInstance {
6073 return !spec.IsStatic;
6077 public override bool IsStatic {
6079 return spec.IsStatic;
6083 public override string KindName {
6084 get { return "field"; }
6087 public FieldSpec Spec {
6093 protected override TypeSpec DeclaringType {
6095 return spec.DeclaringType;
6099 public VariableInfo VariableInfo {
6101 return variable_info;
6107 public override string GetSignatureForError ()
6109 return spec.GetSignatureForError ();
6112 public bool IsMarshalByRefAccess (ResolveContext rc)
6114 // Checks possible ldflda of field access expression
6115 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6116 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6117 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6120 public void SetHasAddressTaken ()
6122 IVariableReference vr = InstanceExpression as IVariableReference;
6124 vr.SetHasAddressTaken ();
6128 protected override void CloneTo (CloneContext clonectx, Expression target)
6130 var t = (FieldExpr) target;
6132 if (InstanceExpression != null)
6133 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6136 public override Expression CreateExpressionTree (ResolveContext ec)
6138 if (ConditionalAccess) {
6139 Error_NullShortCircuitInsideExpressionTree (ec);
6142 return CreateExpressionTree (ec, true);
6145 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6148 Expression instance;
6150 if (InstanceExpression == null) {
6151 instance = new NullLiteral (loc);
6152 } else if (convertInstance) {
6153 instance = InstanceExpression.CreateExpressionTree (ec);
6155 args = new Arguments (1);
6156 args.Add (new Argument (InstanceExpression));
6157 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6160 args = Arguments.CreateForExpressionTree (ec, null,
6162 CreateTypeOfExpression ());
6164 return CreateExpressionFactoryCall (ec, "Field", args);
6167 public Expression CreateTypeOfExpression ()
6169 return new TypeOfField (spec, loc);
6172 protected override Expression DoResolve (ResolveContext ec)
6174 spec.MemberDefinition.SetIsUsed ();
6176 return DoResolve (ec, null);
6179 Expression DoResolve (ResolveContext ec, Expression rhs)
6181 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6184 ResolveConditionalAccessReceiver (ec);
6186 if (ResolveInstanceExpression (ec, rhs)) {
6187 // Resolve the field's instance expression while flow analysis is turned
6188 // off: when accessing a field "a.b", we must check whether the field
6189 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6191 if (lvalue_instance) {
6192 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6194 Expression right_side =
6195 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6197 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6199 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6202 if (InstanceExpression == null)
6206 DoBestMemberChecks (ec, spec);
6208 if (conditional_access_receiver)
6209 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6212 var fb = spec as FixedFieldSpec;
6213 IVariableReference var = InstanceExpression as IVariableReference;
6216 IFixedExpression fe = InstanceExpression as IFixedExpression;
6217 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6218 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6221 if (InstanceExpression.eclass != ExprClass.Variable) {
6222 ec.Report.SymbolRelatedToPreviousError (spec);
6223 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6224 TypeManager.GetFullNameSignature (spec));
6225 } else if (var != null && var.IsHoisted) {
6226 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6229 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6233 // Set flow-analysis variable info for struct member access. It will be check later
6234 // for precise error reporting
6236 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6237 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6240 if (ConditionalAccess) {
6241 if (conditional_access_receiver)
6242 type = LiftMemberType (ec, type);
6244 if (InstanceExpression.IsNull)
6245 return Constant.CreateConstantFromValue (type, null, loc);
6248 eclass = ExprClass.Variable;
6252 public void SetFieldAssigned (FlowAnalysisContext fc)
6257 bool lvalue_instance = spec.DeclaringType.IsStruct;
6258 if (lvalue_instance) {
6259 var var = InstanceExpression as IVariableReference;
6260 if (var != null && var.VariableInfo != null) {
6261 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6265 var fe = InstanceExpression as FieldExpr;
6267 Expression instance;
6270 instance = fe.InstanceExpression;
6271 var fe_instance = instance as FieldExpr;
6272 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6273 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6274 var var = InstanceExpression as IVariableReference;
6275 if (var != null && var.VariableInfo == null) {
6276 var var_inst = instance as IVariableReference;
6277 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6278 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6282 if (fe_instance != null) {
6291 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6292 instance.FlowAnalysis (fc);
6294 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6295 InstanceExpression.FlowAnalysis (fc);
6299 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6301 // The return value is always null. Returning a value simplifies calling code.
6303 if (right_side == EmptyExpression.OutAccess) {
6305 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6306 GetSignatureForError ());
6308 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6309 GetSignatureForError ());
6315 if (right_side == EmptyExpression.LValueMemberAccess) {
6316 // Already reported as CS1648/CS1650
6320 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6322 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6323 GetSignatureForError ());
6325 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6326 GetSignatureForError ());
6332 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6333 GetSignatureForError ());
6335 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6336 GetSignatureForError ());
6342 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6344 if (ConditionalAccess)
6345 throw new NotSupportedException ("null propagating operator assignment");
6347 if (spec is FixedFieldSpec) {
6348 // It could be much better error message but we want to be error compatible
6349 Error_ValueAssignment (ec, right_side);
6352 Expression e = DoResolve (ec, right_side);
6357 spec.MemberDefinition.SetIsAssigned ();
6359 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6360 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6361 ec.Report.Warning (420, 1, loc,
6362 "`{0}': A volatile field references will not be treated as volatile",
6363 spec.GetSignatureForError ());
6366 if (spec.IsReadOnly) {
6367 // InitOnly fields can only be assigned in constructors or initializers
6368 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6369 return Error_AssignToReadonly (ec, right_side);
6371 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6373 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6374 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6375 return Error_AssignToReadonly (ec, right_side);
6376 // static InitOnly fields cannot be assigned-to in an instance constructor
6377 if (IsStatic && !ec.IsStatic)
6378 return Error_AssignToReadonly (ec, right_side);
6379 // instance constructors can't modify InitOnly fields of other instances of the same type
6380 if (!IsStatic && !(InstanceExpression is This))
6381 return Error_AssignToReadonly (ec, right_side);
6385 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6386 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6387 ec.Report.Warning (197, 1, loc,
6388 "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",
6389 GetSignatureForError ());
6392 eclass = ExprClass.Variable;
6396 public override void FlowAnalysis (FlowAnalysisContext fc)
6398 var var = InstanceExpression as IVariableReference;
6400 var vi = var.VariableInfo;
6401 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6402 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6406 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6410 base.FlowAnalysis (fc);
6412 if (conditional_access_receiver)
6413 fc.ConditionalAccessEnd ();
6416 public override int GetHashCode ()
6418 return spec.GetHashCode ();
6421 public bool IsFixed {
6424 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6426 IVariableReference variable = InstanceExpression as IVariableReference;
6427 if (variable != null)
6428 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6430 IFixedExpression fe = InstanceExpression as IFixedExpression;
6431 return fe != null && fe.IsFixed;
6435 public override bool Equals (object obj)
6437 FieldExpr fe = obj as FieldExpr;
6441 if (spec != fe.spec)
6444 if (InstanceExpression == null || fe.InstanceExpression == null)
6447 return InstanceExpression.Equals (fe.InstanceExpression);
6450 public void Emit (EmitContext ec, bool leave_copy)
6452 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6456 ec.Emit (OpCodes.Volatile);
6458 ec.Emit (OpCodes.Ldsfld, spec);
6461 if (conditional_access_receiver)
6462 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6464 EmitInstance (ec, false);
6467 // Optimization for build-in types
6468 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6469 ec.EmitLoadFromPtr (type);
6471 var ff = spec as FixedFieldSpec;
6473 ec.Emit (OpCodes.Ldflda, spec);
6474 ec.Emit (OpCodes.Ldflda, ff.Element);
6477 ec.Emit (OpCodes.Volatile);
6479 ec.Emit (OpCodes.Ldfld, spec);
6483 if (conditional_access_receiver) {
6484 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6489 ec.Emit (OpCodes.Dup);
6491 temp = new LocalTemporary (this.Type);
6497 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6499 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6500 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6505 if (ConditionalAccess)
6506 throw new NotImplementedException ("null operator assignment");
6508 if (has_await_source)
6509 source = source.EmitToField (ec);
6511 EmitInstance (ec, prepared);
6516 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6517 ec.Emit (OpCodes.Dup);
6519 temp = new LocalTemporary (this.Type);
6524 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6525 ec.Emit (OpCodes.Volatile);
6527 spec.MemberDefinition.SetIsAssigned ();
6530 ec.Emit (OpCodes.Stsfld, spec);
6532 ec.Emit (OpCodes.Stfld, spec);
6534 if (ec.NotifyEvaluatorOnStore) {
6536 throw new NotImplementedException ("instance field write");
6539 ec.Emit (OpCodes.Dup);
6541 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6552 // Emits store to field with prepared values on stack
6554 public void EmitAssignFromStack (EmitContext ec)
6557 ec.Emit (OpCodes.Stsfld, spec);
6559 ec.Emit (OpCodes.Stfld, spec);
6563 public override void Emit (EmitContext ec)
6568 public override void EmitSideEffect (EmitContext ec)
6570 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6572 if (is_volatile) // || is_marshal_by_ref ())
6573 base.EmitSideEffect (ec);
6576 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6578 if ((mode & AddressOp.Store) != 0)
6579 spec.MemberDefinition.SetIsAssigned ();
6580 if ((mode & AddressOp.Load) != 0)
6581 spec.MemberDefinition.SetIsUsed ();
6584 // Handle initonly fields specially: make a copy and then
6585 // get the address of the copy.
6588 if (spec.IsReadOnly){
6590 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6602 var temp = ec.GetTemporaryLocal (type);
6603 ec.Emit (OpCodes.Stloc, temp);
6604 ec.Emit (OpCodes.Ldloca, temp);
6610 ec.Emit (OpCodes.Ldsflda, spec);
6613 EmitInstance (ec, false);
6614 ec.Emit (OpCodes.Ldflda, spec);
6618 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6620 return MakeExpression (ctx);
6623 public override SLE.Expression MakeExpression (BuilderContext ctx)
6626 return base.MakeExpression (ctx);
6628 return SLE.Expression.Field (
6629 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6630 spec.GetMetaInfo ());
6634 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6636 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6642 // Expression that evaluates to a Property.
6644 // This is not an LValue because we need to re-write the expression. We
6645 // can not take data from the stack and store it.
6647 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6649 Arguments arguments;
6650 FieldExpr backing_field;
6652 public PropertyExpr (PropertySpec spec, Location l)
6655 best_candidate = spec;
6656 type = spec.MemberType;
6661 protected override Arguments Arguments {
6670 protected override TypeSpec DeclaringType {
6672 return best_candidate.DeclaringType;
6676 public override string Name {
6678 return best_candidate.Name;
6682 public bool IsAutoPropertyAccess {
6684 var prop = best_candidate.MemberDefinition as Property;
6685 return prop != null && prop.BackingField != null;
6689 public override bool IsInstance {
6695 public override bool IsStatic {
6697 return best_candidate.IsStatic;
6701 public override string KindName {
6702 get { return "property"; }
6705 public PropertySpec PropertyInfo {
6707 return best_candidate;
6713 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6715 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6718 var args_count = arguments == null ? 0 : arguments.Count;
6719 if (args_count != body.Parameters.Count && args_count == 0)
6722 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6723 mg.InstanceExpression = InstanceExpression;
6728 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6730 return new PropertyExpr (spec, loc) {
6736 public override Expression CreateExpressionTree (ResolveContext ec)
6738 if (ConditionalAccess) {
6739 Error_NullShortCircuitInsideExpressionTree (ec);
6743 if (IsSingleDimensionalArrayLength ()) {
6744 args = new Arguments (1);
6745 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6746 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6749 args = new Arguments (2);
6750 if (InstanceExpression == null)
6751 args.Add (new Argument (new NullLiteral (loc)));
6753 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6754 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6755 return CreateExpressionFactoryCall (ec, "Property", args);
6758 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6760 DoResolveLValue (rc, null);
6761 return new TypeOfMethod (Setter, loc);
6764 public override string GetSignatureForError ()
6766 return best_candidate.GetSignatureForError ();
6769 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6772 return base.MakeExpression (ctx);
6774 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6778 public override SLE.Expression MakeExpression (BuilderContext ctx)
6781 return base.MakeExpression (ctx);
6783 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6787 void Error_PropertyNotValid (ResolveContext ec)
6789 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6790 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6791 GetSignatureForError ());
6794 bool IsSingleDimensionalArrayLength ()
6796 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6799 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6800 return ac != null && ac.Rank == 1;
6803 public override void Emit (EmitContext ec, bool leave_copy)
6806 // Special case: length of single dimension array property is turned into ldlen
6808 if (IsSingleDimensionalArrayLength ()) {
6809 if (conditional_access_receiver) {
6810 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6813 EmitInstance (ec, false);
6815 ec.Emit (OpCodes.Ldlen);
6816 ec.Emit (OpCodes.Conv_I4);
6818 if (conditional_access_receiver) {
6819 ec.CloseConditionalAccess (type);
6825 base.Emit (ec, leave_copy);
6828 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6830 if (backing_field != null) {
6831 backing_field.EmitAssign (ec, source, false, false);
6836 LocalTemporary await_source_arg = null;
6838 if (isCompound && !(source is DynamicExpressionStatement)) {
6839 emitting_compound_assignment = true;
6842 if (has_await_arguments) {
6843 await_source_arg = new LocalTemporary (Type);
6844 await_source_arg.Store (ec);
6846 args = new Arguments (1);
6847 args.Add (new Argument (await_source_arg));
6850 temp = await_source_arg;
6853 has_await_arguments = false;
6858 ec.Emit (OpCodes.Dup);
6859 temp = new LocalTemporary (this.Type);
6864 args = arguments ?? new Arguments (1);
6868 temp = new LocalTemporary (this.Type);
6870 args.Add (new Argument (temp));
6872 args.Add (new Argument (source));
6876 emitting_compound_assignment = false;
6878 var call = new CallEmitter ();
6879 call.InstanceExpression = InstanceExpression;
6881 call.InstanceExpressionOnStack = true;
6883 if (ConditionalAccess) {
6884 call.ConditionalAccess = true;
6888 call.Emit (ec, Setter, args, loc);
6890 call.EmitStatement (ec, Setter, args, loc);
6897 if (await_source_arg != null) {
6898 await_source_arg.Release (ec);
6902 public override void FlowAnalysis (FlowAnalysisContext fc)
6904 var prop = best_candidate.MemberDefinition as Property;
6905 if (prop != null && prop.BackingField != null) {
6906 var var = InstanceExpression as IVariableReference;
6908 var vi = var.VariableInfo;
6909 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6910 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6914 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6919 base.FlowAnalysis (fc);
6921 if (conditional_access_receiver)
6922 fc.ConditionalAccessEnd ();
6925 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6927 eclass = ExprClass.PropertyAccess;
6929 if (best_candidate.IsNotCSharpCompatible) {
6930 Error_PropertyNotValid (rc);
6933 ResolveInstanceExpression (rc, right_side);
6935 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6936 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6937 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6939 type = p.MemberType;
6943 DoBestMemberChecks (rc, best_candidate);
6945 // Handling of com-imported properties with any number of default property parameters
6946 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6947 var p = best_candidate.Get.Parameters;
6948 arguments = new Arguments (p.Count);
6949 for (int i = 0; i < p.Count; ++i) {
6950 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6952 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6953 var p = best_candidate.Set.Parameters;
6954 arguments = new Arguments (p.Count - 1);
6955 for (int i = 0; i < p.Count - 1; ++i) {
6956 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6963 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
6965 var prop = best_candidate.MemberDefinition as Property;
6969 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
6972 var spec = prop.BackingField;
6976 if (rc.IsStatic != spec.IsStatic)
6979 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
6982 backing_field = new FieldExpr (prop.BackingField, loc);
6983 backing_field.ResolveLValue (rc, rhs);
6987 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
6989 if (backing_field != null) {
6990 backing_field.SetFieldAssigned (fc);
6994 if (!IsAutoPropertyAccess)
6997 var prop = best_candidate.MemberDefinition as Property;
6998 if (prop != null && prop.BackingField != null) {
6999 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7000 if (lvalue_instance) {
7001 var var = InstanceExpression as IVariableReference;
7002 if (var != null && var.VariableInfo != null) {
7003 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7009 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7011 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7015 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7017 // getter and setter can be different for base calls
7018 MethodSpec getter, setter;
7019 protected T best_candidate;
7021 protected LocalTemporary temp;
7022 protected bool emitting_compound_assignment;
7023 protected bool has_await_arguments;
7025 protected PropertyOrIndexerExpr (Location l)
7032 protected abstract Arguments Arguments { get; set; }
7034 public MethodSpec Getter {
7043 public MethodSpec Setter {
7054 protected override Expression DoResolve (ResolveContext ec)
7056 if (eclass == ExprClass.Unresolved) {
7057 ResolveConditionalAccessReceiver (ec);
7059 var expr = OverloadResolve (ec, null);
7064 return expr.Resolve (ec);
7066 if (conditional_access_receiver) {
7067 type = LiftMemberType (ec, type);
7068 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7072 if (!ResolveGetter (ec))
7078 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7080 if (ConditionalAccess)
7081 throw new NotSupportedException ("null propagating operator assignment");
7083 if (right_side == EmptyExpression.OutAccess) {
7084 // TODO: best_candidate can be null at this point
7085 INamedBlockVariable variable = null;
7086 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7087 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7088 best_candidate.Name);
7090 right_side.DoResolveLValue (rc, this);
7095 if (eclass == ExprClass.Unresolved) {
7096 var expr = OverloadResolve (rc, right_side);
7101 return expr.ResolveLValue (rc, right_side);
7103 ResolveInstanceExpression (rc, right_side);
7106 if (!best_candidate.HasSet) {
7107 if (ResolveAutopropertyAssignment (rc, right_side))
7110 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7111 GetSignatureForError ());
7115 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7116 if (best_candidate.HasDifferentAccessibility) {
7117 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7118 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7119 GetSignatureForError ());
7121 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7122 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7126 if (best_candidate.HasDifferentAccessibility)
7127 CheckProtectedMemberAccess (rc, best_candidate.Set);
7129 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7133 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7135 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7137 call.Emit (ec, method, arguments, loc);
7139 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7143 // Implements the IAssignMethod interface for assignments
7145 public virtual void Emit (EmitContext ec, bool leave_copy)
7147 var call = new CallEmitter ();
7148 call.ConditionalAccess = ConditionalAccess;
7149 call.InstanceExpression = InstanceExpression;
7150 if (has_await_arguments)
7151 call.HasAwaitArguments = true;
7153 call.DuplicateArguments = emitting_compound_assignment;
7155 if (conditional_access_receiver)
7156 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7158 call.Emit (ec, Getter, Arguments, loc);
7160 if (call.HasAwaitArguments) {
7161 InstanceExpression = call.InstanceExpression;
7162 Arguments = call.EmittedArguments;
7163 has_await_arguments = true;
7167 ec.Emit (OpCodes.Dup);
7168 temp = new LocalTemporary (Type);
7173 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7175 public override void Emit (EmitContext ec)
7180 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7182 has_await_arguments = true;
7187 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7189 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7191 bool ResolveGetter (ResolveContext rc)
7193 if (!best_candidate.HasGet) {
7194 if (InstanceExpression != EmptyExpression.Null) {
7195 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7196 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7197 best_candidate.GetSignatureForError ());
7200 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7201 if (best_candidate.HasDifferentAccessibility) {
7202 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7203 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7204 TypeManager.CSharpSignature (best_candidate));
7206 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7207 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7211 if (best_candidate.HasDifferentAccessibility) {
7212 CheckProtectedMemberAccess (rc, best_candidate.Get);
7215 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7219 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7226 /// Fully resolved expression that evaluates to an Event
7228 public class EventExpr : MemberExpr, IAssignMethod
7230 readonly EventSpec spec;
7233 public EventExpr (EventSpec spec, Location loc)
7241 protected override TypeSpec DeclaringType {
7243 return spec.DeclaringType;
7247 public override string Name {
7253 public override bool IsInstance {
7255 return !spec.IsStatic;
7259 public override bool IsStatic {
7261 return spec.IsStatic;
7265 public override string KindName {
7266 get { return "event"; }
7269 public MethodSpec Operator {
7277 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7280 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7282 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7283 if (spec.BackingField != null &&
7284 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7286 spec.MemberDefinition.SetIsUsed ();
7288 if (!ec.IsObsolete) {
7289 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7291 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7294 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7295 Error_AssignmentEventOnly (ec);
7297 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7299 InstanceExpression = null;
7301 return ml.ResolveMemberAccess (ec, left, original);
7305 return base.ResolveMemberAccess (ec, left, original);
7308 public override Expression CreateExpressionTree (ResolveContext ec)
7310 throw new NotSupportedException ("ET");
7313 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7315 if (right_side == EmptyExpression.EventAddition) {
7316 op = spec.AccessorAdd;
7317 } else if (right_side == EmptyExpression.EventSubtraction) {
7318 op = spec.AccessorRemove;
7322 Error_AssignmentEventOnly (ec);
7326 op = CandidateToBaseOverride (ec, op);
7330 protected override Expression DoResolve (ResolveContext ec)
7332 eclass = ExprClass.EventAccess;
7333 type = spec.MemberType;
7335 ResolveInstanceExpression (ec, null);
7337 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7338 Error_AssignmentEventOnly (ec);
7341 DoBestMemberChecks (ec, spec);
7345 public override void Emit (EmitContext ec)
7347 throw new NotSupportedException ();
7348 //Error_CannotAssign ();
7351 #region IAssignMethod Members
7353 public void Emit (EmitContext ec, bool leave_copy)
7355 throw new NotImplementedException ();
7358 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7360 if (leave_copy || !isCompound)
7361 throw new NotImplementedException ("EventExpr::EmitAssign");
7363 Arguments args = new Arguments (1);
7364 args.Add (new Argument (source));
7366 // TODO: Wrong, needs receiver
7367 // if (NullShortCircuit) {
7368 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7371 var call = new CallEmitter ();
7372 call.InstanceExpression = InstanceExpression;
7373 call.ConditionalAccess = ConditionalAccess;
7374 call.EmitStatement (ec, op, args, loc);
7376 // if (NullShortCircuit)
7377 // ec.CloseConditionalAccess (null);
7382 void Error_AssignmentEventOnly (ResolveContext ec)
7384 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7385 ec.Report.Error (79, loc,
7386 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7387 GetSignatureForError ());
7389 ec.Report.Error (70, loc,
7390 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7391 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7395 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7397 name = name.Substring (0, name.LastIndexOf ('.'));
7398 base.Error_CannotCallAbstractBase (rc, name);
7401 public override string GetSignatureForError ()
7403 return TypeManager.CSharpSignature (spec);
7406 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7408 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7412 public class TemporaryVariableReference : VariableReference
7414 public class Declarator : Statement
7416 TemporaryVariableReference variable;
7418 public Declarator (TemporaryVariableReference variable)
7420 this.variable = variable;
7424 protected override void DoEmit (EmitContext ec)
7426 variable.li.CreateBuilder (ec);
7429 public override void Emit (EmitContext ec)
7431 // Don't create sequence point
7435 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7440 protected override void CloneTo (CloneContext clonectx, Statement target)
7448 public TemporaryVariableReference (LocalVariable li, Location loc)
7451 this.type = li.Type;
7455 public override bool IsLockedByStatement {
7463 public LocalVariable LocalInfo {
7469 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7471 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7472 return new TemporaryVariableReference (li, loc);
7475 protected override Expression DoResolve (ResolveContext ec)
7477 eclass = ExprClass.Variable;
7480 // Don't capture temporary variables except when using
7481 // state machine redirection and block yields
7483 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7484 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7485 ec.IsVariableCapturingRequired) {
7486 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7487 storey.CaptureLocalVariable (ec, li);
7493 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7495 return Resolve (ec);
7498 public override void Emit (EmitContext ec)
7500 li.CreateBuilder (ec);
7505 public void EmitAssign (EmitContext ec, Expression source)
7507 li.CreateBuilder (ec);
7509 EmitAssign (ec, source, false, false);
7512 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7514 return li.HoistedVariant;
7517 public override bool IsFixed {
7518 get { return true; }
7521 public override bool IsRef {
7522 get { return false; }
7525 public override string Name {
7526 get { throw new NotImplementedException (); }
7529 public override void SetHasAddressTaken ()
7531 throw new NotImplementedException ();
7534 protected override ILocalVariable Variable {
7538 public override VariableInfo VariableInfo {
7539 get { return null; }
7544 /// Handles `var' contextual keyword; var becomes a keyword only
7545 /// if no type called var exists in a variable scope
7547 class VarExpr : SimpleName
7549 public VarExpr (Location loc)
7554 public bool InferType (ResolveContext ec, Expression right_side)
7557 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7559 type = right_side.Type;
7560 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7561 ec.Report.Error (815, loc,
7562 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7563 type.GetSignatureForError ());
7567 eclass = ExprClass.Variable;
7571 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7573 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7574 base.Error_TypeOrNamespaceNotFound (ec);
7576 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");