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 protected 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
826 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
827 // `qualifier_type' or null to lookup members in the current class.
829 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
831 var members = MemberCache.FindMembers (queried_type, name, false);
835 MemberSpec non_method = null;
836 MemberSpec ambig_non_method = null;
838 for (int i = 0; i < members.Count; ++i) {
839 var member = members[i];
841 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
842 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
845 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
848 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
852 if (!member.IsAccessible (rc))
856 // With runtime binder we can have a situation where queried type is inaccessible
857 // because it came via dynamic object, the check about inconsisted accessibility
858 // had no effect as the type was unknown during compilation
861 // private class N { }
863 // public dynamic Foo ()
869 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
873 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
874 if (member is MethodSpec) {
876 // Interface members that are hidden by class members are removed from the set. This
877 // step only has an effect if T is a type parameter and T has both an effective base
878 // class other than object and a non-empty effective interface set
880 var tps = queried_type as TypeParameterSpec;
881 if (tps != null && tps.HasTypeConstraint)
882 members = RemoveHiddenTypeParameterMethods (members);
884 return new MethodGroupExpr (members, queried_type, loc);
887 if (!Invocation.IsMemberInvocable (member))
891 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
893 } else if (!errorMode && !member.IsNotCSharpCompatible) {
895 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
896 // T has both an effective base class other than object and a non-empty effective interface set.
898 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
900 var tps = queried_type as TypeParameterSpec;
901 if (tps != null && tps.HasTypeConstraint) {
902 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
905 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
911 ambig_non_method = member;
915 if (non_method != null) {
916 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
917 var report = rc.Module.Compiler.Report;
918 report.SymbolRelatedToPreviousError (non_method);
919 report.SymbolRelatedToPreviousError (ambig_non_method);
920 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
921 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
924 if (non_method is MethodSpec)
925 return new MethodGroupExpr (members, queried_type, loc);
927 return ExprClassFromMemberInfo (non_method, loc);
930 if (members[0].DeclaringType.BaseType == null)
933 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
935 } while (members != null);
940 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
942 if (members.Count < 2)
946 // If M is a method, then all non-method members declared in an interface declaration
947 // are removed from the set, and all methods with the same signature as M declared in
948 // an interface declaration are removed from the set
952 for (int i = 0; i < members.Count; ++i) {
953 var method = members[i] as MethodSpec;
954 if (method == null) {
957 members = new List<MemberSpec> (members);
960 members.RemoveAt (i--);
964 if (!method.DeclaringType.IsInterface)
967 for (int ii = 0; ii < members.Count; ++ii) {
968 var candidate = members[ii] as MethodSpec;
969 if (candidate == null || !candidate.DeclaringType.IsClass)
972 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
977 members = new List<MemberSpec> (members);
980 members.RemoveAt (i--);
988 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
990 throw new NotImplementedException ();
993 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
995 if (t == InternalType.ErrorType)
998 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
999 oper, t.GetSignatureForError ());
1002 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1004 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1007 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1009 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1012 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1017 // Special version of flow analysis for expressions which can return different
1018 // on-true and on-false result. Used by &&, ||, ?: expressions
1020 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1023 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1027 /// Returns an expression that can be used to invoke operator true
1028 /// on the expression if it exists.
1030 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1032 return GetOperatorTrueOrFalse (ec, e, true, loc);
1036 /// Returns an expression that can be used to invoke operator false
1037 /// on the expression if it exists.
1039 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1041 return GetOperatorTrueOrFalse (ec, e, false, loc);
1044 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1046 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1048 if (type.IsNullableType)
1049 type = Nullable.NullableInfo.GetUnderlyingType (type);
1051 var methods = MemberCache.GetUserOperator (type, op, false);
1052 if (methods == null)
1055 Arguments arguments = new Arguments (1);
1056 arguments.Add (new Argument (e));
1058 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1059 var oper = res.ResolveOperator (ec, ref arguments);
1064 return new UserOperatorCall (oper, arguments, null, loc);
1067 public virtual string ExprClassName
1071 case ExprClass.Unresolved:
1072 return "Unresolved";
1073 case ExprClass.Value:
1075 case ExprClass.Variable:
1077 case ExprClass.Namespace:
1079 case ExprClass.Type:
1081 case ExprClass.MethodGroup:
1082 return "method group";
1083 case ExprClass.PropertyAccess:
1084 return "property access";
1085 case ExprClass.EventAccess:
1086 return "event access";
1087 case ExprClass.IndexerAccess:
1088 return "indexer access";
1089 case ExprClass.Nothing:
1091 case ExprClass.TypeParameter:
1092 return "type parameter";
1094 throw new Exception ("Should not happen");
1099 /// Reports that we were expecting `expr' to be of class `expected'
1101 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1103 var name = memberExpr.GetSignatureForError ();
1105 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1108 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1110 string [] valid = new string [4];
1113 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1114 valid [count++] = "variable";
1115 valid [count++] = "value";
1118 if ((flags & ResolveFlags.Type) != 0)
1119 valid [count++] = "type";
1121 if ((flags & ResolveFlags.MethodGroup) != 0)
1122 valid [count++] = "method group";
1125 valid [count++] = "unknown";
1127 StringBuilder sb = new StringBuilder (valid [0]);
1128 for (int i = 1; i < count - 1; i++) {
1130 sb.Append (valid [i]);
1133 sb.Append ("' or `");
1134 sb.Append (valid [count - 1]);
1137 ec.Report.Error (119, loc,
1138 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1141 public static void UnsafeError (ResolveContext ec, Location loc)
1143 UnsafeError (ec.Report, loc);
1146 public static void UnsafeError (Report Report, Location loc)
1148 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1152 // Converts `source' to an int, uint, long or ulong.
1154 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1156 var btypes = ec.BuiltinTypes;
1158 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1159 Arguments args = new Arguments (1);
1160 args.Add (new Argument (source));
1161 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1164 Expression converted;
1166 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1167 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1168 if (converted == null)
1169 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1170 if (converted == null)
1171 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1172 if (converted == null)
1173 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1175 if (converted == null) {
1176 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1185 // Only positive constants are allowed at compile time
1187 Constant c = converted as Constant;
1188 if (c != null && c.IsNegative)
1189 Error_NegativeArrayIndex (ec, source.loc);
1191 // No conversion needed to array index
1192 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1195 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1199 // Derived classes implement this method by cloning the fields that
1200 // could become altered during the Resolve stage
1202 // Only expressions that are created for the parser need to implement
1205 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1207 throw new NotImplementedException (
1209 "CloneTo not implemented for expression {0}", this.GetType ()));
1213 // Clones an expression created by the parser.
1215 // We only support expressions created by the parser so far, not
1216 // expressions that have been resolved (many more classes would need
1217 // to implement CloneTo).
1219 // This infrastructure is here merely for Lambda expressions which
1220 // compile the same code using different type values for the same
1221 // arguments to find the correct overload
1223 public virtual Expression Clone (CloneContext clonectx)
1225 Expression cloned = (Expression) MemberwiseClone ();
1226 CloneTo (clonectx, cloned);
1232 // Implementation of expression to expression tree conversion
1234 public abstract Expression CreateExpressionTree (ResolveContext ec);
1236 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1238 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1241 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1243 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1246 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1248 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1251 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1253 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1257 return new TypeExpression (t, loc);
1261 // Implemented by all expressions which support conversion from
1262 // compiler expression to invokable runtime expression. Used by
1263 // dynamic C# binder.
1265 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1267 throw new NotImplementedException ("MakeExpression for " + GetType ());
1270 public virtual object Accept (StructuralVisitor visitor)
1272 return visitor.Visit (this);
1277 /// This is just a base class for expressions that can
1278 /// appear on statements (invocations, object creation,
1279 /// assignments, post/pre increment and decrement). The idea
1280 /// being that they would support an extra Emition interface that
1281 /// does not leave a result on the stack.
1283 public abstract class ExpressionStatement : Expression
1285 public virtual void MarkReachable (Reachability rc)
1289 public ExpressionStatement ResolveStatement (BlockContext ec)
1291 Expression e = Resolve (ec);
1295 ExpressionStatement es = e as ExpressionStatement;
1296 if (es == null || e is AnonymousMethodBody)
1297 Error_InvalidExpressionStatement (ec);
1300 // This is quite expensive warning, try to limit the damage
1302 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1303 WarningAsyncWithoutWait (ec, e);
1309 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1311 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1312 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1317 // Need to do full resolve because GetAwaiter can be extension method
1318 // available only in this context
1320 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1324 var arguments = new Arguments (0);
1325 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1330 // Use same check rules as for real await
1332 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1333 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1336 bc.Report.Warning (4014, 1, e.Location,
1337 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1341 var inv = e as Invocation;
1342 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1343 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1344 bc.Report.Warning (4014, 1, e.Location,
1345 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1351 /// Requests the expression to be emitted in a `statement'
1352 /// context. This means that no new value is left on the
1353 /// stack after invoking this method (constrasted with
1354 /// Emit that will always leave a value on the stack).
1356 public abstract void EmitStatement (EmitContext ec);
1358 public override void EmitSideEffect (EmitContext ec)
1365 /// This kind of cast is used to encapsulate the child
1366 /// whose type is child.Type into an expression that is
1367 /// reported to return "return_type". This is used to encapsulate
1368 /// expressions which have compatible types, but need to be dealt
1369 /// at higher levels with.
1371 /// For example, a "byte" expression could be encapsulated in one
1372 /// of these as an "unsigned int". The type for the expression
1373 /// would be "unsigned int".
1376 public abstract class TypeCast : Expression
1378 protected readonly Expression child;
1380 protected TypeCast (Expression child, TypeSpec return_type)
1382 eclass = child.eclass;
1383 loc = child.Location;
1388 public Expression Child {
1394 public override bool ContainsEmitWithAwait ()
1396 return child.ContainsEmitWithAwait ();
1399 public override Expression CreateExpressionTree (ResolveContext ec)
1401 Arguments args = new Arguments (2);
1402 args.Add (new Argument (child.CreateExpressionTree (ec)));
1403 args.Add (new Argument (new TypeOf (type, loc)));
1405 if (type.IsPointer || child.Type.IsPointer)
1406 Error_PointerInsideExpressionTree (ec);
1408 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1411 protected override Expression DoResolve (ResolveContext ec)
1413 // This should never be invoked, we are born in fully
1414 // initialized state.
1419 public override void Emit (EmitContext ec)
1424 public override void FlowAnalysis (FlowAnalysisContext fc)
1426 child.FlowAnalysis (fc);
1429 public override SLE.Expression MakeExpression (BuilderContext ctx)
1432 return base.MakeExpression (ctx);
1434 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1435 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1436 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1440 protected override void CloneTo (CloneContext clonectx, Expression t)
1445 public override bool IsNull {
1446 get { return child.IsNull; }
1450 public class EmptyCast : TypeCast {
1451 EmptyCast (Expression child, TypeSpec target_type)
1452 : base (child, target_type)
1456 public static Expression Create (Expression child, TypeSpec type)
1458 Constant c = child as Constant;
1460 var enum_constant = c as EnumConstant;
1461 if (enum_constant != null)
1462 c = enum_constant.Child;
1464 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1468 var res = c.ConvertImplicitly (type);
1474 EmptyCast e = child as EmptyCast;
1476 return new EmptyCast (e.child, type);
1478 return new EmptyCast (child, type);
1481 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1483 child.EmitBranchable (ec, label, on_true);
1486 public override void EmitSideEffect (EmitContext ec)
1488 child.EmitSideEffect (ec);
1493 // Used for predefined type user operator (no obsolete check, etc.)
1495 public class OperatorCast : TypeCast
1497 readonly MethodSpec conversion_operator;
1499 public OperatorCast (Expression expr, TypeSpec target_type)
1500 : this (expr, target_type, target_type, false)
1504 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1505 : this (expr, target_type, target_type, find_explicit)
1509 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1510 : base (expr, returnType)
1512 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1513 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1516 foreach (MethodSpec oper in mi) {
1517 if (oper.ReturnType != returnType)
1520 if (oper.Parameters.Types[0] == expr.Type) {
1521 conversion_operator = oper;
1527 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1528 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1531 public override void Emit (EmitContext ec)
1534 ec.Emit (OpCodes.Call, conversion_operator);
1539 // Constant specialization of EmptyCast.
1540 // We need to special case this since an empty cast of
1541 // a constant is still a constant.
1543 public class EmptyConstantCast : Constant
1545 public readonly Constant child;
1547 public EmptyConstantCast (Constant child, TypeSpec type)
1548 : base (child.Location)
1551 throw new ArgumentNullException ("child");
1554 this.eclass = child.eclass;
1558 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1560 if (child.Type == target_type)
1563 // FIXME: check that 'type' can be converted to 'target_type' first
1564 return child.ConvertExplicitly (in_checked_context, target_type);
1567 public override Expression CreateExpressionTree (ResolveContext ec)
1569 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1570 child.CreateExpressionTree (ec),
1571 new TypeOf (type, loc));
1574 Error_PointerInsideExpressionTree (ec);
1576 return CreateExpressionFactoryCall (ec, "Convert", args);
1579 public override bool IsDefaultValue {
1580 get { return child.IsDefaultValue; }
1583 public override bool IsNegative {
1584 get { return child.IsNegative; }
1587 public override bool IsNull {
1588 get { return child.IsNull; }
1591 public override bool IsOneInteger {
1592 get { return child.IsOneInteger; }
1595 public override bool IsSideEffectFree {
1597 return child.IsSideEffectFree;
1601 public override bool IsZeroInteger {
1602 get { return child.IsZeroInteger; }
1605 public override void Emit (EmitContext ec)
1610 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1612 child.EmitBranchable (ec, label, on_true);
1614 // Only to make verifier happy
1615 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1616 ec.Emit (OpCodes.Unbox_Any, type);
1619 public override void EmitSideEffect (EmitContext ec)
1621 child.EmitSideEffect (ec);
1624 public override object GetValue ()
1626 return child.GetValue ();
1629 public override string GetValueAsLiteral ()
1631 return child.GetValueAsLiteral ();
1634 public override long GetValueAsLong ()
1636 return child.GetValueAsLong ();
1639 public override Constant ConvertImplicitly (TypeSpec target_type)
1641 if (type == target_type)
1644 // FIXME: Do we need to check user conversions?
1645 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1648 return child.ConvertImplicitly (target_type);
1653 /// This class is used to wrap literals which belong inside Enums
1655 public class EnumConstant : Constant
1657 public Constant Child;
1659 public EnumConstant (Constant child, TypeSpec enum_type)
1660 : base (child.Location)
1664 this.eclass = ExprClass.Value;
1665 this.type = enum_type;
1668 protected EnumConstant (Location loc)
1673 public override void Emit (EmitContext ec)
1678 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1680 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1683 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1685 Child.EmitBranchable (ec, label, on_true);
1688 public override void EmitSideEffect (EmitContext ec)
1690 Child.EmitSideEffect (ec);
1693 public override string GetSignatureForError()
1695 return Type.GetSignatureForError ();
1698 public override object GetValue ()
1700 return Child.GetValue ();
1704 public override object GetTypedValue ()
1707 // The method can be used in dynamic context only (on closed types)
1709 // System.Enum.ToObject cannot be called on dynamic types
1710 // EnumBuilder has to be used, but we cannot use EnumBuilder
1711 // because it does not properly support generics
1713 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1717 public override string GetValueAsLiteral ()
1719 return Child.GetValueAsLiteral ();
1722 public override long GetValueAsLong ()
1724 return Child.GetValueAsLong ();
1727 public EnumConstant Increment()
1729 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1732 public override bool IsDefaultValue {
1734 return Child.IsDefaultValue;
1738 public override bool IsSideEffectFree {
1740 return Child.IsSideEffectFree;
1744 public override bool IsZeroInteger {
1745 get { return Child.IsZeroInteger; }
1748 public override bool IsNegative {
1750 return Child.IsNegative;
1754 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1756 if (Child.Type == target_type)
1759 return Child.ConvertExplicitly (in_checked_context, target_type);
1762 public override Constant ConvertImplicitly (TypeSpec type)
1764 if (this.type == type) {
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1772 return Child.ConvertImplicitly (type);
1777 /// This kind of cast is used to encapsulate Value Types in objects.
1779 /// The effect of it is to box the value type emitted by the previous
1782 public class BoxedCast : TypeCast {
1784 public BoxedCast (Expression expr, TypeSpec target_type)
1785 : base (expr, target_type)
1787 eclass = ExprClass.Value;
1790 protected override Expression DoResolve (ResolveContext ec)
1792 // This should never be invoked, we are born in fully
1793 // initialized state.
1798 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1800 // Only boxing to object type is supported
1801 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1802 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1806 enc.Encode (child.Type);
1807 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1810 public override void Emit (EmitContext ec)
1814 ec.Emit (OpCodes.Box, child.Type);
1817 public override void EmitSideEffect (EmitContext ec)
1819 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1820 // so, we need to emit the box+pop instructions in most cases
1821 if (child.Type.IsStruct &&
1822 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1823 child.EmitSideEffect (ec);
1825 base.EmitSideEffect (ec);
1829 public class UnboxCast : TypeCast {
1830 public UnboxCast (Expression expr, TypeSpec return_type)
1831 : base (expr, return_type)
1835 protected override Expression DoResolve (ResolveContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override void Emit (EmitContext ec)
1847 ec.Emit (OpCodes.Unbox_Any, type);
1852 /// This is used to perform explicit numeric conversions.
1854 /// Explicit numeric conversions might trigger exceptions in a checked
1855 /// context, so they should generate the conv.ovf opcodes instead of
1858 public class ConvCast : TypeCast {
1859 public enum Mode : byte {
1860 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1862 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1863 U2_I1, U2_U1, U2_I2, U2_CH,
1864 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1865 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1866 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1867 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1868 CH_I1, CH_U1, CH_I2,
1869 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1870 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1876 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1877 : base (child, return_type)
1882 protected override Expression DoResolve (ResolveContext ec)
1884 // This should never be invoked, we are born in fully
1885 // initialized state.
1890 public override string ToString ()
1892 return String.Format ("ConvCast ({0}, {1})", mode, child);
1895 public override void Emit (EmitContext ec)
1901 public static void Emit (EmitContext ec, Mode mode)
1903 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1905 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1906 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1907 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1908 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1909 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1911 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1912 case Mode.U1_CH: /* nothing */ break;
1914 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1915 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1916 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1917 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1918 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1919 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1921 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1922 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1923 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1924 case Mode.U2_CH: /* nothing */ break;
1926 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1927 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1928 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1929 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1930 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1931 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1932 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1935 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1936 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1937 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1938 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1939 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1941 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1942 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1943 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1944 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1945 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1946 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1948 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1951 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1952 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1953 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1954 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1955 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1956 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1957 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1958 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1959 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1961 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1962 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1963 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1965 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1966 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1967 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1968 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1969 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1970 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1971 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1972 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1973 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1975 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1976 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1977 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1978 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1979 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1980 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1981 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1982 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1983 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1984 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1986 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1990 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1991 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1992 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1993 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1994 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1996 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1997 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1999 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2000 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2001 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2002 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2003 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2004 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2006 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2007 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2008 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2009 case Mode.U2_CH: /* nothing */ break;
2011 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2012 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2013 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2014 case Mode.I4_U4: /* nothing */ break;
2015 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2023 case Mode.U4_I4: /* nothing */ break;
2024 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2026 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2027 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2028 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2029 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2031 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2032 case Mode.I8_U8: /* nothing */ break;
2033 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2036 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2037 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2038 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2039 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2040 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2041 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2042 case Mode.U8_I8: /* nothing */ break;
2043 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2046 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2047 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2048 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2050 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2051 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2052 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2053 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2054 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2055 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2056 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2057 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2058 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2060 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2061 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2062 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2063 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2064 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2065 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2066 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2067 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2068 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2069 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2071 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2077 class OpcodeCast : TypeCast
2081 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2082 : base (child, return_type)
2087 protected override Expression DoResolve (ResolveContext ec)
2089 // This should never be invoked, we are born in fully
2090 // initialized state.
2095 public override void Emit (EmitContext ec)
2101 public TypeSpec UnderlyingType {
2102 get { return child.Type; }
2107 // Opcode casts expression with 2 opcodes but only
2108 // single expression tree node
2110 class OpcodeCastDuplex : OpcodeCast
2112 readonly OpCode second;
2114 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2115 : base (child, returnType, first)
2117 this.second = second;
2120 public override void Emit (EmitContext ec)
2128 /// This kind of cast is used to encapsulate a child and cast it
2129 /// to the class requested
2131 public sealed class ClassCast : TypeCast {
2132 readonly bool forced;
2134 public ClassCast (Expression child, TypeSpec return_type)
2135 : base (child, return_type)
2139 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2140 : base (child, return_type)
2142 this.forced = forced;
2145 public override void Emit (EmitContext ec)
2149 bool gen = TypeManager.IsGenericParameter (child.Type);
2151 ec.Emit (OpCodes.Box, child.Type);
2153 if (type.IsGenericParameter) {
2154 ec.Emit (OpCodes.Unbox_Any, type);
2161 ec.Emit (OpCodes.Castclass, type);
2166 // Created during resolving pahse when an expression is wrapped or constantified
2167 // and original expression can be used later (e.g. for expression trees)
2169 public class ReducedExpression : Expression
2171 public sealed class ReducedConstantExpression : EmptyConstantCast
2173 readonly Expression orig_expr;
2175 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2176 : base (expr, expr.Type)
2178 this.orig_expr = orig_expr;
2181 public Expression OriginalExpression {
2187 public override Constant ConvertImplicitly (TypeSpec target_type)
2189 Constant c = base.ConvertImplicitly (target_type);
2191 c = new ReducedConstantExpression (c, orig_expr);
2196 public override Expression CreateExpressionTree (ResolveContext ec)
2198 return orig_expr.CreateExpressionTree (ec);
2201 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2203 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2205 c = new ReducedConstantExpression (c, orig_expr);
2209 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2212 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2214 if (orig_expr is Conditional)
2215 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2217 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2221 sealed class ReducedExpressionStatement : ExpressionStatement
2223 readonly Expression orig_expr;
2224 readonly ExpressionStatement stm;
2226 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2228 this.orig_expr = orig;
2230 this.eclass = stm.eclass;
2231 this.type = stm.Type;
2233 this.loc = orig.Location;
2236 public override bool ContainsEmitWithAwait ()
2238 return stm.ContainsEmitWithAwait ();
2241 public override Expression CreateExpressionTree (ResolveContext ec)
2243 return orig_expr.CreateExpressionTree (ec);
2246 protected override Expression DoResolve (ResolveContext ec)
2251 public override void Emit (EmitContext ec)
2256 public override void EmitStatement (EmitContext ec)
2258 stm.EmitStatement (ec);
2261 public override void FlowAnalysis (FlowAnalysisContext fc)
2263 stm.FlowAnalysis (fc);
2267 readonly Expression expr, orig_expr;
2269 private ReducedExpression (Expression expr, Expression orig_expr)
2272 this.eclass = expr.eclass;
2273 this.type = expr.Type;
2274 this.orig_expr = orig_expr;
2275 this.loc = orig_expr.Location;
2280 public override bool IsSideEffectFree {
2282 return expr.IsSideEffectFree;
2286 public Expression OriginalExpression {
2294 public override bool ContainsEmitWithAwait ()
2296 return expr.ContainsEmitWithAwait ();
2300 // Creates fully resolved expression switcher
2302 public static Constant Create (Constant expr, Expression original_expr)
2304 if (expr.eclass == ExprClass.Unresolved)
2305 throw new ArgumentException ("Unresolved expression");
2307 return new ReducedConstantExpression (expr, original_expr);
2310 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2312 return new ReducedExpressionStatement (s, orig);
2315 public static Expression Create (Expression expr, Expression original_expr)
2317 return Create (expr, original_expr, true);
2321 // Creates unresolved reduce expression. The original expression has to be
2322 // already resolved. Created expression is constant based based on `expr'
2323 // value unless canBeConstant is used
2325 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2327 if (canBeConstant) {
2328 Constant c = expr as Constant;
2330 return Create (c, original_expr);
2333 ExpressionStatement s = expr as ExpressionStatement;
2335 return Create (s, original_expr);
2337 if (expr.eclass == ExprClass.Unresolved)
2338 throw new ArgumentException ("Unresolved expression");
2340 return new ReducedExpression (expr, original_expr);
2343 public override Expression CreateExpressionTree (ResolveContext ec)
2345 return orig_expr.CreateExpressionTree (ec);
2348 protected override Expression DoResolve (ResolveContext ec)
2353 public override void Emit (EmitContext ec)
2358 public override Expression EmitToField (EmitContext ec)
2360 return expr.EmitToField(ec);
2363 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2365 expr.EmitBranchable (ec, target, on_true);
2368 public override void FlowAnalysis (FlowAnalysisContext fc)
2370 expr.FlowAnalysis (fc);
2373 public override SLE.Expression MakeExpression (BuilderContext ctx)
2375 return orig_expr.MakeExpression (ctx);
2380 // Standard composite pattern
2382 public abstract class CompositeExpression : Expression
2384 protected Expression expr;
2386 protected CompositeExpression (Expression expr)
2389 this.loc = expr.Location;
2392 public override bool ContainsEmitWithAwait ()
2394 return expr.ContainsEmitWithAwait ();
2397 public override Expression CreateExpressionTree (ResolveContext rc)
2399 return expr.CreateExpressionTree (rc);
2402 public Expression Child {
2403 get { return expr; }
2406 protected override Expression DoResolve (ResolveContext rc)
2408 expr = expr.Resolve (rc);
2413 eclass = expr.eclass;
2417 public override void Emit (EmitContext ec)
2422 public override bool IsNull {
2423 get { return expr.IsNull; }
2428 // Base of expressions used only to narrow resolve flow
2430 public abstract class ShimExpression : Expression
2432 protected Expression expr;
2434 protected ShimExpression (Expression expr)
2439 public Expression Expr {
2445 protected override void CloneTo (CloneContext clonectx, Expression t)
2450 ShimExpression target = (ShimExpression) t;
2451 target.expr = expr.Clone (clonectx);
2454 public override bool ContainsEmitWithAwait ()
2456 return expr.ContainsEmitWithAwait ();
2459 public override Expression CreateExpressionTree (ResolveContext ec)
2461 throw new NotSupportedException ("ET");
2464 public override void Emit (EmitContext ec)
2466 throw new InternalErrorException ("Missing Resolve call");
2470 public class UnreachableExpression : Expression
2472 public UnreachableExpression (Expression expr)
2474 this.loc = expr.Location;
2477 public override Expression CreateExpressionTree (ResolveContext ec)
2480 throw new NotImplementedException ();
2483 protected override Expression DoResolve (ResolveContext rc)
2485 throw new NotSupportedException ();
2488 public override void FlowAnalysis (FlowAnalysisContext fc)
2490 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2493 public override void Emit (EmitContext ec)
2497 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2503 // Unresolved type name expressions
2505 public abstract class ATypeNameExpression : FullNamedExpression
2508 protected TypeArguments targs;
2510 protected ATypeNameExpression (string name, Location l)
2516 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2523 protected ATypeNameExpression (string name, int arity, Location l)
2524 : this (name, new UnboundTypeArguments (arity), l)
2530 protected int Arity {
2532 return targs == null ? 0 : targs.Count;
2536 public bool HasTypeArguments {
2538 return targs != null && !targs.IsEmpty;
2542 public string Name {
2551 public TypeArguments TypeArguments {
2559 public override bool Equals (object obj)
2561 ATypeNameExpression atne = obj as ATypeNameExpression;
2562 return atne != null && atne.Name == Name &&
2563 (targs == null || targs.Equals (atne.targs));
2566 protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
2568 mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
2571 public override int GetHashCode ()
2573 return Name.GetHashCode ();
2576 // TODO: Move it to MemberCore
2577 public static string GetMemberType (MemberCore mc)
2583 if (mc is FieldBase)
2585 if (mc is MethodCore)
2587 if (mc is EnumMember)
2595 public override string GetSignatureForError ()
2597 if (targs != null) {
2598 return Name + "<" + targs.GetSignatureForError () + ">";
2604 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2608 /// SimpleName expressions are formed of a single word and only happen at the beginning
2609 /// of a dotted-name.
2611 public class SimpleName : ATypeNameExpression
2613 public SimpleName (string name, Location l)
2618 public SimpleName (string name, TypeArguments args, Location l)
2619 : base (name, args, l)
2623 public SimpleName (string name, int arity, Location l)
2624 : base (name, arity, l)
2628 public SimpleName GetMethodGroup ()
2630 return new SimpleName (Name, targs, loc);
2633 protected override Expression DoResolve (ResolveContext rc)
2635 return SimpleNameResolve (rc, null);
2638 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2640 return SimpleNameResolve (ec, right_side);
2643 public void Error_NameDoesNotExist (ResolveContext rc)
2645 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2648 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2650 if (ctx.CurrentType != null) {
2651 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2652 if (member != null) {
2653 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2658 var report = ctx.Module.Compiler.Report;
2660 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2661 if (retval != null) {
2662 report.SymbolRelatedToPreviousError (retval.Type);
2663 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2667 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2668 if (retval != null) {
2669 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2673 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2674 if (ns_candidates != null) {
2675 if (ctx is UsingAliasNamespace.AliasContext) {
2676 report.Error (246, loc,
2677 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2678 ns_candidates[0], Name);
2680 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2681 report.Error (246, loc,
2682 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2686 report.Error (246, loc,
2687 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2692 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2694 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2697 if (fne.Type != null && Arity > 0) {
2698 if (HasTypeArguments) {
2699 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2700 if (ct.ResolveAsType (mc) == null)
2706 if (!allowUnboundTypeArguments)
2707 Error_OpenGenericTypeIsNotAllowed (mc);
2709 return new GenericOpenTypeExpr (fne.Type, loc);
2713 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2715 if (!(fne is NamespaceExpression))
2719 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2720 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2721 mc.Module.Compiler.Report.Error (1980, Location,
2722 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2723 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2726 fne = new DynamicTypeExpr (loc);
2727 fne.ResolveAsType (mc);
2733 Error_TypeOrNamespaceNotFound (mc);
2737 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2739 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2742 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2744 int lookup_arity = Arity;
2745 bool errorMode = false;
2747 Block current_block = rc.CurrentBlock;
2748 INamedBlockVariable variable = null;
2749 bool variable_found = false;
2753 // Stage 1: binding to local variables or parameters
2755 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2757 if (current_block != null && lookup_arity == 0) {
2758 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2759 if (!variable.IsDeclared) {
2760 // We found local name in accessible block but it's not
2761 // initialized yet, maybe the user wanted to bind to something else
2763 variable_found = true;
2765 e = variable.CreateReferenceExpression (rc, loc);
2768 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2777 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2779 TypeSpec member_type = rc.CurrentType;
2780 for (; member_type != null; member_type = member_type.DeclaringType) {
2781 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2785 var me = e as MemberExpr;
2787 // The name matches a type, defer to ResolveAsTypeStep
2795 if (variable != null) {
2796 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2797 rc.Report.Error (844, loc,
2798 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2799 Name, me.GetSignatureForError ());
2803 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2804 // Leave it to overload resolution to report correct error
2806 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2807 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2810 // LAMESPEC: again, ignores InvocableOnly
2811 if (variable != null) {
2812 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2813 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2817 // MemberLookup does not check accessors availability, this is actually needed for properties only
2819 var pe = me as PropertyExpr;
2822 // Break as there is no other overload available anyway
2823 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2824 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2827 pe.Getter = pe.PropertyInfo.Get;
2829 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2832 pe.Setter = pe.PropertyInfo.Set;
2837 // TODO: It's used by EventExpr -> FieldExpr transformation only
2838 // TODO: Should go to MemberAccess
2839 me = me.ResolveMemberAccess (rc, null, null);
2843 me.SetTypeArguments (rc, targs);
2850 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2852 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2853 if (IsPossibleTypeOrNamespace (rc)) {
2854 if (variable != null) {
2855 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2856 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2859 return ResolveAsTypeOrNamespace (rc, false);
2863 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2867 mg.SetTypeArguments (rc, targs);
2872 if (Name == "nameof")
2873 return new NameOf (this);
2876 if (variable_found) {
2877 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2880 var tparams = rc.CurrentTypeParameters;
2881 if (tparams != null) {
2882 if (tparams.Find (Name) != null) {
2883 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2888 var ct = rc.CurrentType;
2890 if (ct.MemberDefinition.TypeParametersCount > 0) {
2891 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2892 if (ctp.Name == Name) {
2893 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2899 ct = ct.DeclaringType;
2900 } while (ct != null);
2903 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2904 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2906 rc.Report.SymbolRelatedToPreviousError (e.Type);
2907 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2911 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2913 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2914 return ErrorExpression.Instance;
2918 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2920 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2921 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2925 if (e is TypeExpr) {
2926 // TypeExpression does not have correct location
2927 if (e is TypeExpression)
2928 e = new TypeExpression (e.Type, loc);
2934 Error_NameDoesNotExist (rc);
2937 return ErrorExpression.Instance;
2940 if (rc.Module.Evaluator != null) {
2941 var fi = rc.Module.Evaluator.LookupField (Name);
2943 return new FieldExpr (fi.Item1, loc);
2951 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2953 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2958 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2959 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2963 if (right_side != null) {
2964 e = e.ResolveLValue (ec, right_side);
2972 public override object Accept (StructuralVisitor visitor)
2974 return visitor.Visit (this);
2979 /// Represents a namespace or a type. The name of the class was inspired by
2980 /// section 10.8.1 (Fully Qualified Names).
2982 public abstract class FullNamedExpression : Expression
2984 protected override void CloneTo (CloneContext clonectx, Expression target)
2986 // Do nothing, most unresolved type expressions cannot be
2987 // resolved to different type
2990 public override bool ContainsEmitWithAwait ()
2995 public override Expression CreateExpressionTree (ResolveContext ec)
2997 throw new NotSupportedException ("ET");
3000 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3003 // This is used to resolve the expression as a type, a null
3004 // value will be returned if the expression is not a type
3007 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3009 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3014 TypeExpr te = fne as TypeExpr;
3016 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3024 var dep = type.GetMissingDependencies ();
3026 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3029 if (type.Kind == MemberKind.Void) {
3030 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3034 // Obsolete checks cannot be done when resolving base context as they
3035 // require type dependencies to be set but we are in process of resolving them
3037 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3038 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3039 if (obsolete_attr != null && !mc.IsObsolete) {
3040 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3048 public override void Emit (EmitContext ec)
3050 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3051 GetSignatureForError ());
3056 /// Expression that evaluates to a type
3058 public abstract class TypeExpr : FullNamedExpression
3060 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3066 protected sealed override Expression DoResolve (ResolveContext ec)
3072 public override bool Equals (object obj)
3074 TypeExpr tobj = obj as TypeExpr;
3078 return Type == tobj.Type;
3081 public override int GetHashCode ()
3083 return Type.GetHashCode ();
3088 /// Fully resolved Expression that already evaluated to a type
3090 public class TypeExpression : TypeExpr
3092 public TypeExpression (TypeSpec t, Location l)
3095 eclass = ExprClass.Type;
3099 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3105 public class NamespaceExpression : FullNamedExpression
3107 readonly Namespace ns;
3109 public NamespaceExpression (Namespace ns, Location loc)
3112 this.Type = InternalType.Namespace;
3113 this.eclass = ExprClass.Namespace;
3117 public Namespace Namespace {
3123 protected override Expression DoResolve (ResolveContext rc)
3125 throw new NotImplementedException ();
3128 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3133 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3135 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3136 if (retval != null) {
3137 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3138 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3142 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3143 if (retval != null) {
3144 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3149 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3150 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3154 string assembly = null;
3155 string possible_name = Namespace.GetSignatureForError () + "." + name;
3157 // Only assembly unique name should be added
3158 switch (possible_name) {
3159 case "System.Drawing":
3160 case "System.Web.Services":
3163 case "System.Configuration":
3164 case "System.Data.Services":
3165 case "System.DirectoryServices":
3167 case "System.Net.Http":
3168 case "System.Numerics":
3169 case "System.Runtime.Caching":
3170 case "System.ServiceModel":
3171 case "System.Transactions":
3172 case "System.Web.Routing":
3173 case "System.Xml.Linq":
3175 assembly = possible_name;
3179 case "System.Linq.Expressions":
3180 assembly = "System.Core";
3183 case "System.Windows.Forms":
3184 case "System.Windows.Forms.Layout":
3185 assembly = "System.Windows.Forms";
3189 assembly = assembly == null ? "an" : "`" + assembly + "'";
3191 if (Namespace is GlobalRootNamespace) {
3192 ctx.Module.Compiler.Report.Error (400, loc,
3193 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3196 ctx.Module.Compiler.Report.Error (234, loc,
3197 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3198 name, GetSignatureForError (), assembly);
3202 public override string GetSignatureForError ()
3204 return ns.GetSignatureForError ();
3207 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3209 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3214 /// This class denotes an expression which evaluates to a member
3215 /// of a struct or a class.
3217 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3219 protected bool conditional_access_receiver;
3222 // An instance expression associated with this member, if it's a
3223 // non-static member
3225 public Expression InstanceExpression;
3228 /// The name of this member.
3230 public abstract string Name {
3235 // When base.member is used
3237 public bool IsBase {
3238 get { return InstanceExpression is BaseThis; }
3242 /// Whether this is an instance member.
3244 public abstract bool IsInstance {
3249 /// Whether this is a static member.
3251 public abstract bool IsStatic {
3255 public abstract string KindName {
3259 public bool ConditionalAccess { get; set; }
3261 protected abstract TypeSpec DeclaringType {
3265 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3267 return InstanceExpression.Type;
3272 // Converts best base candidate for virtual method starting from QueriedBaseType
3274 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3277 // Only when base.member is used and method is virtual
3283 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3284 // means for base.member access we have to find the closest match after we found best candidate
3286 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3288 // The method could already be what we are looking for
3290 TypeSpec[] targs = null;
3291 if (method.DeclaringType != InstanceExpression.Type) {
3293 // Candidate can have inflated MVAR parameters and we need to find
3294 // base match for original definition not inflated parameter types
3296 var parameters = method.Parameters;
3297 if (method.Arity > 0) {
3298 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3299 var inflated = method.DeclaringType as InflatedTypeSpec;
3300 if (inflated != null) {
3301 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3305 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3306 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3307 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3308 if (base_override.IsGeneric)
3309 targs = method.TypeArguments;
3311 method = base_override;
3316 // When base access is used inside anonymous method/iterator/etc we need to
3317 // get back to the context of original type. We do it by emiting proxy
3318 // method in original class and rewriting base call to this compiler
3319 // generated method call which does the actual base invocation. This may
3320 // introduce redundant storey but with `this' only but it's tricky to avoid
3321 // at this stage as we don't know what expressions follow base
3323 if (rc.CurrentAnonymousMethod != null) {
3324 if (targs == null && method.IsGeneric) {
3325 targs = method.TypeArguments;
3326 method = method.GetGenericMethodDefinition ();
3329 if (method.Parameters.HasArglist)
3330 throw new NotImplementedException ("__arglist base call proxy");
3332 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3334 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3335 // get/set member expressions second call would fail to proxy because left expression
3336 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3337 // FIXME: The async check is another hack but will probably fail with mutators
3338 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3339 InstanceExpression = new This (loc).Resolve (rc);
3343 method = method.MakeGenericMethod (rc, targs);
3347 // Only base will allow this invocation to happen.
3349 if (method.IsAbstract) {
3350 rc.Report.SymbolRelatedToPreviousError (method);
3351 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3357 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3359 if (InstanceExpression == null)
3362 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3363 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3364 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3369 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3371 if (InstanceExpression == null)
3374 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3377 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3379 var ct = rc.CurrentType;
3380 if (ct == qualifier)
3383 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3386 qualifier = qualifier.GetDefinition ();
3387 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3394 public override bool ContainsEmitWithAwait ()
3396 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3399 public override bool HasConditionalAccess ()
3401 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3404 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3407 type = type.GetDefinition ();
3409 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3412 type = type.DeclaringType;
3413 } while (type != null);
3418 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3420 if (InstanceExpression != null) {
3421 InstanceExpression = InstanceExpression.Resolve (rc);
3422 CheckProtectedMemberAccess (rc, member);
3425 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3426 UnsafeError (rc, loc);
3429 var dep = member.GetMissingDependencies ();
3431 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3434 if (!rc.IsObsolete) {
3435 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3437 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3440 if (!(member is FieldSpec))
3441 member.MemberDefinition.SetIsUsed ();
3444 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3446 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3449 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3451 rc.Report.SymbolRelatedToPreviousError (member);
3452 rc.Report.Error (1540, loc,
3453 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3454 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3457 public override void FlowAnalysis (FlowAnalysisContext fc)
3459 if (InstanceExpression != null) {
3460 InstanceExpression.FlowAnalysis (fc);
3462 if (ConditionalAccess) {
3463 fc.BranchConditionalAccessDefiniteAssignment ();
3468 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3470 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3471 if (HasConditionalAccess ()) {
3472 conditional_access_receiver = true;
3473 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3478 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3480 if (!ResolveInstanceExpressionCore (rc, rhs))
3484 // Check intermediate value modification which won't have any effect
3486 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3487 var fexpr = InstanceExpression as FieldExpr;
3488 if (fexpr != null) {
3489 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3492 if (fexpr.IsStatic) {
3493 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3494 fexpr.GetSignatureForError ());
3496 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3497 fexpr.GetSignatureForError ());
3503 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3504 if (rc.CurrentInitializerVariable != null) {
3505 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3506 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3508 rc.Report.Error (1612, loc,
3509 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3510 InstanceExpression.GetSignatureForError ());
3516 var lvr = InstanceExpression as LocalVariableReference;
3519 if (!lvr.local_info.IsReadonly)
3522 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3523 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3530 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3533 if (InstanceExpression != null) {
3534 if (InstanceExpression is TypeExpr) {
3535 var t = InstanceExpression.Type;
3537 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3538 if (oa != null && !rc.IsObsolete) {
3539 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3542 t = t.DeclaringType;
3543 } while (t != null);
3545 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3546 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3547 rc.Report.Error (176, loc,
3548 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3549 GetSignatureForError ());
3553 InstanceExpression = null;
3559 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3560 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3561 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3562 rc.Report.Error (236, loc,
3563 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3564 GetSignatureForError ());
3566 var fe = this as FieldExpr;
3567 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3568 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3569 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3571 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3575 rc.Report.Error (120, loc,
3576 "An object reference is required to access non-static member `{0}'",
3577 GetSignatureForError ());
3581 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3585 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3586 rc.Report.Error (38, loc,
3587 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3588 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3591 InstanceExpression = new This (loc).Resolve (rc);
3595 var me = InstanceExpression as MemberExpr;
3597 me.ResolveInstanceExpressionCore (rc, rhs);
3599 var fe = me as FieldExpr;
3600 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3601 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3602 rc.Report.Warning (1690, 1, loc,
3603 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3604 me.GetSignatureForError ());
3611 // Additional checks for l-value member access
3614 if (InstanceExpression is UnboxCast) {
3615 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3622 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3624 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3625 ec.Report.Warning (1720, 1, left.Location,
3626 "Expression will always cause a `{0}'", "System.NullReferenceException");
3629 InstanceExpression = left;
3633 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3635 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3636 inst.Emit (ec, ConditionalAccess);
3638 if (prepare_for_load)
3639 ec.Emit (OpCodes.Dup);
3642 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3645 public class ExtensionMethodCandidates
3647 readonly NamespaceContainer container;
3648 readonly IList<MethodSpec> methods;
3650 readonly IMemberContext context;
3652 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3654 this.context = context;
3655 this.methods = methods;
3656 this.container = nsContainer;
3657 this.index = lookupIndex;
3660 public NamespaceContainer Container {
3666 public IMemberContext Context {
3672 public int LookupIndex {
3678 public IList<MethodSpec> Methods {
3686 // Represents a group of extension method candidates for whole namespace
3688 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3690 ExtensionMethodCandidates candidates;
3691 public Expression ExtensionExpression;
3693 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3694 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3696 this.candidates = candidates;
3697 this.ExtensionExpression = extensionExpr;
3700 public override bool IsStatic {
3701 get { return true; }
3704 public override void FlowAnalysis (FlowAnalysisContext fc)
3706 if (ConditionalAccess) {
3707 fc.BranchConditionalAccessDefiniteAssignment ();
3712 // For extension methodgroup we are not looking for base members but parent
3713 // namespace extension methods
3715 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3717 // TODO: candidates are null only when doing error reporting, that's
3718 // incorrect. We have to discover same extension methods in error mode
3719 if (candidates == null)
3722 int arity = type_arguments == null ? 0 : type_arguments.Count;
3724 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3725 if (candidates == null)
3728 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3731 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3733 // We are already here
3737 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3739 if (arguments == null)
3740 arguments = new Arguments (1);
3742 ExtensionExpression = ExtensionExpression.Resolve (ec);
3743 if (ExtensionExpression == null)
3746 var cand = candidates;
3747 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3748 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3749 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3751 // Restore candidates in case we are running in probing mode
3754 // Store resolved argument and restore original arguments
3756 // Clean-up modified arguments for error reporting
3757 arguments.RemoveAt (0);
3761 var me = ExtensionExpression as MemberExpr;
3763 me.ResolveInstanceExpression (ec, null);
3764 var fe = me as FieldExpr;
3766 fe.Spec.MemberDefinition.SetIsUsed ();
3769 InstanceExpression = null;
3773 #region IErrorHandler Members
3775 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3780 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3782 rc.Report.SymbolRelatedToPreviousError (best);
3783 rc.Report.Error (1928, loc,
3784 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3785 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3788 rc.Report.Error (1929, loc,
3789 "Extension method instance type `{0}' cannot be converted to `{1}'",
3790 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3796 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3801 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3810 /// MethodGroupExpr represents a group of method candidates which
3811 /// can be resolved to the best method overload
3813 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3815 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3817 protected IList<MemberSpec> Methods;
3818 MethodSpec best_candidate;
3819 TypeSpec best_candidate_return;
3820 protected TypeArguments type_arguments;
3822 SimpleName simple_name;
3823 protected TypeSpec queried_type;
3825 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3829 this.type = InternalType.MethodGroup;
3831 eclass = ExprClass.MethodGroup;
3832 queried_type = type;
3835 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3836 : this (new MemberSpec[] { m }, type, loc)
3842 public MethodSpec BestCandidate {
3844 return best_candidate;
3848 public TypeSpec BestCandidateReturnType {
3850 return best_candidate_return;
3854 public IList<MemberSpec> Candidates {
3860 protected override TypeSpec DeclaringType {
3862 return queried_type;
3866 public bool IsConditionallyExcluded {
3868 return Methods == Excluded;
3872 public override bool IsInstance {
3874 if (best_candidate != null)
3875 return !best_candidate.IsStatic;
3881 public override bool IsSideEffectFree {
3883 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3887 public override bool IsStatic {
3889 if (best_candidate != null)
3890 return best_candidate.IsStatic;
3896 public override string KindName {
3897 get { return "method"; }
3900 public override string Name {
3902 if (best_candidate != null)
3903 return best_candidate.Name;
3906 return Methods.First ().Name;
3913 // When best candidate is already know this factory can be used
3914 // to avoid expensive overload resolution to be called
3916 // NOTE: InstanceExpression has to be set manually
3918 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3920 return new MethodGroupExpr (best, queriedType, loc) {
3921 best_candidate = best,
3922 best_candidate_return = best.ReturnType
3926 public override string GetSignatureForError ()
3928 if (best_candidate != null)
3929 return best_candidate.GetSignatureForError ();
3931 return Methods.First ().GetSignatureForError ();
3934 public override Expression CreateExpressionTree (ResolveContext ec)
3936 if (best_candidate == null) {
3937 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3941 if (IsConditionallyExcluded)
3942 ec.Report.Error (765, loc,
3943 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3945 if (ConditionalAccess)
3946 Error_NullShortCircuitInsideExpressionTree (ec);
3948 return new TypeOfMethod (best_candidate, loc);
3951 protected override Expression DoResolve (ResolveContext ec)
3953 this.eclass = ExprClass.MethodGroup;
3955 if (InstanceExpression != null) {
3956 InstanceExpression = InstanceExpression.Resolve (ec);
3957 if (InstanceExpression == null)
3964 public override void Emit (EmitContext ec)
3966 throw new NotSupportedException ();
3969 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3971 var call = new CallEmitter ();
3972 call.InstanceExpression = InstanceExpression;
3973 call.ConditionalAccess = ConditionalAccess;
3976 call.EmitStatement (ec, best_candidate, arguments, loc);
3978 call.Emit (ec, best_candidate, arguments, loc);
3981 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
3983 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
3984 Statement = statement
3987 EmitCall (ec, arguments, statement);
3989 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
3992 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3994 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3995 Name, target.GetSignatureForError ());
3998 public static bool IsExtensionMethodArgument (Expression expr)
4001 // LAMESPEC: No details about which expressions are not allowed
4003 return !(expr is TypeExpr) && !(expr is BaseThis);
4007 /// Find the Applicable Function Members (7.4.2.1)
4009 /// me: Method Group expression with the members to select.
4010 /// it might contain constructors or methods (or anything
4011 /// that maps to a method).
4013 /// Arguments: ArrayList containing resolved Argument objects.
4015 /// loc: The location if we want an error to be reported, or a Null
4016 /// location for "probing" purposes.
4018 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4019 /// that is the best match of me on Arguments.
4022 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4024 // TODO: causes issues with probing mode, remove explicit Kind check
4025 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4028 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4029 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4030 r.BaseMembersProvider = this;
4031 r.InstanceQualifier = this;
4034 if (cerrors != null)
4035 r.CustomErrors = cerrors;
4037 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4038 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4039 if (best_candidate == null) {
4040 if (!r.BestCandidateIsDynamic)
4043 if (simple_name != null && ec.IsStatic)
4044 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4049 // Overload resolver had to create a new method group, all checks bellow have already been executed
4050 if (r.BestCandidateNewMethodGroup != null)
4051 return r.BestCandidateNewMethodGroup;
4053 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4054 if (InstanceExpression != null) {
4055 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4056 InstanceExpression = null;
4058 if (simple_name != null && best_candidate.IsStatic) {
4059 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4062 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4066 ResolveInstanceExpression (ec, null);
4069 var base_override = CandidateToBaseOverride (ec, best_candidate);
4070 if (base_override == best_candidate) {
4071 best_candidate_return = r.BestCandidateReturnType;
4073 best_candidate = base_override;
4074 best_candidate_return = best_candidate.ReturnType;
4077 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4078 ConstraintChecker cc = new ConstraintChecker (ec);
4079 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4083 // Additional check for possible imported base override method which
4084 // could not be done during IsOverrideMethodBaseTypeAccessible
4086 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4087 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4088 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4089 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4092 // Speed up the check by not doing it on disallowed targets
4093 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4099 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4101 var fe = left as FieldExpr;
4104 // Using method-group on struct fields makes the struct assigned. I am not sure
4105 // why but that's what .net does
4107 fe.Spec.MemberDefinition.SetIsAssigned ();
4110 simple_name = original;
4111 return base.ResolveMemberAccess (ec, left, original);
4114 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4116 type_arguments = ta;
4119 #region IBaseMembersProvider Members
4121 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4123 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4126 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4128 if (queried_type == member.DeclaringType)
4131 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4132 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4136 // Extension methods lookup after ordinary methods candidates failed to apply
4138 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4140 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4143 if (!IsExtensionMethodArgument (InstanceExpression))
4146 int arity = type_arguments == null ? 0 : type_arguments.Count;
4147 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4148 if (methods == null)
4151 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4152 emg.SetTypeArguments (rc, type_arguments);
4159 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4161 public ConstructorInstanceQualifier (TypeSpec type)
4164 InstanceType = type;
4167 public TypeSpec InstanceType { get; private set; }
4169 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4171 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4175 public struct OverloadResolver
4178 public enum Restrictions
4182 ProbingOnly = 1 << 1,
4183 CovariantDelegate = 1 << 2,
4184 NoBaseMembers = 1 << 3,
4185 BaseMembersIncluded = 1 << 4,
4186 GetEnumeratorLookup = 1 << 5
4189 public interface IBaseMembersProvider
4191 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4192 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4193 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4196 public interface IErrorHandler
4198 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4199 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4200 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4201 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4204 public interface IInstanceQualifier
4206 TypeSpec InstanceType { get; }
4207 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4210 sealed class NoBaseMembers : IBaseMembersProvider
4212 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4214 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4219 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4224 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4230 struct AmbiguousCandidate
4232 public readonly MemberSpec Member;
4233 public readonly bool Expanded;
4234 public readonly AParametersCollection Parameters;
4236 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4239 Parameters = parameters;
4240 Expanded = expanded;
4245 IList<MemberSpec> members;
4246 TypeArguments type_arguments;
4247 IBaseMembersProvider base_provider;
4248 IErrorHandler custom_errors;
4249 IInstanceQualifier instance_qualifier;
4250 Restrictions restrictions;
4251 MethodGroupExpr best_candidate_extension_group;
4252 TypeSpec best_candidate_return_type;
4254 SessionReportPrinter lambda_conv_msgs;
4256 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4257 : this (members, null, restrictions, loc)
4261 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4264 if (members == null || members.Count == 0)
4265 throw new ArgumentException ("empty members set");
4267 this.members = members;
4269 type_arguments = targs;
4270 this.restrictions = restrictions;
4271 if (IsDelegateInvoke)
4272 this.restrictions |= Restrictions.NoBaseMembers;
4274 base_provider = NoBaseMembers.Instance;
4279 public IBaseMembersProvider BaseMembersProvider {
4281 return base_provider;
4284 base_provider = value;
4288 public bool BestCandidateIsDynamic { get; set; }
4291 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4293 public MethodGroupExpr BestCandidateNewMethodGroup {
4295 return best_candidate_extension_group;
4300 // Return type can be different between best candidate and closest override
4302 public TypeSpec BestCandidateReturnType {
4304 return best_candidate_return_type;
4308 public IErrorHandler CustomErrors {
4310 return custom_errors;
4313 custom_errors = value;
4317 TypeSpec DelegateType {
4319 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4320 throw new InternalErrorException ("Not running in delegate mode", loc);
4322 return members [0].DeclaringType;
4326 public IInstanceQualifier InstanceQualifier {
4328 return instance_qualifier;
4331 instance_qualifier = value;
4335 bool IsProbingOnly {
4337 return (restrictions & Restrictions.ProbingOnly) != 0;
4341 bool IsDelegateInvoke {
4343 return (restrictions & Restrictions.DelegateInvoke) != 0;
4350 // 7.4.3.3 Better conversion from expression
4351 // Returns : 1 if a->p is better,
4352 // 2 if a->q is better,
4353 // 0 if neither is better
4355 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4357 TypeSpec argument_type = a.Type;
4360 // If argument is an anonymous function
4362 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4364 // p and q are delegate types or expression tree types
4366 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4367 if (q.MemberDefinition != p.MemberDefinition) {
4372 // Uwrap delegate from Expression<T>
4374 q = TypeManager.GetTypeArguments (q)[0];
4375 p = TypeManager.GetTypeArguments (p)[0];
4378 var p_m = Delegate.GetInvokeMethod (p);
4379 var q_m = Delegate.GetInvokeMethod (q);
4382 // With identical parameter lists
4384 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4392 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4394 if (p.Kind == MemberKind.Void) {
4395 return q.Kind != MemberKind.Void ? 2 : 0;
4399 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4401 if (q.Kind == MemberKind.Void) {
4402 return p.Kind != MemberKind.Void ? 1: 0;
4405 var am = (AnonymousMethodExpression) a.Expr;
4408 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4409 // better conversion is performed between underlying types Y1 and Y2
4411 if (p.IsGenericTask || q.IsGenericTask) {
4412 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4413 q = q.TypeArguments[0];
4414 p = p.TypeArguments[0];
4420 // An inferred return type X exists for E in the context of that parameter list, and
4421 // the conversion from X to Y1 is better than the conversion from X to Y2
4423 argument_type = am.InferReturnType (ec, null, orig_q);
4424 if (argument_type == null) {
4425 // TODO: Can this be hit?
4429 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4430 argument_type = ec.BuiltinTypes.Object;
4434 if (argument_type == p)
4437 if (argument_type == q)
4441 // The parameters are identicial and return type is not void, use better type conversion
4442 // on return type to determine better one
4444 return BetterTypeConversion (ec, p, q);
4448 // 7.4.3.4 Better conversion from type
4450 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4452 if (p == null || q == null)
4453 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4455 switch (p.BuiltinType) {
4456 case BuiltinTypeSpec.Type.Int:
4457 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4460 case BuiltinTypeSpec.Type.Long:
4461 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4464 case BuiltinTypeSpec.Type.SByte:
4465 switch (q.BuiltinType) {
4466 case BuiltinTypeSpec.Type.Byte:
4467 case BuiltinTypeSpec.Type.UShort:
4468 case BuiltinTypeSpec.Type.UInt:
4469 case BuiltinTypeSpec.Type.ULong:
4473 case BuiltinTypeSpec.Type.Short:
4474 switch (q.BuiltinType) {
4475 case BuiltinTypeSpec.Type.UShort:
4476 case BuiltinTypeSpec.Type.UInt:
4477 case BuiltinTypeSpec.Type.ULong:
4481 case BuiltinTypeSpec.Type.Dynamic:
4482 // Dynamic is never better
4486 switch (q.BuiltinType) {
4487 case BuiltinTypeSpec.Type.Int:
4488 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4491 case BuiltinTypeSpec.Type.Long:
4492 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4495 case BuiltinTypeSpec.Type.SByte:
4496 switch (p.BuiltinType) {
4497 case BuiltinTypeSpec.Type.Byte:
4498 case BuiltinTypeSpec.Type.UShort:
4499 case BuiltinTypeSpec.Type.UInt:
4500 case BuiltinTypeSpec.Type.ULong:
4504 case BuiltinTypeSpec.Type.Short:
4505 switch (p.BuiltinType) {
4506 case BuiltinTypeSpec.Type.UShort:
4507 case BuiltinTypeSpec.Type.UInt:
4508 case BuiltinTypeSpec.Type.ULong:
4512 case BuiltinTypeSpec.Type.Dynamic:
4513 // Dynamic is never better
4517 // FIXME: handle lifted operators
4519 // TODO: this is expensive
4520 Expression p_tmp = new EmptyExpression (p);
4521 Expression q_tmp = new EmptyExpression (q);
4523 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4524 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4526 if (p_to_q && !q_to_p)
4529 if (q_to_p && !p_to_q)
4536 /// Determines "Better function" between candidate
4537 /// and the current best match
4540 /// Returns a boolean indicating :
4541 /// false if candidate ain't better
4542 /// true if candidate is better than the current best match
4544 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4545 MemberSpec best, AParametersCollection bparam, bool best_params)
4547 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4548 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4550 bool better_at_least_one = false;
4551 bool are_equivalent = true;
4552 int args_count = args == null ? 0 : args.Count;
4556 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4559 // Default arguments are ignored for better decision
4560 if (a.IsDefaultArgument)
4564 // When comparing named argument the parameter type index has to be looked up
4565 // in original parameter set (override version for virtual members)
4567 NamedArgument na = a as NamedArgument;
4569 int idx = cparam.GetParameterIndexByName (na.Name);
4570 ct = candidate_pd.Types[idx];
4571 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4572 ct = TypeManager.GetElementType (ct);
4574 idx = bparam.GetParameterIndexByName (na.Name);
4575 bt = best_pd.Types[idx];
4576 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4577 bt = TypeManager.GetElementType (bt);
4579 ct = candidate_pd.Types[c_idx];
4580 bt = best_pd.Types[b_idx];
4582 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4583 ct = TypeManager.GetElementType (ct);
4587 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4588 bt = TypeManager.GetElementType (bt);
4593 if (TypeSpecComparer.IsEqual (ct, bt))
4596 are_equivalent = false;
4597 int result = BetterExpressionConversion (ec, a, ct, bt);
4599 // for each argument, the conversion to 'ct' should be no worse than
4600 // the conversion to 'bt'.
4604 // for at least one argument, the conversion to 'ct' should be better than
4605 // the conversion to 'bt'.
4607 better_at_least_one = true;
4610 if (better_at_least_one)
4614 // Tie-breaking rules are applied only for equivalent parameter types
4616 if (!are_equivalent)
4620 // If candidate is applicable in its normal form and best has a params array and is applicable
4621 // only in its expanded form, then candidate is better
4623 if (candidate_params != best_params)
4624 return !candidate_params;
4627 // We have not reached end of parameters list due to params or used default parameters
4629 while (j < candidate_pd.Count && j < best_pd.Count) {
4630 var cand_param = candidate_pd.FixedParameters [j];
4631 var best_param = best_pd.FixedParameters [j];
4633 if (candidate_pd.Count == best_pd.Count) {
4637 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4638 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4640 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4641 return cand_param.HasDefaultValue;
4643 if (cand_param.HasDefaultValue) {
4649 // Neither is better when not all arguments are provided
4651 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4652 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4653 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4655 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4662 if (candidate_pd.Count != best_pd.Count)
4663 return candidate_pd.Count < best_pd.Count;
4666 // One is a non-generic method and second is a generic method, then non-generic is better
4668 if (best.IsGeneric != candidate.IsGeneric)
4669 return best.IsGeneric;
4672 // Both methods have the same number of parameters, and the parameters have equal types
4673 // Pick the "more specific" signature using rules over original (non-inflated) types
4675 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4676 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4678 bool specific_at_least_once = false;
4679 for (j = 0; j < args_count; ++j) {
4680 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4682 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4683 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4685 ct = candidate_def_pd.Types[j];
4686 bt = best_def_pd.Types[j];
4691 TypeSpec specific = MoreSpecific (ct, bt);
4695 specific_at_least_once = true;
4698 if (specific_at_least_once)
4704 static bool CheckInflatedArguments (MethodSpec ms)
4706 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4709 // Setup constraint checker for probing only
4710 ConstraintChecker cc = new ConstraintChecker (null);
4712 var mp = ms.Parameters.Types;
4713 for (int i = 0; i < mp.Length; ++i) {
4714 var type = mp[i] as InflatedTypeSpec;
4718 var targs = type.TypeArguments;
4719 if (targs.Length == 0)
4722 // TODO: Checking inflated MVAR arguments should be enough
4723 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4730 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4732 rc.Report.Error (1729, loc,
4733 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4734 type.GetSignatureForError (), argCount.ToString ());
4738 // Determines if the candidate method is applicable to the given set of arguments
4739 // There could be two different set of parameters for same candidate where one
4740 // is the closest override for default values and named arguments checks and second
4741 // one being the virtual base for the parameter types and modifiers.
4743 // A return value rates candidate method compatibility,
4745 // 0 = the best, int.MaxValue = the worst
4747 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)
4750 // Each step has allocated 10 values, it can overflow for
4751 // more than 10 arguments but that's ok as it's used for
4752 // better error reporting only
4754 const int ArgumentCountMismatch = 1000000000;
4755 const int NamedArgumentsMismatch = 100000000;
4756 const int DefaultArgumentMismatch = 10000000;
4757 const int UnexpectedTypeArguments = 1000000;
4758 const int TypeArgumentsMismatch = 100000;
4759 const int InflatedTypesMismatch = 10000;
4761 // Parameters of most-derived type used mainly for named and optional parameters
4762 var pd = pm.Parameters;
4764 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4765 // params modifier instead of most-derived type
4766 var cpd = ((IParametersMember) candidate).Parameters;
4767 int param_count = pd.Count;
4768 int optional_count = 0;
4770 Arguments orig_args = arguments;
4772 if (arg_count != param_count) {
4774 // No arguments expansion when doing exact match for delegates
4776 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4777 for (int i = 0; i < pd.Count; ++i) {
4778 if (pd.FixedParameters[i].HasDefaultValue) {
4779 optional_count = pd.Count - i;
4785 if (optional_count != 0) {
4786 // Readjust expected number when params used
4787 if (cpd.HasParams) {
4789 if (arg_count < param_count)
4791 } else if (arg_count > param_count) {
4792 int args_gap = System.Math.Abs (arg_count - param_count);
4793 return ArgumentCountMismatch + args_gap;
4794 } else if (arg_count < param_count - optional_count) {
4795 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4796 return ArgumentCountMismatch + args_gap;
4798 } else if (arg_count != param_count) {
4799 int args_gap = System.Math.Abs (arg_count - param_count);
4801 return ArgumentCountMismatch + args_gap;
4802 if (arg_count < param_count - 1)
4803 return ArgumentCountMismatch + args_gap;
4806 // Resize to fit optional arguments
4807 if (optional_count != 0) {
4808 if (arguments == null) {
4809 arguments = new Arguments (optional_count);
4811 // Have to create a new container, so the next run can do same
4812 var resized = new Arguments (param_count);
4813 resized.AddRange (arguments);
4814 arguments = resized;
4817 for (int i = arg_count; i < param_count; ++i)
4818 arguments.Add (null);
4822 if (arg_count > 0) {
4824 // Shuffle named arguments to the right positions if there are any
4826 if (arguments[arg_count - 1] is NamedArgument) {
4827 arg_count = arguments.Count;
4829 for (int i = 0; i < arg_count; ++i) {
4830 bool arg_moved = false;
4832 NamedArgument na = arguments[i] as NamedArgument;
4836 int index = pd.GetParameterIndexByName (na.Name);
4838 // Named parameter not found
4840 return NamedArgumentsMismatch - i;
4842 // already reordered
4847 if (index >= param_count) {
4848 // When using parameters which should not be available to the user
4849 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4852 arguments.Add (null);
4856 if (index == arg_count)
4857 return NamedArgumentsMismatch - i - 1;
4859 temp = arguments [index];
4861 // The slot has been taken by positional argument
4862 if (temp != null && !(temp is NamedArgument))
4867 arguments = arguments.MarkOrderedArgument (na);
4871 if (arguments == orig_args) {
4872 arguments = new Arguments (orig_args.Count);
4873 arguments.AddRange (orig_args);
4876 arguments[index] = arguments[i];
4877 arguments[i] = temp;
4884 arg_count = arguments.Count;
4886 } else if (arguments != null) {
4887 arg_count = arguments.Count;
4891 // Don't do any expensive checks when the candidate cannot succeed
4893 if (arg_count != param_count && !cpd.HasParams)
4894 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4896 var dep = candidate.GetMissingDependencies ();
4898 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4903 // 1. Handle generic method using type arguments when specified or type inference
4906 var ms = candidate as MethodSpec;
4907 if (ms != null && ms.IsGeneric) {
4908 if (type_arguments != null) {
4909 var g_args_count = ms.Arity;
4910 if (g_args_count != type_arguments.Count)
4911 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4913 if (type_arguments.Arguments != null)
4914 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4917 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4918 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4919 // candidate was found use the set to report more details about what was wrong with lambda body.
4920 // The general idea is to distinguish between code errors and errors caused by
4921 // trial-and-error type inference
4923 if (lambda_conv_msgs == null) {
4924 for (int i = 0; i < arg_count; i++) {
4925 Argument a = arguments[i];
4929 var am = a.Expr as AnonymousMethodExpression;
4931 if (lambda_conv_msgs == null)
4932 lambda_conv_msgs = new SessionReportPrinter ();
4934 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4939 var ti = new TypeInference (arguments);
4940 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4943 return TypeArgumentsMismatch - ti.InferenceScore;
4946 // Clear any error messages when the result was success
4948 if (lambda_conv_msgs != null)
4949 lambda_conv_msgs.ClearSession ();
4951 if (i_args.Length != 0) {
4953 for (int i = 0; i < i_args.Length; ++i) {
4954 var ta = i_args [i];
4955 if (!ta.IsAccessible (ec))
4956 return TypeArgumentsMismatch - i;
4960 ms = ms.MakeGenericMethod (ec, i_args);
4965 // Type arguments constraints have to match for the method to be applicable
4967 if (!CheckInflatedArguments (ms)) {
4969 return InflatedTypesMismatch;
4973 // We have a generic return type and at same time the method is override which
4974 // means we have to also inflate override return type in case the candidate is
4975 // best candidate and override return type is different to base return type.
4977 // virtual Foo<T, object> with override Foo<T, dynamic>
4979 if (candidate != pm) {
4980 MethodSpec override_ms = (MethodSpec) pm;
4981 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4982 returnType = inflator.Inflate (returnType);
4984 returnType = ms.ReturnType;
4991 if (type_arguments != null)
4992 return UnexpectedTypeArguments;
4998 // 2. Each argument has to be implicitly convertible to method parameter
5000 Parameter.Modifier p_mod = 0;
5003 for (int i = 0; i < arg_count; i++) {
5004 Argument a = arguments[i];
5006 var fp = pd.FixedParameters[i];
5007 if (!fp.HasDefaultValue) {
5008 arguments = orig_args;
5009 return arg_count * 2 + 2;
5013 // Get the default value expression, we can use the same expression
5014 // if the type matches
5016 Expression e = fp.DefaultValue;
5018 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5020 // Restore for possible error reporting
5021 for (int ii = i; ii < arg_count; ++ii)
5022 arguments.RemoveAt (i);
5024 return (arg_count - i) * 2 + 1;
5028 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5030 // LAMESPEC: Attributes can be mixed together with build-in priority
5032 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5033 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5034 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5035 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5036 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5037 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5041 arguments[i] = new Argument (e, Argument.AType.Default);
5045 if (p_mod != Parameter.Modifier.PARAMS) {
5046 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5048 } else if (!params_expanded_form) {
5049 params_expanded_form = true;
5050 pt = ((ElementTypeSpec) pt).Element;
5056 if (!params_expanded_form) {
5057 if (a.IsExtensionType) {
5059 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
5061 // LAMESPEC: or implicit type parameter conversion
5064 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
5065 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
5066 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
5071 score = IsArgumentCompatible (ec, a, p_mod, pt);
5074 dynamicArgument = true;
5079 // It can be applicable in expanded form (when not doing exact match like for delegates)
5081 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5082 if (!params_expanded_form) {
5083 pt = ((ElementTypeSpec) pt).Element;
5087 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5090 params_expanded_form = true;
5091 dynamicArgument = true;
5092 } else if (score == 0 || arg_count > pd.Count) {
5093 params_expanded_form = true;
5098 if (params_expanded_form)
5100 return (arg_count - i) * 2 + score;
5105 // Restore original arguments for dynamic binder to keep the intention of original source code
5107 if (dynamicArgument)
5108 arguments = orig_args;
5113 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5115 if (e is Constant && e.Type == ptype)
5119 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5121 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5122 e = new MemberAccess (new MemberAccess (new MemberAccess (
5123 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5124 } else if (e is Constant) {
5126 // Handles int to int? conversions, DefaultParameterValue check
5128 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5132 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5135 return e.Resolve (ec);
5139 // Tests argument compatibility with the parameter
5140 // The possible return values are
5142 // 1 - modifier mismatch
5143 // 2 - type mismatch
5144 // -1 - dynamic binding required
5146 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5149 // Types have to be identical when ref or out modifer
5150 // is used and argument is not of dynamic type
5152 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5153 var arg_type = argument.Type;
5155 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5157 // Using dynamic for ref/out parameter can still succeed at runtime
5159 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5165 if (arg_type != parameter) {
5166 if (arg_type == InternalType.VarOutType)
5170 // Do full equality check after quick path
5172 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5174 // Using dynamic for ref/out parameter can still succeed at runtime
5176 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5184 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5188 // Use implicit conversion in all modes to return same candidates when the expression
5189 // is used as argument or delegate conversion
5191 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5192 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5199 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5201 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5203 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5206 var ac_p = p as ArrayContainer;
5208 var ac_q = q as ArrayContainer;
5212 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5213 if (specific == ac_p.Element)
5215 if (specific == ac_q.Element)
5217 } else if (p.IsGeneric && q.IsGeneric) {
5218 var pargs = TypeManager.GetTypeArguments (p);
5219 var qargs = TypeManager.GetTypeArguments (q);
5221 bool p_specific_at_least_once = false;
5222 bool q_specific_at_least_once = false;
5224 for (int i = 0; i < pargs.Length; i++) {
5225 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5226 if (specific == pargs[i])
5227 p_specific_at_least_once = true;
5228 if (specific == qargs[i])
5229 q_specific_at_least_once = true;
5232 if (p_specific_at_least_once && !q_specific_at_least_once)
5234 if (!p_specific_at_least_once && q_specific_at_least_once)
5242 // Find the best method from candidate list
5244 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5246 List<AmbiguousCandidate> ambiguous_candidates = null;
5248 MemberSpec best_candidate;
5249 Arguments best_candidate_args = null;
5250 bool best_candidate_params = false;
5251 bool best_candidate_dynamic = false;
5252 int best_candidate_rate;
5253 IParametersMember best_parameter_member = null;
5255 int args_count = args != null ? args.Count : 0;
5257 Arguments candidate_args = args;
5258 bool error_mode = false;
5259 MemberSpec invocable_member = null;
5262 best_candidate = null;
5263 best_candidate_rate = int.MaxValue;
5265 var type_members = members;
5267 for (int i = 0; i < type_members.Count; ++i) {
5268 var member = type_members[i];
5271 // Methods in a base class are not candidates if any method in a derived
5272 // class is applicable
5274 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5278 if (!member.IsAccessible (rc))
5281 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5284 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5285 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5290 IParametersMember pm = member as IParametersMember;
5293 // Will use it later to report ambiguity between best method and invocable member
5295 if (Invocation.IsMemberInvocable (member))
5296 invocable_member = member;
5302 // Overload resolution is looking for base member but using parameter names
5303 // and default values from the closest member. That means to do expensive lookup
5304 // for the closest override for virtual or abstract members
5306 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5307 var override_params = base_provider.GetOverrideMemberParameters (member);
5308 if (override_params != null)
5309 pm = override_params;
5313 // Check if the member candidate is applicable
5315 bool params_expanded_form = false;
5316 bool dynamic_argument = false;
5317 TypeSpec rt = pm.MemberType;
5318 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5320 if (lambda_conv_msgs != null)
5321 lambda_conv_msgs.EndSession ();
5324 // How does it score compare to others
5326 if (candidate_rate < best_candidate_rate) {
5328 // Fatal error (missing dependency), cannot continue
5329 if (candidate_rate < 0)
5332 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5333 // Only parameterless methods are considered
5335 best_candidate_rate = candidate_rate;
5336 best_candidate = member;
5337 best_candidate_args = candidate_args;
5338 best_candidate_params = params_expanded_form;
5339 best_candidate_dynamic = dynamic_argument;
5340 best_parameter_member = pm;
5341 best_candidate_return_type = rt;
5343 } else if (candidate_rate == 0) {
5345 // The member look is done per type for most operations but sometimes
5346 // it's not possible like for binary operators overload because they
5347 // are unioned between 2 sides
5349 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5350 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5355 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5357 // We pack all interface members into top level type which makes the overload resolution
5358 // more complicated for interfaces. We compensate it by removing methods with same
5359 // signature when building the cache hence this path should not really be hit often
5362 // interface IA { void Foo (int arg); }
5363 // interface IB : IA { void Foo (params int[] args); }
5365 // IB::Foo is the best overload when calling IB.Foo (1)
5368 if (ambiguous_candidates != null) {
5369 foreach (var amb_cand in ambiguous_candidates) {
5370 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5379 ambiguous_candidates = null;
5382 // Is the new candidate better
5383 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5387 best_candidate = member;
5388 best_candidate_args = candidate_args;
5389 best_candidate_params = params_expanded_form;
5390 best_candidate_dynamic = dynamic_argument;
5391 best_parameter_member = pm;
5392 best_candidate_return_type = rt;
5394 // It's not better but any other found later could be but we are not sure yet
5395 if (ambiguous_candidates == null)
5396 ambiguous_candidates = new List<AmbiguousCandidate> ();
5398 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5402 // Restore expanded arguments
5403 candidate_args = args;
5405 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5408 // We've found exact match
5410 if (best_candidate_rate == 0)
5414 // Try extension methods lookup when no ordinary method match was found and provider enables it
5417 var emg = base_provider.LookupExtensionMethod (rc);
5419 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5421 best_candidate_extension_group = emg;
5422 return (T) (MemberSpec) emg.BestCandidate;
5427 // Don't run expensive error reporting mode for probing
5434 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5437 lambda_conv_msgs = null;
5442 // No best member match found, report an error
5444 if (best_candidate_rate != 0 || error_mode) {
5445 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5449 if (best_candidate_dynamic) {
5450 if (args[0].IsExtensionType) {
5451 rc.Report.Error (1973, loc,
5452 "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",
5453 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5457 // Check type constraints only when explicit type arguments are used
5459 if (best_candidate.IsGeneric && type_arguments != null) {
5460 MethodSpec bc = best_candidate as MethodSpec;
5461 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5462 ConstraintChecker cc = new ConstraintChecker (rc);
5463 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5467 BestCandidateIsDynamic = true;
5472 // These flags indicates we are running delegate probing conversion. No need to
5473 // do more expensive checks
5475 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5476 return (T) best_candidate;
5478 if (ambiguous_candidates != null) {
5480 // Now check that there are no ambiguities i.e the selected method
5481 // should be better than all the others
5483 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5484 var candidate = ambiguous_candidates [ix];
5486 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5487 var ambiguous = candidate.Member;
5488 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5489 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5490 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5491 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5492 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5495 return (T) best_candidate;
5500 if (invocable_member != null && !IsProbingOnly) {
5501 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5502 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5503 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5504 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5508 // And now check if the arguments are all
5509 // compatible, perform conversions if
5510 // necessary etc. and return if everything is
5513 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5516 if (best_candidate == null)
5520 // Don't run possibly expensive checks in probing mode
5522 if (!IsProbingOnly && !rc.IsInProbingMode) {
5524 // Check ObsoleteAttribute on the best method
5526 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5527 if (oa != null && !rc.IsObsolete)
5528 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5530 best_candidate.MemberDefinition.SetIsUsed ();
5533 args = best_candidate_args;
5534 return (T) best_candidate;
5537 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5539 return ResolveMember<MethodSpec> (rc, ref args);
5542 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5543 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5545 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5548 if (a.Type == InternalType.ErrorType)
5551 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5552 ec.Report.SymbolRelatedToPreviousError (method);
5553 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5554 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5555 TypeManager.CSharpSignature (method));
5558 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5559 TypeManager.CSharpSignature (method));
5560 } else if (IsDelegateInvoke) {
5561 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5562 DelegateType.GetSignatureForError ());
5564 ec.Report.SymbolRelatedToPreviousError (method);
5565 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5566 method.GetSignatureForError ());
5569 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5571 string index = (idx + 1).ToString ();
5572 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5573 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5574 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5575 index, Parameter.GetModifierSignature (a.Modifier));
5577 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5578 index, Parameter.GetModifierSignature (mod));
5580 string p1 = a.GetSignatureForError ();
5581 string p2 = paramType.GetSignatureForError ();
5584 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5585 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5588 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5589 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5590 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5593 ec.Report.Error (1503, a.Expr.Location,
5594 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5599 // We have failed to find exact match so we return error info about the closest match
5601 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5603 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5604 int arg_count = args == null ? 0 : args.Count;
5606 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5607 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5608 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5612 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5617 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5618 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5619 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5623 // For candidates which match on parameters count report more details about incorrect arguments
5626 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5627 // Reject any inaccessible member
5628 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5629 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5630 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5634 var ms = best_candidate as MethodSpec;
5635 if (ms != null && ms.IsGeneric) {
5636 bool constr_ok = true;
5637 if (ms.TypeArguments != null)
5638 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5640 if (ta_count == 0 && ms.TypeArguments == null) {
5641 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5645 rc.Report.Error (411, loc,
5646 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5647 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5654 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5660 // We failed to find any method with correct argument count, report best candidate
5662 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5665 if (best_candidate.Kind == MemberKind.Constructor) {
5666 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5667 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5668 } else if (IsDelegateInvoke) {
5669 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5670 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5671 DelegateType.GetSignatureForError (), arg_count.ToString ());
5673 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5674 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5675 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5676 name, arg_count.ToString ());
5680 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5682 var p = ((IParametersMember)best_candidate).Parameters;
5687 for (int i = p.Count - 1; i != 0; --i) {
5688 var fp = p.FixedParameters [i];
5689 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5699 foreach (var arg in args) {
5700 var na = arg as NamedArgument;
5704 if (na.Name == name) {
5713 return args.Count + 1 == pm.Parameters.Count;
5716 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5718 var pd = pm.Parameters;
5719 var cpd = ((IParametersMember) member).Parameters;
5720 var ptypes = cpd.Types;
5722 Parameter.Modifier p_mod = 0;
5724 int a_idx = 0, a_pos = 0;
5726 ArrayInitializer params_initializers = null;
5727 bool has_unsafe_arg = pm.MemberType.IsPointer;
5728 int arg_count = args == null ? 0 : args.Count;
5730 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5735 if (p_mod != Parameter.Modifier.PARAMS) {
5736 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5738 has_unsafe_arg |= pt.IsPointer;
5740 if (p_mod == Parameter.Modifier.PARAMS) {
5741 if (chose_params_expanded) {
5742 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5743 pt = TypeManager.GetElementType (pt);
5749 // Types have to be identical when ref or out modifer is used
5751 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5752 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5755 var arg_type = a.Type;
5759 if (arg_type == InternalType.VarOutType) {
5761 // Set underlying variable type based on parameter type
5763 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5767 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5771 NamedArgument na = a as NamedArgument;
5773 int name_index = pd.GetParameterIndexByName (na.Name);
5774 if (name_index < 0 || name_index >= pd.Count) {
5775 if (IsDelegateInvoke) {
5776 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5777 ec.Report.Error (1746, na.Location,
5778 "The delegate `{0}' does not contain a parameter named `{1}'",
5779 DelegateType.GetSignatureForError (), na.Name);
5781 ec.Report.SymbolRelatedToPreviousError (member);
5782 ec.Report.Error (1739, na.Location,
5783 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5784 TypeManager.CSharpSignature (member), na.Name);
5786 } else if (args[name_index] != a && args[name_index] != null) {
5787 if (IsDelegateInvoke)
5788 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5790 ec.Report.SymbolRelatedToPreviousError (member);
5792 ec.Report.Error (1744, na.Location,
5793 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5798 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5801 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5802 custom_errors.NoArgumentMatch (ec, member);
5807 if (a.IsExtensionType) {
5808 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5811 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5813 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5816 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5823 // Convert params arguments to an array initializer
5825 if (params_initializers != null) {
5826 // we choose to use 'a.Expr' rather than 'conv' so that
5827 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5828 params_initializers.Add (a.Expr);
5829 args.RemoveAt (a_idx--);
5835 // Update the argument with the implicit conversion
5839 if (a_idx != arg_count) {
5841 // Convert all var out argument to error type for less confusing error reporting
5842 // when no matching overload is found
5844 for (; a_idx < arg_count; a_idx++) {
5845 var arg = args [a_idx];
5849 if (arg.Type == InternalType.VarOutType) {
5850 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5854 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5859 // Fill not provided arguments required by params modifier
5861 if (params_initializers == null && arg_count + 1 == pd.Count) {
5863 args = new Arguments (1);
5865 pt = ptypes[pd.Count - 1];
5866 pt = TypeManager.GetElementType (pt);
5867 has_unsafe_arg |= pt.IsPointer;
5868 params_initializers = new ArrayInitializer (0, loc);
5872 // Append an array argument with all params arguments
5874 if (params_initializers != null) {
5875 args.Add (new Argument (
5876 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5880 if (has_unsafe_arg && !ec.IsUnsafe) {
5881 Expression.UnsafeError (ec, loc);
5885 // We could infer inaccesible type arguments
5887 if (type_arguments == null && member.IsGeneric) {
5888 var ms = (MethodSpec) member;
5889 foreach (var ta in ms.TypeArguments) {
5890 if (!ta.IsAccessible (ec)) {
5891 ec.Report.SymbolRelatedToPreviousError (ta);
5892 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5902 public class ConstantExpr : MemberExpr
5904 readonly ConstSpec constant;
5906 public ConstantExpr (ConstSpec constant, Location loc)
5908 this.constant = constant;
5912 public override string Name {
5913 get { throw new NotImplementedException (); }
5916 public override string KindName {
5917 get { return "constant"; }
5920 public override bool IsInstance {
5921 get { return !IsStatic; }
5924 public override bool IsStatic {
5925 get { return true; }
5928 protected override TypeSpec DeclaringType {
5929 get { return constant.DeclaringType; }
5932 public override Expression CreateExpressionTree (ResolveContext ec)
5934 throw new NotSupportedException ("ET");
5937 protected override Expression DoResolve (ResolveContext rc)
5939 ResolveInstanceExpression (rc, null);
5940 DoBestMemberChecks (rc, constant);
5942 var c = constant.GetConstant (rc);
5944 // Creates reference expression to the constant value
5945 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5948 public override void Emit (EmitContext ec)
5950 throw new NotSupportedException ();
5953 public override string GetSignatureForError ()
5955 return constant.GetSignatureForError ();
5958 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5960 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5965 // Fully resolved expression that references a Field
5967 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5969 protected FieldSpec spec;
5970 VariableInfo variable_info;
5972 LocalTemporary temp;
5975 protected FieldExpr (Location l)
5980 public FieldExpr (FieldSpec spec, Location loc)
5985 type = spec.MemberType;
5988 public FieldExpr (FieldBase fi, Location l)
5995 public override string Name {
6001 public bool IsHoisted {
6003 IVariableReference hv = InstanceExpression as IVariableReference;
6004 return hv != null && hv.IsHoisted;
6008 public override bool IsInstance {
6010 return !spec.IsStatic;
6014 public override bool IsStatic {
6016 return spec.IsStatic;
6020 public override string KindName {
6021 get { return "field"; }
6024 public FieldSpec Spec {
6030 protected override TypeSpec DeclaringType {
6032 return spec.DeclaringType;
6036 public VariableInfo VariableInfo {
6038 return variable_info;
6044 public override string GetSignatureForError ()
6046 return spec.GetSignatureForError ();
6049 public bool IsMarshalByRefAccess (ResolveContext rc)
6051 // Checks possible ldflda of field access expression
6052 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6053 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6054 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6057 public void SetHasAddressTaken ()
6059 IVariableReference vr = InstanceExpression as IVariableReference;
6061 vr.SetHasAddressTaken ();
6065 protected override void CloneTo (CloneContext clonectx, Expression target)
6067 var t = (FieldExpr) target;
6069 if (InstanceExpression != null)
6070 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6073 public override Expression CreateExpressionTree (ResolveContext ec)
6075 if (ConditionalAccess) {
6076 Error_NullShortCircuitInsideExpressionTree (ec);
6079 return CreateExpressionTree (ec, true);
6082 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6085 Expression instance;
6087 if (InstanceExpression == null) {
6088 instance = new NullLiteral (loc);
6089 } else if (convertInstance) {
6090 instance = InstanceExpression.CreateExpressionTree (ec);
6092 args = new Arguments (1);
6093 args.Add (new Argument (InstanceExpression));
6094 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6097 args = Arguments.CreateForExpressionTree (ec, null,
6099 CreateTypeOfExpression ());
6101 return CreateExpressionFactoryCall (ec, "Field", args);
6104 public Expression CreateTypeOfExpression ()
6106 return new TypeOfField (spec, loc);
6109 protected override Expression DoResolve (ResolveContext ec)
6111 spec.MemberDefinition.SetIsUsed ();
6113 return DoResolve (ec, null);
6116 Expression DoResolve (ResolveContext ec, Expression rhs)
6118 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6121 ResolveConditionalAccessReceiver (ec);
6123 if (ResolveInstanceExpression (ec, rhs)) {
6124 // Resolve the field's instance expression while flow analysis is turned
6125 // off: when accessing a field "a.b", we must check whether the field
6126 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6128 if (lvalue_instance) {
6129 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6131 Expression right_side =
6132 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6134 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6136 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6139 if (InstanceExpression == null)
6143 DoBestMemberChecks (ec, spec);
6145 if (conditional_access_receiver)
6146 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6149 var fb = spec as FixedFieldSpec;
6150 IVariableReference var = InstanceExpression as IVariableReference;
6153 IFixedExpression fe = InstanceExpression as IFixedExpression;
6154 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6155 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6158 if (InstanceExpression.eclass != ExprClass.Variable) {
6159 ec.Report.SymbolRelatedToPreviousError (spec);
6160 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6161 TypeManager.GetFullNameSignature (spec));
6162 } else if (var != null && var.IsHoisted) {
6163 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6166 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6170 // Set flow-analysis variable info for struct member access. It will be check later
6171 // for precise error reporting
6173 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6174 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6177 if (ConditionalAccess) {
6178 if (conditional_access_receiver)
6179 type = LiftMemberType (ec, type);
6181 if (InstanceExpression.IsNull)
6182 return Constant.CreateConstantFromValue (type, null, loc);
6185 eclass = ExprClass.Variable;
6189 public void SetFieldAssigned (FlowAnalysisContext fc)
6194 bool lvalue_instance = spec.DeclaringType.IsStruct;
6195 if (lvalue_instance) {
6196 var var = InstanceExpression as IVariableReference;
6197 if (var != null && var.VariableInfo != null) {
6198 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6202 var fe = InstanceExpression as FieldExpr;
6204 Expression instance;
6207 instance = fe.InstanceExpression;
6208 var fe_instance = instance as FieldExpr;
6209 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6210 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6211 var var = InstanceExpression as IVariableReference;
6212 if (var != null && var.VariableInfo == null) {
6213 var var_inst = instance as IVariableReference;
6214 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6215 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6219 if (fe_instance != null) {
6228 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6229 instance.FlowAnalysis (fc);
6231 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6232 InstanceExpression.FlowAnalysis (fc);
6236 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6238 // The return value is always null. Returning a value simplifies calling code.
6240 if (right_side == EmptyExpression.OutAccess) {
6242 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6243 GetSignatureForError ());
6245 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6246 GetSignatureForError ());
6252 if (right_side == EmptyExpression.LValueMemberAccess) {
6253 // Already reported as CS1648/CS1650
6257 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6259 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6260 GetSignatureForError ());
6262 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6263 GetSignatureForError ());
6269 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6270 GetSignatureForError ());
6272 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6273 GetSignatureForError ());
6279 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6281 if (ConditionalAccess)
6282 throw new NotSupportedException ("null propagating operator assignment");
6284 if (spec is FixedFieldSpec) {
6285 // It could be much better error message but we want to be error compatible
6286 Error_ValueAssignment (ec, right_side);
6289 Expression e = DoResolve (ec, right_side);
6294 spec.MemberDefinition.SetIsAssigned ();
6296 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6297 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6298 ec.Report.Warning (420, 1, loc,
6299 "`{0}': A volatile field references will not be treated as volatile",
6300 spec.GetSignatureForError ());
6303 if (spec.IsReadOnly) {
6304 // InitOnly fields can only be assigned in constructors or initializers
6305 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6306 return Error_AssignToReadonly (ec, right_side);
6308 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6310 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6311 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6312 return Error_AssignToReadonly (ec, right_side);
6313 // static InitOnly fields cannot be assigned-to in an instance constructor
6314 if (IsStatic && !ec.IsStatic)
6315 return Error_AssignToReadonly (ec, right_side);
6316 // instance constructors can't modify InitOnly fields of other instances of the same type
6317 if (!IsStatic && !(InstanceExpression is This))
6318 return Error_AssignToReadonly (ec, right_side);
6322 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6323 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6324 ec.Report.Warning (197, 1, loc,
6325 "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",
6326 GetSignatureForError ());
6329 eclass = ExprClass.Variable;
6333 public override void FlowAnalysis (FlowAnalysisContext fc)
6335 var var = InstanceExpression as IVariableReference;
6337 var vi = var.VariableInfo;
6338 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6339 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6343 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6347 base.FlowAnalysis (fc);
6349 if (conditional_access_receiver)
6350 fc.ConditionalAccessEnd ();
6353 public override int GetHashCode ()
6355 return spec.GetHashCode ();
6358 public bool IsFixed {
6361 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6363 IVariableReference variable = InstanceExpression as IVariableReference;
6364 if (variable != null)
6365 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6367 IFixedExpression fe = InstanceExpression as IFixedExpression;
6368 return fe != null && fe.IsFixed;
6372 public override bool Equals (object obj)
6374 FieldExpr fe = obj as FieldExpr;
6378 if (spec != fe.spec)
6381 if (InstanceExpression == null || fe.InstanceExpression == null)
6384 return InstanceExpression.Equals (fe.InstanceExpression);
6387 public void Emit (EmitContext ec, bool leave_copy)
6389 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6393 ec.Emit (OpCodes.Volatile);
6395 ec.Emit (OpCodes.Ldsfld, spec);
6398 if (conditional_access_receiver)
6399 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6401 EmitInstance (ec, false);
6404 // Optimization for build-in types
6405 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6406 ec.EmitLoadFromPtr (type);
6408 var ff = spec as FixedFieldSpec;
6410 ec.Emit (OpCodes.Ldflda, spec);
6411 ec.Emit (OpCodes.Ldflda, ff.Element);
6414 ec.Emit (OpCodes.Volatile);
6416 ec.Emit (OpCodes.Ldfld, spec);
6420 if (conditional_access_receiver) {
6421 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6426 ec.Emit (OpCodes.Dup);
6428 temp = new LocalTemporary (this.Type);
6434 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6436 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6437 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6442 if (ConditionalAccess)
6443 throw new NotImplementedException ("null operator assignment");
6445 if (has_await_source)
6446 source = source.EmitToField (ec);
6448 EmitInstance (ec, prepared);
6453 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6454 ec.Emit (OpCodes.Dup);
6456 temp = new LocalTemporary (this.Type);
6461 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6462 ec.Emit (OpCodes.Volatile);
6464 spec.MemberDefinition.SetIsAssigned ();
6467 ec.Emit (OpCodes.Stsfld, spec);
6469 ec.Emit (OpCodes.Stfld, spec);
6471 if (ec.NotifyEvaluatorOnStore) {
6473 throw new NotImplementedException ("instance field write");
6476 ec.Emit (OpCodes.Dup);
6478 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6489 // Emits store to field with prepared values on stack
6491 public void EmitAssignFromStack (EmitContext ec)
6494 ec.Emit (OpCodes.Stsfld, spec);
6496 ec.Emit (OpCodes.Stfld, spec);
6500 public override void Emit (EmitContext ec)
6505 public override void EmitSideEffect (EmitContext ec)
6507 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6509 if (is_volatile) // || is_marshal_by_ref ())
6510 base.EmitSideEffect (ec);
6513 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6515 if ((mode & AddressOp.Store) != 0)
6516 spec.MemberDefinition.SetIsAssigned ();
6517 if ((mode & AddressOp.Load) != 0)
6518 spec.MemberDefinition.SetIsUsed ();
6521 // Handle initonly fields specially: make a copy and then
6522 // get the address of the copy.
6525 if (spec.IsReadOnly){
6527 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6539 var temp = ec.GetTemporaryLocal (type);
6540 ec.Emit (OpCodes.Stloc, temp);
6541 ec.Emit (OpCodes.Ldloca, temp);
6547 ec.Emit (OpCodes.Ldsflda, spec);
6550 EmitInstance (ec, false);
6551 ec.Emit (OpCodes.Ldflda, spec);
6555 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6557 return MakeExpression (ctx);
6560 public override SLE.Expression MakeExpression (BuilderContext ctx)
6563 return base.MakeExpression (ctx);
6565 return SLE.Expression.Field (
6566 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6567 spec.GetMetaInfo ());
6571 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6573 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6579 // Expression that evaluates to a Property.
6581 // This is not an LValue because we need to re-write the expression. We
6582 // can not take data from the stack and store it.
6584 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6586 Arguments arguments;
6588 public PropertyExpr (PropertySpec spec, Location l)
6591 best_candidate = spec;
6592 type = spec.MemberType;
6597 protected override Arguments Arguments {
6606 protected override TypeSpec DeclaringType {
6608 return best_candidate.DeclaringType;
6612 public override string Name {
6614 return best_candidate.Name;
6618 public override bool IsInstance {
6624 public override bool IsStatic {
6626 return best_candidate.IsStatic;
6630 public override string KindName {
6631 get { return "property"; }
6634 public PropertySpec PropertyInfo {
6636 return best_candidate;
6642 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6644 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6647 var args_count = arguments == null ? 0 : arguments.Count;
6648 if (args_count != body.Parameters.Count && args_count == 0)
6651 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6652 mg.InstanceExpression = InstanceExpression;
6657 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6659 return new PropertyExpr (spec, loc) {
6665 public override Expression CreateExpressionTree (ResolveContext ec)
6667 if (ConditionalAccess) {
6668 Error_NullShortCircuitInsideExpressionTree (ec);
6672 if (IsSingleDimensionalArrayLength ()) {
6673 args = new Arguments (1);
6674 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6675 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6678 args = new Arguments (2);
6679 if (InstanceExpression == null)
6680 args.Add (new Argument (new NullLiteral (loc)));
6682 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6683 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6684 return CreateExpressionFactoryCall (ec, "Property", args);
6687 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6689 DoResolveLValue (rc, null);
6690 return new TypeOfMethod (Setter, loc);
6693 public override string GetSignatureForError ()
6695 return best_candidate.GetSignatureForError ();
6698 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6701 return base.MakeExpression (ctx);
6703 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6707 public override SLE.Expression MakeExpression (BuilderContext ctx)
6710 return base.MakeExpression (ctx);
6712 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6716 void Error_PropertyNotValid (ResolveContext ec)
6718 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6719 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6720 GetSignatureForError ());
6723 bool IsSingleDimensionalArrayLength ()
6725 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6728 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6729 return ac != null && ac.Rank == 1;
6732 public override void Emit (EmitContext ec, bool leave_copy)
6735 // Special case: length of single dimension array property is turned into ldlen
6737 if (IsSingleDimensionalArrayLength ()) {
6738 if (conditional_access_receiver) {
6739 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6742 EmitInstance (ec, false);
6744 ec.Emit (OpCodes.Ldlen);
6745 ec.Emit (OpCodes.Conv_I4);
6747 if (conditional_access_receiver) {
6748 ec.CloseConditionalAccess (type);
6754 base.Emit (ec, leave_copy);
6757 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6760 LocalTemporary await_source_arg = null;
6762 if (isCompound && !(source is DynamicExpressionStatement)) {
6763 emitting_compound_assignment = true;
6766 if (has_await_arguments) {
6767 await_source_arg = new LocalTemporary (Type);
6768 await_source_arg.Store (ec);
6770 args = new Arguments (1);
6771 args.Add (new Argument (await_source_arg));
6774 temp = await_source_arg;
6777 has_await_arguments = false;
6782 ec.Emit (OpCodes.Dup);
6783 temp = new LocalTemporary (this.Type);
6788 args = arguments ?? new Arguments (1);
6792 temp = new LocalTemporary (this.Type);
6794 args.Add (new Argument (temp));
6796 args.Add (new Argument (source));
6800 emitting_compound_assignment = false;
6802 var call = new CallEmitter ();
6803 call.InstanceExpression = InstanceExpression;
6805 call.InstanceExpressionOnStack = true;
6807 if (ConditionalAccess) {
6808 call.ConditionalAccess = true;
6812 call.Emit (ec, Setter, args, loc);
6814 call.EmitStatement (ec, Setter, args, loc);
6821 if (await_source_arg != null) {
6822 await_source_arg.Release (ec);
6826 public override void FlowAnalysis (FlowAnalysisContext fc)
6828 base.FlowAnalysis (fc);
6830 if (conditional_access_receiver)
6831 fc.ConditionalAccessEnd ();
6834 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6836 eclass = ExprClass.PropertyAccess;
6838 if (best_candidate.IsNotCSharpCompatible) {
6839 Error_PropertyNotValid (rc);
6842 ResolveInstanceExpression (rc, right_side);
6844 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6845 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6846 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6848 type = p.MemberType;
6852 DoBestMemberChecks (rc, best_candidate);
6854 // Handling of com-imported properties with any number of default property parameters
6855 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6856 var p = best_candidate.Get.Parameters;
6857 arguments = new Arguments (p.Count);
6858 for (int i = 0; i < p.Count; ++i) {
6859 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6861 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6862 var p = best_candidate.Set.Parameters;
6863 arguments = new Arguments (p.Count - 1);
6864 for (int i = 0; i < p.Count - 1; ++i) {
6865 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6872 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6874 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6878 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6880 // getter and setter can be different for base calls
6881 MethodSpec getter, setter;
6882 protected T best_candidate;
6884 protected LocalTemporary temp;
6885 protected bool emitting_compound_assignment;
6886 protected bool has_await_arguments;
6888 protected PropertyOrIndexerExpr (Location l)
6895 protected abstract Arguments Arguments { get; set; }
6897 public MethodSpec Getter {
6906 public MethodSpec Setter {
6917 protected override Expression DoResolve (ResolveContext ec)
6919 if (eclass == ExprClass.Unresolved) {
6920 ResolveConditionalAccessReceiver (ec);
6922 var expr = OverloadResolve (ec, null);
6927 return expr.Resolve (ec);
6929 if (conditional_access_receiver) {
6930 type = LiftMemberType (ec, type);
6931 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6935 if (!ResolveGetter (ec))
6941 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6943 if (ConditionalAccess)
6944 throw new NotSupportedException ("null propagating operator assignment");
6946 if (right_side == EmptyExpression.OutAccess) {
6947 // TODO: best_candidate can be null at this point
6948 INamedBlockVariable variable = null;
6949 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6950 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6951 best_candidate.Name);
6953 right_side.DoResolveLValue (ec, this);
6958 if (eclass == ExprClass.Unresolved) {
6959 var expr = OverloadResolve (ec, right_side);
6964 return expr.ResolveLValue (ec, right_side);
6966 ResolveInstanceExpression (ec, right_side);
6969 if (!ResolveSetter (ec))
6975 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
6977 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6979 call.Emit (ec, method, arguments, loc);
6981 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
6985 // Implements the IAssignMethod interface for assignments
6987 public virtual void Emit (EmitContext ec, bool leave_copy)
6989 var call = new CallEmitter ();
6990 call.ConditionalAccess = ConditionalAccess;
6991 call.InstanceExpression = InstanceExpression;
6992 if (has_await_arguments)
6993 call.HasAwaitArguments = true;
6995 call.DuplicateArguments = emitting_compound_assignment;
6997 if (conditional_access_receiver)
6998 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7000 call.Emit (ec, Getter, Arguments, loc);
7002 if (call.HasAwaitArguments) {
7003 InstanceExpression = call.InstanceExpression;
7004 Arguments = call.EmittedArguments;
7005 has_await_arguments = true;
7009 ec.Emit (OpCodes.Dup);
7010 temp = new LocalTemporary (Type);
7015 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7017 public override void Emit (EmitContext ec)
7022 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7024 has_await_arguments = true;
7029 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7031 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7033 bool ResolveGetter (ResolveContext rc)
7035 if (!best_candidate.HasGet) {
7036 if (InstanceExpression != EmptyExpression.Null) {
7037 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7038 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7039 best_candidate.GetSignatureForError ());
7042 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7043 if (best_candidate.HasDifferentAccessibility) {
7044 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7045 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7046 TypeManager.CSharpSignature (best_candidate));
7048 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7049 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7053 if (best_candidate.HasDifferentAccessibility) {
7054 CheckProtectedMemberAccess (rc, best_candidate.Get);
7057 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7061 bool ResolveSetter (ResolveContext rc)
7063 if (!best_candidate.HasSet) {
7064 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7065 GetSignatureForError ());
7069 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7070 if (best_candidate.HasDifferentAccessibility) {
7071 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7072 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7073 GetSignatureForError ());
7075 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7076 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7080 if (best_candidate.HasDifferentAccessibility)
7081 CheckProtectedMemberAccess (rc, best_candidate.Set);
7083 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7089 /// Fully resolved expression that evaluates to an Event
7091 public class EventExpr : MemberExpr, IAssignMethod
7093 readonly EventSpec spec;
7096 public EventExpr (EventSpec spec, Location loc)
7104 protected override TypeSpec DeclaringType {
7106 return spec.DeclaringType;
7110 public override string Name {
7116 public override bool IsInstance {
7118 return !spec.IsStatic;
7122 public override bool IsStatic {
7124 return spec.IsStatic;
7128 public override string KindName {
7129 get { return "event"; }
7132 public MethodSpec Operator {
7140 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7143 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7145 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7146 if (spec.BackingField != null &&
7147 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7149 spec.MemberDefinition.SetIsUsed ();
7151 if (!ec.IsObsolete) {
7152 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7154 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7157 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7158 Error_AssignmentEventOnly (ec);
7160 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7162 InstanceExpression = null;
7164 return ml.ResolveMemberAccess (ec, left, original);
7168 return base.ResolveMemberAccess (ec, left, original);
7171 public override Expression CreateExpressionTree (ResolveContext ec)
7173 throw new NotSupportedException ("ET");
7176 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7178 if (right_side == EmptyExpression.EventAddition) {
7179 op = spec.AccessorAdd;
7180 } else if (right_side == EmptyExpression.EventSubtraction) {
7181 op = spec.AccessorRemove;
7185 Error_AssignmentEventOnly (ec);
7189 op = CandidateToBaseOverride (ec, op);
7193 protected override Expression DoResolve (ResolveContext ec)
7195 eclass = ExprClass.EventAccess;
7196 type = spec.MemberType;
7198 ResolveInstanceExpression (ec, null);
7200 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7201 Error_AssignmentEventOnly (ec);
7204 DoBestMemberChecks (ec, spec);
7208 public override void Emit (EmitContext ec)
7210 throw new NotSupportedException ();
7211 //Error_CannotAssign ();
7214 #region IAssignMethod Members
7216 public void Emit (EmitContext ec, bool leave_copy)
7218 throw new NotImplementedException ();
7221 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7223 if (leave_copy || !isCompound)
7224 throw new NotImplementedException ("EventExpr::EmitAssign");
7226 Arguments args = new Arguments (1);
7227 args.Add (new Argument (source));
7229 // TODO: Wrong, needs receiver
7230 // if (NullShortCircuit) {
7231 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7234 var call = new CallEmitter ();
7235 call.InstanceExpression = InstanceExpression;
7236 call.ConditionalAccess = ConditionalAccess;
7237 call.EmitStatement (ec, op, args, loc);
7239 // if (NullShortCircuit)
7240 // ec.CloseConditionalAccess (null);
7245 void Error_AssignmentEventOnly (ResolveContext ec)
7247 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7248 ec.Report.Error (79, loc,
7249 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7250 GetSignatureForError ());
7252 ec.Report.Error (70, loc,
7253 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7254 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7258 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7260 name = name.Substring (0, name.LastIndexOf ('.'));
7261 base.Error_CannotCallAbstractBase (rc, name);
7264 public override string GetSignatureForError ()
7266 return TypeManager.CSharpSignature (spec);
7269 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7271 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7275 public class TemporaryVariableReference : VariableReference
7277 public class Declarator : Statement
7279 TemporaryVariableReference variable;
7281 public Declarator (TemporaryVariableReference variable)
7283 this.variable = variable;
7287 protected override void DoEmit (EmitContext ec)
7289 variable.li.CreateBuilder (ec);
7292 public override void Emit (EmitContext ec)
7294 // Don't create sequence point
7298 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7303 protected override void CloneTo (CloneContext clonectx, Statement target)
7311 public TemporaryVariableReference (LocalVariable li, Location loc)
7314 this.type = li.Type;
7318 public override bool IsLockedByStatement {
7326 public LocalVariable LocalInfo {
7332 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7334 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7335 return new TemporaryVariableReference (li, loc);
7338 protected override Expression DoResolve (ResolveContext ec)
7340 eclass = ExprClass.Variable;
7343 // Don't capture temporary variables except when using
7344 // state machine redirection and block yields
7346 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7347 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7348 ec.IsVariableCapturingRequired) {
7349 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7350 storey.CaptureLocalVariable (ec, li);
7356 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7358 return Resolve (ec);
7361 public override void Emit (EmitContext ec)
7363 li.CreateBuilder (ec);
7368 public void EmitAssign (EmitContext ec, Expression source)
7370 li.CreateBuilder (ec);
7372 EmitAssign (ec, source, false, false);
7375 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7377 return li.HoistedVariant;
7380 public override bool IsFixed {
7381 get { return true; }
7384 public override bool IsRef {
7385 get { return false; }
7388 public override string Name {
7389 get { throw new NotImplementedException (); }
7392 public override void SetHasAddressTaken ()
7394 throw new NotImplementedException ();
7397 protected override ILocalVariable Variable {
7401 public override VariableInfo VariableInfo {
7402 get { return null; }
7407 /// Handles `var' contextual keyword; var becomes a keyword only
7408 /// if no type called var exists in a variable scope
7410 class VarExpr : SimpleName
7412 public VarExpr (Location loc)
7417 public bool InferType (ResolveContext ec, Expression right_side)
7420 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7422 type = right_side.Type;
7423 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7424 ec.Report.Error (815, loc,
7425 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7426 type.GetSignatureForError ());
7430 eclass = ExprClass.Variable;
7434 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7436 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7437 base.Error_TypeOrNamespaceNotFound (ec);
7439 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");