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);
3212 public override string ToString ()
3214 return Namespace.Name;
3219 /// This class denotes an expression which evaluates to a member
3220 /// of a struct or a class.
3222 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3224 protected bool conditional_access_receiver;
3227 // An instance expression associated with this member, if it's a
3228 // non-static member
3230 public Expression InstanceExpression;
3233 /// The name of this member.
3235 public abstract string Name {
3240 // When base.member is used
3242 public bool IsBase {
3243 get { return InstanceExpression is BaseThis; }
3247 /// Whether this is an instance member.
3249 public abstract bool IsInstance {
3254 /// Whether this is a static member.
3256 public abstract bool IsStatic {
3260 public abstract string KindName {
3264 public bool ConditionalAccess { get; set; }
3266 protected abstract TypeSpec DeclaringType {
3270 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3272 return InstanceExpression.Type;
3277 // Converts best base candidate for virtual method starting from QueriedBaseType
3279 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3282 // Only when base.member is used and method is virtual
3288 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3289 // means for base.member access we have to find the closest match after we found best candidate
3291 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3293 // The method could already be what we are looking for
3295 TypeSpec[] targs = null;
3296 if (method.DeclaringType != InstanceExpression.Type) {
3298 // Candidate can have inflated MVAR parameters and we need to find
3299 // base match for original definition not inflated parameter types
3301 var parameters = method.Parameters;
3302 if (method.Arity > 0) {
3303 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3304 var inflated = method.DeclaringType as InflatedTypeSpec;
3305 if (inflated != null) {
3306 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3310 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3311 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3312 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3313 if (base_override.IsGeneric)
3314 targs = method.TypeArguments;
3316 method = base_override;
3321 // When base access is used inside anonymous method/iterator/etc we need to
3322 // get back to the context of original type. We do it by emiting proxy
3323 // method in original class and rewriting base call to this compiler
3324 // generated method call which does the actual base invocation. This may
3325 // introduce redundant storey but with `this' only but it's tricky to avoid
3326 // at this stage as we don't know what expressions follow base
3328 if (rc.CurrentAnonymousMethod != null) {
3329 if (targs == null && method.IsGeneric) {
3330 targs = method.TypeArguments;
3331 method = method.GetGenericMethodDefinition ();
3334 if (method.Parameters.HasArglist)
3335 throw new NotImplementedException ("__arglist base call proxy");
3337 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3339 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3340 // get/set member expressions second call would fail to proxy because left expression
3341 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3342 // FIXME: The async check is another hack but will probably fail with mutators
3343 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3344 InstanceExpression = new This (loc).Resolve (rc);
3348 method = method.MakeGenericMethod (rc, targs);
3352 // Only base will allow this invocation to happen.
3354 if (method.IsAbstract) {
3355 rc.Report.SymbolRelatedToPreviousError (method);
3356 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3362 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3364 if (InstanceExpression == null)
3367 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3368 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3369 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3374 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3376 if (InstanceExpression == null)
3379 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3382 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3384 var ct = rc.CurrentType;
3385 if (ct == qualifier)
3388 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3391 qualifier = qualifier.GetDefinition ();
3392 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3399 public override bool ContainsEmitWithAwait ()
3401 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3404 public override bool HasConditionalAccess ()
3406 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3409 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3412 type = type.GetDefinition ();
3414 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3417 type = type.DeclaringType;
3418 } while (type != null);
3423 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3425 if (InstanceExpression != null) {
3426 InstanceExpression = InstanceExpression.Resolve (rc);
3427 CheckProtectedMemberAccess (rc, member);
3430 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3431 UnsafeError (rc, loc);
3434 var dep = member.GetMissingDependencies ();
3436 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3439 if (!rc.IsObsolete) {
3440 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3442 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3445 if (!(member is FieldSpec))
3446 member.MemberDefinition.SetIsUsed ();
3449 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3451 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3454 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3456 rc.Report.SymbolRelatedToPreviousError (member);
3457 rc.Report.Error (1540, loc,
3458 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3459 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3462 public override void FlowAnalysis (FlowAnalysisContext fc)
3464 if (InstanceExpression != null) {
3465 InstanceExpression.FlowAnalysis (fc);
3467 if (ConditionalAccess) {
3468 fc.BranchConditionalAccessDefiniteAssignment ();
3473 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3475 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3476 if (HasConditionalAccess ()) {
3477 conditional_access_receiver = true;
3478 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3483 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3485 if (!ResolveInstanceExpressionCore (rc, rhs))
3489 // Check intermediate value modification which won't have any effect
3491 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3492 var fexpr = InstanceExpression as FieldExpr;
3493 if (fexpr != null) {
3494 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3497 if (fexpr.IsStatic) {
3498 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3499 fexpr.GetSignatureForError ());
3501 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3502 fexpr.GetSignatureForError ());
3508 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3509 if (rc.CurrentInitializerVariable != null) {
3510 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3511 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3513 rc.Report.Error (1612, loc,
3514 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3515 InstanceExpression.GetSignatureForError ());
3521 var lvr = InstanceExpression as LocalVariableReference;
3524 if (!lvr.local_info.IsReadonly)
3527 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3528 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3535 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3538 if (InstanceExpression != null) {
3539 if (InstanceExpression is TypeExpr) {
3540 var t = InstanceExpression.Type;
3542 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3543 if (oa != null && !rc.IsObsolete) {
3544 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3547 t = t.DeclaringType;
3548 } while (t != null);
3550 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3551 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3552 rc.Report.Error (176, loc,
3553 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3554 GetSignatureForError ());
3558 InstanceExpression = null;
3564 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3565 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3566 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3567 rc.Report.Error (236, loc,
3568 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3569 GetSignatureForError ());
3571 var fe = this as FieldExpr;
3572 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3573 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3574 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3576 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3580 rc.Report.Error (120, loc,
3581 "An object reference is required to access non-static member `{0}'",
3582 GetSignatureForError ());
3586 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3590 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3591 rc.Report.Error (38, loc,
3592 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3593 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3596 InstanceExpression = new This (loc).Resolve (rc);
3600 var me = InstanceExpression as MemberExpr;
3602 me.ResolveInstanceExpressionCore (rc, rhs);
3604 var fe = me as FieldExpr;
3605 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3606 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3607 rc.Report.Warning (1690, 1, loc,
3608 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3609 me.GetSignatureForError ());
3616 // Additional checks for l-value member access
3619 if (InstanceExpression is UnboxCast) {
3620 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3627 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3629 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3630 ec.Report.Warning (1720, 1, left.Location,
3631 "Expression will always cause a `{0}'", "System.NullReferenceException");
3634 InstanceExpression = left;
3638 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3640 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3641 inst.Emit (ec, ConditionalAccess);
3643 if (prepare_for_load)
3644 ec.Emit (OpCodes.Dup);
3647 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3650 public class ExtensionMethodCandidates
3652 readonly NamespaceContainer container;
3653 readonly IList<MethodSpec> methods;
3655 readonly IMemberContext context;
3657 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3659 this.context = context;
3660 this.methods = methods;
3661 this.container = nsContainer;
3662 this.index = lookupIndex;
3665 public NamespaceContainer Container {
3671 public IMemberContext Context {
3677 public int LookupIndex {
3683 public IList<MethodSpec> Methods {
3691 // Represents a group of extension method candidates for whole namespace
3693 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3695 ExtensionMethodCandidates candidates;
3696 public Expression ExtensionExpression;
3698 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3699 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3701 this.candidates = candidates;
3702 this.ExtensionExpression = extensionExpr;
3705 public override bool IsStatic {
3706 get { return true; }
3709 public override void FlowAnalysis (FlowAnalysisContext fc)
3711 if (ConditionalAccess) {
3712 fc.BranchConditionalAccessDefiniteAssignment ();
3717 // For extension methodgroup we are not looking for base members but parent
3718 // namespace extension methods
3720 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3722 // TODO: candidates are null only when doing error reporting, that's
3723 // incorrect. We have to discover same extension methods in error mode
3724 if (candidates == null)
3727 int arity = type_arguments == null ? 0 : type_arguments.Count;
3729 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3730 if (candidates == null)
3733 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3736 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3738 // We are already here
3742 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3744 if (arguments == null)
3745 arguments = new Arguments (1);
3747 ExtensionExpression = ExtensionExpression.Resolve (ec);
3748 if (ExtensionExpression == null)
3751 var cand = candidates;
3752 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3753 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3754 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3756 // Restore candidates in case we are running in probing mode
3759 // Store resolved argument and restore original arguments
3761 // Clean-up modified arguments for error reporting
3762 arguments.RemoveAt (0);
3766 var me = ExtensionExpression as MemberExpr;
3768 me.ResolveInstanceExpression (ec, null);
3769 var fe = me as FieldExpr;
3771 fe.Spec.MemberDefinition.SetIsUsed ();
3774 InstanceExpression = null;
3778 #region IErrorHandler Members
3780 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3785 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3787 rc.Report.SymbolRelatedToPreviousError (best);
3788 rc.Report.Error (1928, loc,
3789 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3790 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3793 rc.Report.Error (1929, loc,
3794 "Extension method instance type `{0}' cannot be converted to `{1}'",
3795 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3801 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3806 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3815 /// MethodGroupExpr represents a group of method candidates which
3816 /// can be resolved to the best method overload
3818 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3820 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3822 protected IList<MemberSpec> Methods;
3823 MethodSpec best_candidate;
3824 TypeSpec best_candidate_return;
3825 protected TypeArguments type_arguments;
3827 SimpleName simple_name;
3828 protected TypeSpec queried_type;
3830 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3834 this.type = InternalType.MethodGroup;
3836 eclass = ExprClass.MethodGroup;
3837 queried_type = type;
3840 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3841 : this (new MemberSpec[] { m }, type, loc)
3847 public MethodSpec BestCandidate {
3849 return best_candidate;
3853 public TypeSpec BestCandidateReturnType {
3855 return best_candidate_return;
3859 public IList<MemberSpec> Candidates {
3865 protected override TypeSpec DeclaringType {
3867 return queried_type;
3871 public bool IsConditionallyExcluded {
3873 return Methods == Excluded;
3877 public override bool IsInstance {
3879 if (best_candidate != null)
3880 return !best_candidate.IsStatic;
3886 public override bool IsSideEffectFree {
3888 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3892 public override bool IsStatic {
3894 if (best_candidate != null)
3895 return best_candidate.IsStatic;
3901 public override string KindName {
3902 get { return "method"; }
3905 public override string Name {
3907 if (best_candidate != null)
3908 return best_candidate.Name;
3911 return Methods.First ().Name;
3918 // When best candidate is already know this factory can be used
3919 // to avoid expensive overload resolution to be called
3921 // NOTE: InstanceExpression has to be set manually
3923 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3925 return new MethodGroupExpr (best, queriedType, loc) {
3926 best_candidate = best,
3927 best_candidate_return = best.ReturnType
3931 public override string GetSignatureForError ()
3933 if (best_candidate != null)
3934 return best_candidate.GetSignatureForError ();
3936 return Methods.First ().GetSignatureForError ();
3939 public override Expression CreateExpressionTree (ResolveContext ec)
3941 if (best_candidate == null) {
3942 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3946 if (IsConditionallyExcluded)
3947 ec.Report.Error (765, loc,
3948 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3950 if (ConditionalAccess)
3951 Error_NullShortCircuitInsideExpressionTree (ec);
3953 return new TypeOfMethod (best_candidate, loc);
3956 protected override Expression DoResolve (ResolveContext ec)
3958 this.eclass = ExprClass.MethodGroup;
3960 if (InstanceExpression != null) {
3961 InstanceExpression = InstanceExpression.Resolve (ec);
3962 if (InstanceExpression == null)
3969 public override void Emit (EmitContext ec)
3971 throw new NotSupportedException ();
3974 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3976 var call = new CallEmitter ();
3977 call.InstanceExpression = InstanceExpression;
3978 call.ConditionalAccess = ConditionalAccess;
3981 call.EmitStatement (ec, best_candidate, arguments, loc);
3983 call.Emit (ec, best_candidate, arguments, loc);
3986 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
3988 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
3989 Statement = statement
3992 EmitCall (ec, arguments, statement);
3994 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
3997 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3999 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4000 Name, target.GetSignatureForError ());
4003 public static bool IsExtensionMethodArgument (Expression expr)
4006 // LAMESPEC: No details about which expressions are not allowed
4008 return !(expr is TypeExpr) && !(expr is BaseThis);
4012 /// Find the Applicable Function Members (7.4.2.1)
4014 /// me: Method Group expression with the members to select.
4015 /// it might contain constructors or methods (or anything
4016 /// that maps to a method).
4018 /// Arguments: ArrayList containing resolved Argument objects.
4020 /// loc: The location if we want an error to be reported, or a Null
4021 /// location for "probing" purposes.
4023 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4024 /// that is the best match of me on Arguments.
4027 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4029 // TODO: causes issues with probing mode, remove explicit Kind check
4030 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4033 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4034 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4035 r.BaseMembersProvider = this;
4036 r.InstanceQualifier = this;
4039 if (cerrors != null)
4040 r.CustomErrors = cerrors;
4042 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4043 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4044 if (best_candidate == null) {
4045 if (!r.BestCandidateIsDynamic)
4048 if (simple_name != null && ec.IsStatic)
4049 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4054 // Overload resolver had to create a new method group, all checks bellow have already been executed
4055 if (r.BestCandidateNewMethodGroup != null)
4056 return r.BestCandidateNewMethodGroup;
4058 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4059 if (InstanceExpression != null) {
4060 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4061 InstanceExpression = null;
4063 if (simple_name != null && best_candidate.IsStatic) {
4064 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4067 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4071 ResolveInstanceExpression (ec, null);
4074 var base_override = CandidateToBaseOverride (ec, best_candidate);
4075 if (base_override == best_candidate) {
4076 best_candidate_return = r.BestCandidateReturnType;
4078 best_candidate = base_override;
4079 best_candidate_return = best_candidate.ReturnType;
4082 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4083 ConstraintChecker cc = new ConstraintChecker (ec);
4084 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4088 // Additional check for possible imported base override method which
4089 // could not be done during IsOverrideMethodBaseTypeAccessible
4091 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4092 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4093 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4094 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4097 // Speed up the check by not doing it on disallowed targets
4098 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4104 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4106 var fe = left as FieldExpr;
4109 // Using method-group on struct fields makes the struct assigned. I am not sure
4110 // why but that's what .net does
4112 fe.Spec.MemberDefinition.SetIsAssigned ();
4115 simple_name = original;
4116 return base.ResolveMemberAccess (ec, left, original);
4119 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4121 type_arguments = ta;
4124 #region IBaseMembersProvider Members
4126 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4128 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4131 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4133 if (queried_type == member.DeclaringType)
4136 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4137 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4141 // Extension methods lookup after ordinary methods candidates failed to apply
4143 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4145 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4148 if (!IsExtensionMethodArgument (InstanceExpression))
4151 int arity = type_arguments == null ? 0 : type_arguments.Count;
4152 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4153 if (methods == null)
4156 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4157 emg.SetTypeArguments (rc, type_arguments);
4164 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4166 public ConstructorInstanceQualifier (TypeSpec type)
4169 InstanceType = type;
4172 public TypeSpec InstanceType { get; private set; }
4174 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4176 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4180 public struct OverloadResolver
4183 public enum Restrictions
4187 ProbingOnly = 1 << 1,
4188 CovariantDelegate = 1 << 2,
4189 NoBaseMembers = 1 << 3,
4190 BaseMembersIncluded = 1 << 4,
4191 GetEnumeratorLookup = 1 << 5
4194 public interface IBaseMembersProvider
4196 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4197 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4198 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4201 public interface IErrorHandler
4203 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4204 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4205 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4206 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4209 public interface IInstanceQualifier
4211 TypeSpec InstanceType { get; }
4212 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4215 sealed class NoBaseMembers : IBaseMembersProvider
4217 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4219 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4224 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4229 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4235 struct AmbiguousCandidate
4237 public readonly MemberSpec Member;
4238 public readonly bool Expanded;
4239 public readonly AParametersCollection Parameters;
4241 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4244 Parameters = parameters;
4245 Expanded = expanded;
4250 IList<MemberSpec> members;
4251 TypeArguments type_arguments;
4252 IBaseMembersProvider base_provider;
4253 IErrorHandler custom_errors;
4254 IInstanceQualifier instance_qualifier;
4255 Restrictions restrictions;
4256 MethodGroupExpr best_candidate_extension_group;
4257 TypeSpec best_candidate_return_type;
4259 SessionReportPrinter lambda_conv_msgs;
4261 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4262 : this (members, null, restrictions, loc)
4266 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4269 if (members == null || members.Count == 0)
4270 throw new ArgumentException ("empty members set");
4272 this.members = members;
4274 type_arguments = targs;
4275 this.restrictions = restrictions;
4276 if (IsDelegateInvoke)
4277 this.restrictions |= Restrictions.NoBaseMembers;
4279 base_provider = NoBaseMembers.Instance;
4284 public IBaseMembersProvider BaseMembersProvider {
4286 return base_provider;
4289 base_provider = value;
4293 public bool BestCandidateIsDynamic { get; set; }
4296 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4298 public MethodGroupExpr BestCandidateNewMethodGroup {
4300 return best_candidate_extension_group;
4305 // Return type can be different between best candidate and closest override
4307 public TypeSpec BestCandidateReturnType {
4309 return best_candidate_return_type;
4313 public IErrorHandler CustomErrors {
4315 return custom_errors;
4318 custom_errors = value;
4322 TypeSpec DelegateType {
4324 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4325 throw new InternalErrorException ("Not running in delegate mode", loc);
4327 return members [0].DeclaringType;
4331 public IInstanceQualifier InstanceQualifier {
4333 return instance_qualifier;
4336 instance_qualifier = value;
4340 bool IsProbingOnly {
4342 return (restrictions & Restrictions.ProbingOnly) != 0;
4346 bool IsDelegateInvoke {
4348 return (restrictions & Restrictions.DelegateInvoke) != 0;
4355 // 7.4.3.3 Better conversion from expression
4356 // Returns : 1 if a->p is better,
4357 // 2 if a->q is better,
4358 // 0 if neither is better
4360 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4362 TypeSpec argument_type = a.Type;
4365 // If argument is an anonymous function
4367 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4369 // p and q are delegate types or expression tree types
4371 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4372 if (q.MemberDefinition != p.MemberDefinition) {
4377 // Uwrap delegate from Expression<T>
4379 q = TypeManager.GetTypeArguments (q)[0];
4380 p = TypeManager.GetTypeArguments (p)[0];
4383 var p_m = Delegate.GetInvokeMethod (p);
4384 var q_m = Delegate.GetInvokeMethod (q);
4387 // With identical parameter lists
4389 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4397 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4399 if (p.Kind == MemberKind.Void) {
4400 return q.Kind != MemberKind.Void ? 2 : 0;
4404 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4406 if (q.Kind == MemberKind.Void) {
4407 return p.Kind != MemberKind.Void ? 1: 0;
4410 var am = (AnonymousMethodExpression) a.Expr;
4413 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4414 // better conversion is performed between underlying types Y1 and Y2
4416 if (p.IsGenericTask || q.IsGenericTask) {
4417 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4418 q = q.TypeArguments[0];
4419 p = p.TypeArguments[0];
4425 // An inferred return type X exists for E in the context of that parameter list, and
4426 // the conversion from X to Y1 is better than the conversion from X to Y2
4428 argument_type = am.InferReturnType (ec, null, orig_q);
4429 if (argument_type == null) {
4430 // TODO: Can this be hit?
4434 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4435 argument_type = ec.BuiltinTypes.Object;
4439 if (argument_type == p)
4442 if (argument_type == q)
4446 // The parameters are identicial and return type is not void, use better type conversion
4447 // on return type to determine better one
4449 return BetterTypeConversion (ec, p, q);
4453 // 7.4.3.4 Better conversion from type
4455 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4457 if (p == null || q == null)
4458 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4460 switch (p.BuiltinType) {
4461 case BuiltinTypeSpec.Type.Int:
4462 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4465 case BuiltinTypeSpec.Type.Long:
4466 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4469 case BuiltinTypeSpec.Type.SByte:
4470 switch (q.BuiltinType) {
4471 case BuiltinTypeSpec.Type.Byte:
4472 case BuiltinTypeSpec.Type.UShort:
4473 case BuiltinTypeSpec.Type.UInt:
4474 case BuiltinTypeSpec.Type.ULong:
4478 case BuiltinTypeSpec.Type.Short:
4479 switch (q.BuiltinType) {
4480 case BuiltinTypeSpec.Type.UShort:
4481 case BuiltinTypeSpec.Type.UInt:
4482 case BuiltinTypeSpec.Type.ULong:
4486 case BuiltinTypeSpec.Type.Dynamic:
4487 // Dynamic is never better
4491 switch (q.BuiltinType) {
4492 case BuiltinTypeSpec.Type.Int:
4493 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4496 case BuiltinTypeSpec.Type.Long:
4497 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4500 case BuiltinTypeSpec.Type.SByte:
4501 switch (p.BuiltinType) {
4502 case BuiltinTypeSpec.Type.Byte:
4503 case BuiltinTypeSpec.Type.UShort:
4504 case BuiltinTypeSpec.Type.UInt:
4505 case BuiltinTypeSpec.Type.ULong:
4509 case BuiltinTypeSpec.Type.Short:
4510 switch (p.BuiltinType) {
4511 case BuiltinTypeSpec.Type.UShort:
4512 case BuiltinTypeSpec.Type.UInt:
4513 case BuiltinTypeSpec.Type.ULong:
4517 case BuiltinTypeSpec.Type.Dynamic:
4518 // Dynamic is never better
4522 // FIXME: handle lifted operators
4524 // TODO: this is expensive
4525 Expression p_tmp = new EmptyExpression (p);
4526 Expression q_tmp = new EmptyExpression (q);
4528 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4529 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4531 if (p_to_q && !q_to_p)
4534 if (q_to_p && !p_to_q)
4541 /// Determines "Better function" between candidate
4542 /// and the current best match
4545 /// Returns a boolean indicating :
4546 /// false if candidate ain't better
4547 /// true if candidate is better than the current best match
4549 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4550 MemberSpec best, AParametersCollection bparam, bool best_params)
4552 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4553 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4555 bool better_at_least_one = false;
4556 bool are_equivalent = true;
4557 int args_count = args == null ? 0 : args.Count;
4561 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4564 // Default arguments are ignored for better decision
4565 if (a.IsDefaultArgument)
4569 // When comparing named argument the parameter type index has to be looked up
4570 // in original parameter set (override version for virtual members)
4572 NamedArgument na = a as NamedArgument;
4574 int idx = cparam.GetParameterIndexByName (na.Name);
4575 ct = candidate_pd.Types[idx];
4576 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4577 ct = TypeManager.GetElementType (ct);
4579 idx = bparam.GetParameterIndexByName (na.Name);
4580 bt = best_pd.Types[idx];
4581 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4582 bt = TypeManager.GetElementType (bt);
4584 ct = candidate_pd.Types[c_idx];
4585 bt = best_pd.Types[b_idx];
4587 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4588 ct = TypeManager.GetElementType (ct);
4592 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4593 bt = TypeManager.GetElementType (bt);
4598 if (TypeSpecComparer.IsEqual (ct, bt))
4601 are_equivalent = false;
4602 int result = BetterExpressionConversion (ec, a, ct, bt);
4604 // for each argument, the conversion to 'ct' should be no worse than
4605 // the conversion to 'bt'.
4609 // for at least one argument, the conversion to 'ct' should be better than
4610 // the conversion to 'bt'.
4612 better_at_least_one = true;
4615 if (better_at_least_one)
4619 // Tie-breaking rules are applied only for equivalent parameter types
4621 if (!are_equivalent)
4625 // If candidate is applicable in its normal form and best has a params array and is applicable
4626 // only in its expanded form, then candidate is better
4628 if (candidate_params != best_params)
4629 return !candidate_params;
4632 // We have not reached end of parameters list due to params or used default parameters
4634 while (j < candidate_pd.Count && j < best_pd.Count) {
4635 var cand_param = candidate_pd.FixedParameters [j];
4636 var best_param = best_pd.FixedParameters [j];
4638 if (candidate_pd.Count == best_pd.Count) {
4642 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4643 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4645 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4646 return cand_param.HasDefaultValue;
4648 if (cand_param.HasDefaultValue) {
4654 // Neither is better when not all arguments are provided
4656 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4657 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4658 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4660 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4667 if (candidate_pd.Count != best_pd.Count)
4668 return candidate_pd.Count < best_pd.Count;
4671 // One is a non-generic method and second is a generic method, then non-generic is better
4673 if (best.IsGeneric != candidate.IsGeneric)
4674 return best.IsGeneric;
4677 // Both methods have the same number of parameters, and the parameters have equal types
4678 // Pick the "more specific" signature using rules over original (non-inflated) types
4680 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4681 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4683 bool specific_at_least_once = false;
4684 for (j = 0; j < args_count; ++j) {
4685 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4687 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4688 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4690 ct = candidate_def_pd.Types[j];
4691 bt = best_def_pd.Types[j];
4696 TypeSpec specific = MoreSpecific (ct, bt);
4700 specific_at_least_once = true;
4703 if (specific_at_least_once)
4709 static bool CheckInflatedArguments (MethodSpec ms)
4711 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4714 // Setup constraint checker for probing only
4715 ConstraintChecker cc = new ConstraintChecker (null);
4717 var mp = ms.Parameters.Types;
4718 for (int i = 0; i < mp.Length; ++i) {
4719 var type = mp[i] as InflatedTypeSpec;
4723 var targs = type.TypeArguments;
4724 if (targs.Length == 0)
4727 // TODO: Checking inflated MVAR arguments should be enough
4728 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4735 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4737 rc.Report.Error (1729, loc,
4738 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4739 type.GetSignatureForError (), argCount.ToString ());
4743 // Determines if the candidate method is applicable to the given set of arguments
4744 // There could be two different set of parameters for same candidate where one
4745 // is the closest override for default values and named arguments checks and second
4746 // one being the virtual base for the parameter types and modifiers.
4748 // A return value rates candidate method compatibility,
4750 // 0 = the best, int.MaxValue = the worst
4752 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)
4755 // Each step has allocated 10 values, it can overflow for
4756 // more than 10 arguments but that's ok as it's used for
4757 // better error reporting only
4759 const int ArgumentCountMismatch = 1000000000;
4760 const int NamedArgumentsMismatch = 100000000;
4761 const int DefaultArgumentMismatch = 10000000;
4762 const int UnexpectedTypeArguments = 1000000;
4763 const int TypeArgumentsMismatch = 100000;
4764 const int InflatedTypesMismatch = 10000;
4766 // Parameters of most-derived type used mainly for named and optional parameters
4767 var pd = pm.Parameters;
4769 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4770 // params modifier instead of most-derived type
4771 var cpd = ((IParametersMember) candidate).Parameters;
4772 int param_count = pd.Count;
4773 int optional_count = 0;
4775 Arguments orig_args = arguments;
4777 if (arg_count != param_count) {
4779 // No arguments expansion when doing exact match for delegates
4781 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4782 for (int i = 0; i < pd.Count; ++i) {
4783 if (pd.FixedParameters[i].HasDefaultValue) {
4784 optional_count = pd.Count - i;
4790 if (optional_count != 0) {
4791 // Readjust expected number when params used
4792 if (cpd.HasParams) {
4794 if (arg_count < param_count)
4796 } else if (arg_count > param_count) {
4797 int args_gap = System.Math.Abs (arg_count - param_count);
4798 return ArgumentCountMismatch + args_gap;
4799 } else if (arg_count < param_count - optional_count) {
4800 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4801 return ArgumentCountMismatch + args_gap;
4803 } else if (arg_count != param_count) {
4804 int args_gap = System.Math.Abs (arg_count - param_count);
4806 return ArgumentCountMismatch + args_gap;
4807 if (arg_count < param_count - 1)
4808 return ArgumentCountMismatch + args_gap;
4811 // Resize to fit optional arguments
4812 if (optional_count != 0) {
4813 if (arguments == null) {
4814 arguments = new Arguments (optional_count);
4816 // Have to create a new container, so the next run can do same
4817 var resized = new Arguments (param_count);
4818 resized.AddRange (arguments);
4819 arguments = resized;
4822 for (int i = arg_count; i < param_count; ++i)
4823 arguments.Add (null);
4827 if (arg_count > 0) {
4829 // Shuffle named arguments to the right positions if there are any
4831 if (arguments[arg_count - 1] is NamedArgument) {
4832 arg_count = arguments.Count;
4834 for (int i = 0; i < arg_count; ++i) {
4835 bool arg_moved = false;
4837 NamedArgument na = arguments[i] as NamedArgument;
4841 int index = pd.GetParameterIndexByName (na.Name);
4843 // Named parameter not found
4845 return NamedArgumentsMismatch - i;
4847 // already reordered
4852 if (index >= param_count) {
4853 // When using parameters which should not be available to the user
4854 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4857 arguments.Add (null);
4861 if (index == arg_count)
4862 return NamedArgumentsMismatch - i - 1;
4864 temp = arguments [index];
4866 // The slot has been taken by positional argument
4867 if (temp != null && !(temp is NamedArgument))
4872 arguments = arguments.MarkOrderedArgument (na);
4876 if (arguments == orig_args) {
4877 arguments = new Arguments (orig_args.Count);
4878 arguments.AddRange (orig_args);
4881 arguments[index] = arguments[i];
4882 arguments[i] = temp;
4889 arg_count = arguments.Count;
4891 } else if (arguments != null) {
4892 arg_count = arguments.Count;
4896 // Don't do any expensive checks when the candidate cannot succeed
4898 if (arg_count != param_count && !cpd.HasParams)
4899 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4901 var dep = candidate.GetMissingDependencies ();
4903 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4908 // 1. Handle generic method using type arguments when specified or type inference
4911 var ms = candidate as MethodSpec;
4912 if (ms != null && ms.IsGeneric) {
4913 if (type_arguments != null) {
4914 var g_args_count = ms.Arity;
4915 if (g_args_count != type_arguments.Count)
4916 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4918 if (type_arguments.Arguments != null)
4919 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4922 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4923 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4924 // candidate was found use the set to report more details about what was wrong with lambda body.
4925 // The general idea is to distinguish between code errors and errors caused by
4926 // trial-and-error type inference
4928 if (lambda_conv_msgs == null) {
4929 for (int i = 0; i < arg_count; i++) {
4930 Argument a = arguments[i];
4934 var am = a.Expr as AnonymousMethodExpression;
4936 if (lambda_conv_msgs == null)
4937 lambda_conv_msgs = new SessionReportPrinter ();
4939 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4944 var ti = new TypeInference (arguments);
4945 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4948 return TypeArgumentsMismatch - ti.InferenceScore;
4951 // Clear any error messages when the result was success
4953 if (lambda_conv_msgs != null)
4954 lambda_conv_msgs.ClearSession ();
4956 if (i_args.Length != 0) {
4958 for (int i = 0; i < i_args.Length; ++i) {
4959 var ta = i_args [i];
4960 if (!ta.IsAccessible (ec))
4961 return TypeArgumentsMismatch - i;
4965 ms = ms.MakeGenericMethod (ec, i_args);
4970 // Type arguments constraints have to match for the method to be applicable
4972 if (!CheckInflatedArguments (ms)) {
4974 return InflatedTypesMismatch;
4978 // We have a generic return type and at same time the method is override which
4979 // means we have to also inflate override return type in case the candidate is
4980 // best candidate and override return type is different to base return type.
4982 // virtual Foo<T, object> with override Foo<T, dynamic>
4984 if (candidate != pm) {
4985 MethodSpec override_ms = (MethodSpec) pm;
4986 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4987 returnType = inflator.Inflate (returnType);
4989 returnType = ms.ReturnType;
4996 if (type_arguments != null)
4997 return UnexpectedTypeArguments;
5003 // 2. Each argument has to be implicitly convertible to method parameter
5005 Parameter.Modifier p_mod = 0;
5008 for (int i = 0; i < arg_count; i++) {
5009 Argument a = arguments[i];
5011 var fp = pd.FixedParameters[i];
5012 if (!fp.HasDefaultValue) {
5013 arguments = orig_args;
5014 return arg_count * 2 + 2;
5018 // Get the default value expression, we can use the same expression
5019 // if the type matches
5021 Expression e = fp.DefaultValue;
5023 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5025 // Restore for possible error reporting
5026 for (int ii = i; ii < arg_count; ++ii)
5027 arguments.RemoveAt (i);
5029 return (arg_count - i) * 2 + 1;
5033 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5035 // LAMESPEC: Attributes can be mixed together with build-in priority
5037 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5038 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5039 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5040 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5041 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5042 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5046 arguments[i] = new Argument (e, Argument.AType.Default);
5050 if (p_mod != Parameter.Modifier.PARAMS) {
5051 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5053 } else if (!params_expanded_form) {
5054 params_expanded_form = true;
5055 pt = ((ElementTypeSpec) pt).Element;
5061 if (!params_expanded_form) {
5062 if (a.IsExtensionType) {
5064 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
5066 // LAMESPEC: or implicit type parameter conversion
5069 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
5070 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
5071 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
5076 score = IsArgumentCompatible (ec, a, p_mod, pt);
5079 dynamicArgument = true;
5084 // It can be applicable in expanded form (when not doing exact match like for delegates)
5086 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5087 if (!params_expanded_form) {
5088 pt = ((ElementTypeSpec) pt).Element;
5092 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5095 params_expanded_form = true;
5096 dynamicArgument = true;
5097 } else if (score == 0 || arg_count > pd.Count) {
5098 params_expanded_form = true;
5103 if (params_expanded_form)
5105 return (arg_count - i) * 2 + score;
5110 // Restore original arguments for dynamic binder to keep the intention of original source code
5112 if (dynamicArgument)
5113 arguments = orig_args;
5118 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5120 if (e is Constant && e.Type == ptype)
5124 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5126 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5127 e = new MemberAccess (new MemberAccess (new MemberAccess (
5128 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5129 } else if (e is Constant) {
5131 // Handles int to int? conversions, DefaultParameterValue check
5133 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5137 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5140 return e.Resolve (ec);
5144 // Tests argument compatibility with the parameter
5145 // The possible return values are
5147 // 1 - modifier mismatch
5148 // 2 - type mismatch
5149 // -1 - dynamic binding required
5151 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5154 // Types have to be identical when ref or out modifer
5155 // is used and argument is not of dynamic type
5157 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5158 var arg_type = argument.Type;
5160 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5162 // Using dynamic for ref/out parameter can still succeed at runtime
5164 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5170 if (arg_type != parameter) {
5171 if (arg_type == InternalType.VarOutType)
5175 // Do full equality check after quick path
5177 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5179 // Using dynamic for ref/out parameter can still succeed at runtime
5181 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5189 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5193 // Use implicit conversion in all modes to return same candidates when the expression
5194 // is used as argument or delegate conversion
5196 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5197 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5204 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5206 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5208 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5211 var ac_p = p as ArrayContainer;
5213 var ac_q = q as ArrayContainer;
5217 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5218 if (specific == ac_p.Element)
5220 if (specific == ac_q.Element)
5222 } else if (p.IsGeneric && q.IsGeneric) {
5223 var pargs = TypeManager.GetTypeArguments (p);
5224 var qargs = TypeManager.GetTypeArguments (q);
5226 bool p_specific_at_least_once = false;
5227 bool q_specific_at_least_once = false;
5229 for (int i = 0; i < pargs.Length; i++) {
5230 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5231 if (specific == pargs[i])
5232 p_specific_at_least_once = true;
5233 if (specific == qargs[i])
5234 q_specific_at_least_once = true;
5237 if (p_specific_at_least_once && !q_specific_at_least_once)
5239 if (!p_specific_at_least_once && q_specific_at_least_once)
5247 // Find the best method from candidate list
5249 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5251 List<AmbiguousCandidate> ambiguous_candidates = null;
5253 MemberSpec best_candidate;
5254 Arguments best_candidate_args = null;
5255 bool best_candidate_params = false;
5256 bool best_candidate_dynamic = false;
5257 int best_candidate_rate;
5258 IParametersMember best_parameter_member = null;
5260 int args_count = args != null ? args.Count : 0;
5262 Arguments candidate_args = args;
5263 bool error_mode = false;
5264 MemberSpec invocable_member = null;
5267 best_candidate = null;
5268 best_candidate_rate = int.MaxValue;
5270 var type_members = members;
5272 for (int i = 0; i < type_members.Count; ++i) {
5273 var member = type_members[i];
5276 // Methods in a base class are not candidates if any method in a derived
5277 // class is applicable
5279 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5283 if (!member.IsAccessible (rc))
5286 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5289 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5290 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5295 IParametersMember pm = member as IParametersMember;
5298 // Will use it later to report ambiguity between best method and invocable member
5300 if (Invocation.IsMemberInvocable (member))
5301 invocable_member = member;
5307 // Overload resolution is looking for base member but using parameter names
5308 // and default values from the closest member. That means to do expensive lookup
5309 // for the closest override for virtual or abstract members
5311 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5312 var override_params = base_provider.GetOverrideMemberParameters (member);
5313 if (override_params != null)
5314 pm = override_params;
5318 // Check if the member candidate is applicable
5320 bool params_expanded_form = false;
5321 bool dynamic_argument = false;
5322 TypeSpec rt = pm.MemberType;
5323 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5325 if (lambda_conv_msgs != null)
5326 lambda_conv_msgs.EndSession ();
5329 // How does it score compare to others
5331 if (candidate_rate < best_candidate_rate) {
5333 // Fatal error (missing dependency), cannot continue
5334 if (candidate_rate < 0)
5337 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5338 // Only parameterless methods are considered
5340 best_candidate_rate = candidate_rate;
5341 best_candidate = member;
5342 best_candidate_args = candidate_args;
5343 best_candidate_params = params_expanded_form;
5344 best_candidate_dynamic = dynamic_argument;
5345 best_parameter_member = pm;
5346 best_candidate_return_type = rt;
5348 } else if (candidate_rate == 0) {
5350 // The member look is done per type for most operations but sometimes
5351 // it's not possible like for binary operators overload because they
5352 // are unioned between 2 sides
5354 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5355 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5360 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5362 // We pack all interface members into top level type which makes the overload resolution
5363 // more complicated for interfaces. We compensate it by removing methods with same
5364 // signature when building the cache hence this path should not really be hit often
5367 // interface IA { void Foo (int arg); }
5368 // interface IB : IA { void Foo (params int[] args); }
5370 // IB::Foo is the best overload when calling IB.Foo (1)
5373 if (ambiguous_candidates != null) {
5374 foreach (var amb_cand in ambiguous_candidates) {
5375 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5384 ambiguous_candidates = null;
5387 // Is the new candidate better
5388 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5392 best_candidate = member;
5393 best_candidate_args = candidate_args;
5394 best_candidate_params = params_expanded_form;
5395 best_candidate_dynamic = dynamic_argument;
5396 best_parameter_member = pm;
5397 best_candidate_return_type = rt;
5399 // It's not better but any other found later could be but we are not sure yet
5400 if (ambiguous_candidates == null)
5401 ambiguous_candidates = new List<AmbiguousCandidate> ();
5403 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5407 // Restore expanded arguments
5408 candidate_args = args;
5410 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5413 // We've found exact match
5415 if (best_candidate_rate == 0)
5419 // Try extension methods lookup when no ordinary method match was found and provider enables it
5422 var emg = base_provider.LookupExtensionMethod (rc);
5424 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5426 best_candidate_extension_group = emg;
5427 return (T) (MemberSpec) emg.BestCandidate;
5432 // Don't run expensive error reporting mode for probing
5439 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5442 lambda_conv_msgs = null;
5447 // No best member match found, report an error
5449 if (best_candidate_rate != 0 || error_mode) {
5450 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5454 if (best_candidate_dynamic) {
5455 if (args[0].IsExtensionType) {
5456 rc.Report.Error (1973, loc,
5457 "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",
5458 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5462 // Check type constraints only when explicit type arguments are used
5464 if (best_candidate.IsGeneric && type_arguments != null) {
5465 MethodSpec bc = best_candidate as MethodSpec;
5466 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5467 ConstraintChecker cc = new ConstraintChecker (rc);
5468 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5472 BestCandidateIsDynamic = true;
5477 // These flags indicates we are running delegate probing conversion. No need to
5478 // do more expensive checks
5480 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5481 return (T) best_candidate;
5483 if (ambiguous_candidates != null) {
5485 // Now check that there are no ambiguities i.e the selected method
5486 // should be better than all the others
5488 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5489 var candidate = ambiguous_candidates [ix];
5491 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5492 var ambiguous = candidate.Member;
5493 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5494 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5495 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5496 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5497 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5500 return (T) best_candidate;
5505 if (invocable_member != null && !IsProbingOnly) {
5506 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5507 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5508 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5509 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5513 // And now check if the arguments are all
5514 // compatible, perform conversions if
5515 // necessary etc. and return if everything is
5518 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5521 if (best_candidate == null)
5525 // Don't run possibly expensive checks in probing mode
5527 if (!IsProbingOnly && !rc.IsInProbingMode) {
5529 // Check ObsoleteAttribute on the best method
5531 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5532 if (oa != null && !rc.IsObsolete)
5533 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5535 best_candidate.MemberDefinition.SetIsUsed ();
5538 args = best_candidate_args;
5539 return (T) best_candidate;
5542 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5544 return ResolveMember<MethodSpec> (rc, ref args);
5547 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5548 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5550 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5553 if (a.Type == InternalType.ErrorType)
5556 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5557 ec.Report.SymbolRelatedToPreviousError (method);
5558 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5559 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5560 TypeManager.CSharpSignature (method));
5563 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5564 TypeManager.CSharpSignature (method));
5565 } else if (IsDelegateInvoke) {
5566 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5567 DelegateType.GetSignatureForError ());
5569 ec.Report.SymbolRelatedToPreviousError (method);
5570 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5571 method.GetSignatureForError ());
5574 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5576 string index = (idx + 1).ToString ();
5577 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5578 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5579 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5580 index, Parameter.GetModifierSignature (a.Modifier));
5582 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5583 index, Parameter.GetModifierSignature (mod));
5585 string p1 = a.GetSignatureForError ();
5586 string p2 = paramType.GetSignatureForError ();
5589 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5590 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5593 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5594 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5595 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5598 ec.Report.Error (1503, a.Expr.Location,
5599 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5604 // We have failed to find exact match so we return error info about the closest match
5606 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5608 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5609 int arg_count = args == null ? 0 : args.Count;
5611 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5612 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5613 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5617 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5622 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5623 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5624 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5628 // For candidates which match on parameters count report more details about incorrect arguments
5631 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5632 // Reject any inaccessible member
5633 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5634 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5635 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5639 var ms = best_candidate as MethodSpec;
5640 if (ms != null && ms.IsGeneric) {
5641 bool constr_ok = true;
5642 if (ms.TypeArguments != null)
5643 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5645 if (ta_count == 0 && ms.TypeArguments == null) {
5646 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5650 rc.Report.Error (411, loc,
5651 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5652 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5659 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5665 // We failed to find any method with correct argument count, report best candidate
5667 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5670 if (best_candidate.Kind == MemberKind.Constructor) {
5671 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5672 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5673 } else if (IsDelegateInvoke) {
5674 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5675 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5676 DelegateType.GetSignatureForError (), arg_count.ToString ());
5678 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5679 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5680 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5681 name, arg_count.ToString ());
5685 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5687 var p = ((IParametersMember)best_candidate).Parameters;
5692 for (int i = p.Count - 1; i != 0; --i) {
5693 var fp = p.FixedParameters [i];
5694 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5704 foreach (var arg in args) {
5705 var na = arg as NamedArgument;
5709 if (na.Name == name) {
5718 return args.Count + 1 == pm.Parameters.Count;
5721 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5723 var pd = pm.Parameters;
5724 var cpd = ((IParametersMember) member).Parameters;
5725 var ptypes = cpd.Types;
5727 Parameter.Modifier p_mod = 0;
5729 int a_idx = 0, a_pos = 0;
5731 ArrayInitializer params_initializers = null;
5732 bool has_unsafe_arg = pm.MemberType.IsPointer;
5733 int arg_count = args == null ? 0 : args.Count;
5735 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5740 if (p_mod != Parameter.Modifier.PARAMS) {
5741 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5743 has_unsafe_arg |= pt.IsPointer;
5745 if (p_mod == Parameter.Modifier.PARAMS) {
5746 if (chose_params_expanded) {
5747 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5748 pt = TypeManager.GetElementType (pt);
5754 // Types have to be identical when ref or out modifer is used
5756 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5757 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5760 var arg_type = a.Type;
5764 if (arg_type == InternalType.VarOutType) {
5766 // Set underlying variable type based on parameter type
5768 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5772 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5776 NamedArgument na = a as NamedArgument;
5778 int name_index = pd.GetParameterIndexByName (na.Name);
5779 if (name_index < 0 || name_index >= pd.Count) {
5780 if (IsDelegateInvoke) {
5781 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5782 ec.Report.Error (1746, na.Location,
5783 "The delegate `{0}' does not contain a parameter named `{1}'",
5784 DelegateType.GetSignatureForError (), na.Name);
5786 ec.Report.SymbolRelatedToPreviousError (member);
5787 ec.Report.Error (1739, na.Location,
5788 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5789 TypeManager.CSharpSignature (member), na.Name);
5791 } else if (args[name_index] != a && args[name_index] != null) {
5792 if (IsDelegateInvoke)
5793 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5795 ec.Report.SymbolRelatedToPreviousError (member);
5797 ec.Report.Error (1744, na.Location,
5798 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5803 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5806 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5807 custom_errors.NoArgumentMatch (ec, member);
5812 if (a.IsExtensionType) {
5813 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5816 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5818 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5821 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5828 // Convert params arguments to an array initializer
5830 if (params_initializers != null) {
5831 // we choose to use 'a.Expr' rather than 'conv' so that
5832 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5833 params_initializers.Add (a.Expr);
5834 args.RemoveAt (a_idx--);
5840 // Update the argument with the implicit conversion
5844 if (a_idx != arg_count) {
5846 // Convert all var out argument to error type for less confusing error reporting
5847 // when no matching overload is found
5849 for (; a_idx < arg_count; a_idx++) {
5850 var arg = args [a_idx];
5854 if (arg.Type == InternalType.VarOutType) {
5855 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5859 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5864 // Fill not provided arguments required by params modifier
5866 if (params_initializers == null && arg_count + 1 == pd.Count) {
5868 args = new Arguments (1);
5870 pt = ptypes[pd.Count - 1];
5871 pt = TypeManager.GetElementType (pt);
5872 has_unsafe_arg |= pt.IsPointer;
5873 params_initializers = new ArrayInitializer (0, loc);
5877 // Append an array argument with all params arguments
5879 if (params_initializers != null) {
5880 args.Add (new Argument (
5881 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5885 if (has_unsafe_arg && !ec.IsUnsafe) {
5886 Expression.UnsafeError (ec, loc);
5890 // We could infer inaccesible type arguments
5892 if (type_arguments == null && member.IsGeneric) {
5893 var ms = (MethodSpec) member;
5894 foreach (var ta in ms.TypeArguments) {
5895 if (!ta.IsAccessible (ec)) {
5896 ec.Report.SymbolRelatedToPreviousError (ta);
5897 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5907 public class ConstantExpr : MemberExpr
5909 readonly ConstSpec constant;
5911 public ConstantExpr (ConstSpec constant, Location loc)
5913 this.constant = constant;
5917 public override string Name {
5918 get { throw new NotImplementedException (); }
5921 public override string KindName {
5922 get { return "constant"; }
5925 public override bool IsInstance {
5926 get { return !IsStatic; }
5929 public override bool IsStatic {
5930 get { return true; }
5933 protected override TypeSpec DeclaringType {
5934 get { return constant.DeclaringType; }
5937 public override Expression CreateExpressionTree (ResolveContext ec)
5939 throw new NotSupportedException ("ET");
5942 protected override Expression DoResolve (ResolveContext rc)
5944 ResolveInstanceExpression (rc, null);
5945 DoBestMemberChecks (rc, constant);
5947 var c = constant.GetConstant (rc);
5949 // Creates reference expression to the constant value
5950 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5953 public override void Emit (EmitContext ec)
5955 throw new NotSupportedException ();
5958 public override string GetSignatureForError ()
5960 return constant.GetSignatureForError ();
5963 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5965 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5970 // Fully resolved expression that references a Field
5972 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5974 protected FieldSpec spec;
5975 VariableInfo variable_info;
5977 LocalTemporary temp;
5980 protected FieldExpr (Location l)
5985 public FieldExpr (FieldSpec spec, Location loc)
5990 type = spec.MemberType;
5993 public FieldExpr (FieldBase fi, Location l)
6000 public override string Name {
6006 public bool IsHoisted {
6008 IVariableReference hv = InstanceExpression as IVariableReference;
6009 return hv != null && hv.IsHoisted;
6013 public override bool IsInstance {
6015 return !spec.IsStatic;
6019 public override bool IsStatic {
6021 return spec.IsStatic;
6025 public override string KindName {
6026 get { return "field"; }
6029 public FieldSpec Spec {
6035 protected override TypeSpec DeclaringType {
6037 return spec.DeclaringType;
6041 public VariableInfo VariableInfo {
6043 return variable_info;
6049 public override string GetSignatureForError ()
6051 return spec.GetSignatureForError ();
6054 public bool IsMarshalByRefAccess (ResolveContext rc)
6056 // Checks possible ldflda of field access expression
6057 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6058 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6059 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6062 public void SetHasAddressTaken ()
6064 IVariableReference vr = InstanceExpression as IVariableReference;
6066 vr.SetHasAddressTaken ();
6070 protected override void CloneTo (CloneContext clonectx, Expression target)
6072 var t = (FieldExpr) target;
6074 if (InstanceExpression != null)
6075 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6078 public override Expression CreateExpressionTree (ResolveContext ec)
6080 if (ConditionalAccess) {
6081 Error_NullShortCircuitInsideExpressionTree (ec);
6084 return CreateExpressionTree (ec, true);
6087 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6090 Expression instance;
6092 if (InstanceExpression == null) {
6093 instance = new NullLiteral (loc);
6094 } else if (convertInstance) {
6095 instance = InstanceExpression.CreateExpressionTree (ec);
6097 args = new Arguments (1);
6098 args.Add (new Argument (InstanceExpression));
6099 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6102 args = Arguments.CreateForExpressionTree (ec, null,
6104 CreateTypeOfExpression ());
6106 return CreateExpressionFactoryCall (ec, "Field", args);
6109 public Expression CreateTypeOfExpression ()
6111 return new TypeOfField (spec, loc);
6114 protected override Expression DoResolve (ResolveContext ec)
6116 spec.MemberDefinition.SetIsUsed ();
6118 return DoResolve (ec, null);
6121 Expression DoResolve (ResolveContext ec, Expression rhs)
6123 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6126 ResolveConditionalAccessReceiver (ec);
6128 if (ResolveInstanceExpression (ec, rhs)) {
6129 // Resolve the field's instance expression while flow analysis is turned
6130 // off: when accessing a field "a.b", we must check whether the field
6131 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6133 if (lvalue_instance) {
6134 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6136 Expression right_side =
6137 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6139 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6141 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6144 if (InstanceExpression == null)
6148 DoBestMemberChecks (ec, spec);
6150 if (conditional_access_receiver)
6151 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6154 var fb = spec as FixedFieldSpec;
6155 IVariableReference var = InstanceExpression as IVariableReference;
6158 IFixedExpression fe = InstanceExpression as IFixedExpression;
6159 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6160 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6163 if (InstanceExpression.eclass != ExprClass.Variable) {
6164 ec.Report.SymbolRelatedToPreviousError (spec);
6165 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6166 TypeManager.GetFullNameSignature (spec));
6167 } else if (var != null && var.IsHoisted) {
6168 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6171 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6175 // Set flow-analysis variable info for struct member access. It will be check later
6176 // for precise error reporting
6178 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6179 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6182 if (ConditionalAccess) {
6183 if (conditional_access_receiver)
6184 type = LiftMemberType (ec, type);
6186 if (InstanceExpression.IsNull)
6187 return Constant.CreateConstantFromValue (type, null, loc);
6190 eclass = ExprClass.Variable;
6194 public void SetFieldAssigned (FlowAnalysisContext fc)
6199 bool lvalue_instance = spec.DeclaringType.IsStruct;
6200 if (lvalue_instance) {
6201 var var = InstanceExpression as IVariableReference;
6202 if (var != null && var.VariableInfo != null) {
6203 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6207 var fe = InstanceExpression as FieldExpr;
6209 Expression instance;
6212 instance = fe.InstanceExpression;
6213 var fe_instance = instance as FieldExpr;
6214 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6215 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6216 var var = InstanceExpression as IVariableReference;
6217 if (var != null && var.VariableInfo == null) {
6218 var var_inst = instance as IVariableReference;
6219 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6220 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6224 if (fe_instance != null) {
6233 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6234 instance.FlowAnalysis (fc);
6236 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6237 InstanceExpression.FlowAnalysis (fc);
6241 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6243 // The return value is always null. Returning a value simplifies calling code.
6245 if (right_side == EmptyExpression.OutAccess) {
6247 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6248 GetSignatureForError ());
6250 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6251 GetSignatureForError ());
6257 if (right_side == EmptyExpression.LValueMemberAccess) {
6258 // Already reported as CS1648/CS1650
6262 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6264 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6265 GetSignatureForError ());
6267 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6268 GetSignatureForError ());
6274 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6275 GetSignatureForError ());
6277 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6278 GetSignatureForError ());
6284 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6286 if (ConditionalAccess)
6287 throw new NotSupportedException ("null propagating operator assignment");
6289 if (spec is FixedFieldSpec) {
6290 // It could be much better error message but we want to be error compatible
6291 Error_ValueAssignment (ec, right_side);
6294 Expression e = DoResolve (ec, right_side);
6299 spec.MemberDefinition.SetIsAssigned ();
6301 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6302 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6303 ec.Report.Warning (420, 1, loc,
6304 "`{0}': A volatile field references will not be treated as volatile",
6305 spec.GetSignatureForError ());
6308 if (spec.IsReadOnly) {
6309 // InitOnly fields can only be assigned in constructors or initializers
6310 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6311 return Error_AssignToReadonly (ec, right_side);
6313 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6315 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6316 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6317 return Error_AssignToReadonly (ec, right_side);
6318 // static InitOnly fields cannot be assigned-to in an instance constructor
6319 if (IsStatic && !ec.IsStatic)
6320 return Error_AssignToReadonly (ec, right_side);
6321 // instance constructors can't modify InitOnly fields of other instances of the same type
6322 if (!IsStatic && !(InstanceExpression is This))
6323 return Error_AssignToReadonly (ec, right_side);
6327 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6328 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6329 ec.Report.Warning (197, 1, loc,
6330 "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",
6331 GetSignatureForError ());
6334 eclass = ExprClass.Variable;
6338 public override void FlowAnalysis (FlowAnalysisContext fc)
6340 var var = InstanceExpression as IVariableReference;
6342 var vi = var.VariableInfo;
6343 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6344 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6348 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6352 base.FlowAnalysis (fc);
6354 if (conditional_access_receiver)
6355 fc.ConditionalAccessEnd ();
6358 public override int GetHashCode ()
6360 return spec.GetHashCode ();
6363 public bool IsFixed {
6366 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6368 IVariableReference variable = InstanceExpression as IVariableReference;
6369 if (variable != null)
6370 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6372 IFixedExpression fe = InstanceExpression as IFixedExpression;
6373 return fe != null && fe.IsFixed;
6377 public override bool Equals (object obj)
6379 FieldExpr fe = obj as FieldExpr;
6383 if (spec != fe.spec)
6386 if (InstanceExpression == null || fe.InstanceExpression == null)
6389 return InstanceExpression.Equals (fe.InstanceExpression);
6392 public void Emit (EmitContext ec, bool leave_copy)
6394 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6398 ec.Emit (OpCodes.Volatile);
6400 ec.Emit (OpCodes.Ldsfld, spec);
6403 if (conditional_access_receiver)
6404 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6406 EmitInstance (ec, false);
6409 // Optimization for build-in types
6410 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6411 ec.EmitLoadFromPtr (type);
6413 var ff = spec as FixedFieldSpec;
6415 ec.Emit (OpCodes.Ldflda, spec);
6416 ec.Emit (OpCodes.Ldflda, ff.Element);
6419 ec.Emit (OpCodes.Volatile);
6421 ec.Emit (OpCodes.Ldfld, spec);
6425 if (conditional_access_receiver) {
6426 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6431 ec.Emit (OpCodes.Dup);
6433 temp = new LocalTemporary (this.Type);
6439 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6441 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6442 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6447 if (ConditionalAccess)
6448 throw new NotImplementedException ("null operator assignment");
6450 if (has_await_source)
6451 source = source.EmitToField (ec);
6453 EmitInstance (ec, prepared);
6458 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6459 ec.Emit (OpCodes.Dup);
6461 temp = new LocalTemporary (this.Type);
6466 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6467 ec.Emit (OpCodes.Volatile);
6469 spec.MemberDefinition.SetIsAssigned ();
6472 ec.Emit (OpCodes.Stsfld, spec);
6474 ec.Emit (OpCodes.Stfld, spec);
6476 if (ec.NotifyEvaluatorOnStore) {
6478 throw new NotImplementedException ("instance field write");
6481 ec.Emit (OpCodes.Dup);
6483 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6494 // Emits store to field with prepared values on stack
6496 public void EmitAssignFromStack (EmitContext ec)
6499 ec.Emit (OpCodes.Stsfld, spec);
6501 ec.Emit (OpCodes.Stfld, spec);
6505 public override void Emit (EmitContext ec)
6510 public override void EmitSideEffect (EmitContext ec)
6512 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6514 if (is_volatile) // || is_marshal_by_ref ())
6515 base.EmitSideEffect (ec);
6518 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6520 if ((mode & AddressOp.Store) != 0)
6521 spec.MemberDefinition.SetIsAssigned ();
6522 if ((mode & AddressOp.Load) != 0)
6523 spec.MemberDefinition.SetIsUsed ();
6526 // Handle initonly fields specially: make a copy and then
6527 // get the address of the copy.
6530 if (spec.IsReadOnly){
6532 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6544 var temp = ec.GetTemporaryLocal (type);
6545 ec.Emit (OpCodes.Stloc, temp);
6546 ec.Emit (OpCodes.Ldloca, temp);
6552 ec.Emit (OpCodes.Ldsflda, spec);
6555 EmitInstance (ec, false);
6556 ec.Emit (OpCodes.Ldflda, spec);
6560 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6562 return MakeExpression (ctx);
6565 public override SLE.Expression MakeExpression (BuilderContext ctx)
6568 return base.MakeExpression (ctx);
6570 return SLE.Expression.Field (
6571 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6572 spec.GetMetaInfo ());
6576 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6578 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6584 // Expression that evaluates to a Property.
6586 // This is not an LValue because we need to re-write the expression. We
6587 // can not take data from the stack and store it.
6589 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6591 Arguments arguments;
6592 FieldExpr backing_field;
6594 public PropertyExpr (PropertySpec spec, Location l)
6597 best_candidate = spec;
6598 type = spec.MemberType;
6603 protected override Arguments Arguments {
6612 protected override TypeSpec DeclaringType {
6614 return best_candidate.DeclaringType;
6618 public override string Name {
6620 return best_candidate.Name;
6624 public bool IsAutoPropertyAccess {
6626 var prop = best_candidate.MemberDefinition as Property;
6627 return prop != null && prop.BackingField != null;
6631 public override bool IsInstance {
6637 public override bool IsStatic {
6639 return best_candidate.IsStatic;
6643 public override string KindName {
6644 get { return "property"; }
6647 public PropertySpec PropertyInfo {
6649 return best_candidate;
6655 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6657 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6660 var args_count = arguments == null ? 0 : arguments.Count;
6661 if (args_count != body.Parameters.Count && args_count == 0)
6664 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6665 mg.InstanceExpression = InstanceExpression;
6670 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6672 return new PropertyExpr (spec, loc) {
6678 public override Expression CreateExpressionTree (ResolveContext ec)
6680 if (ConditionalAccess) {
6681 Error_NullShortCircuitInsideExpressionTree (ec);
6685 if (IsSingleDimensionalArrayLength ()) {
6686 args = new Arguments (1);
6687 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6688 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6691 args = new Arguments (2);
6692 if (InstanceExpression == null)
6693 args.Add (new Argument (new NullLiteral (loc)));
6695 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6696 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6697 return CreateExpressionFactoryCall (ec, "Property", args);
6700 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6702 DoResolveLValue (rc, null);
6703 return new TypeOfMethod (Setter, loc);
6706 public override string GetSignatureForError ()
6708 return best_candidate.GetSignatureForError ();
6711 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6714 return base.MakeExpression (ctx);
6716 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6720 public override SLE.Expression MakeExpression (BuilderContext ctx)
6723 return base.MakeExpression (ctx);
6725 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6729 void Error_PropertyNotValid (ResolveContext ec)
6731 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6732 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6733 GetSignatureForError ());
6736 bool IsSingleDimensionalArrayLength ()
6738 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6741 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6742 return ac != null && ac.Rank == 1;
6745 public override void Emit (EmitContext ec, bool leave_copy)
6748 // Special case: length of single dimension array property is turned into ldlen
6750 if (IsSingleDimensionalArrayLength ()) {
6751 if (conditional_access_receiver) {
6752 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6755 EmitInstance (ec, false);
6757 ec.Emit (OpCodes.Ldlen);
6758 ec.Emit (OpCodes.Conv_I4);
6760 if (conditional_access_receiver) {
6761 ec.CloseConditionalAccess (type);
6767 base.Emit (ec, leave_copy);
6770 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6772 if (backing_field != null) {
6773 backing_field.EmitAssign (ec, source, false, false);
6778 LocalTemporary await_source_arg = null;
6780 if (isCompound && !(source is DynamicExpressionStatement)) {
6781 emitting_compound_assignment = true;
6784 if (has_await_arguments) {
6785 await_source_arg = new LocalTemporary (Type);
6786 await_source_arg.Store (ec);
6788 args = new Arguments (1);
6789 args.Add (new Argument (await_source_arg));
6792 temp = await_source_arg;
6795 has_await_arguments = false;
6800 ec.Emit (OpCodes.Dup);
6801 temp = new LocalTemporary (this.Type);
6806 args = arguments ?? new Arguments (1);
6810 temp = new LocalTemporary (this.Type);
6812 args.Add (new Argument (temp));
6814 args.Add (new Argument (source));
6818 emitting_compound_assignment = false;
6820 var call = new CallEmitter ();
6821 call.InstanceExpression = InstanceExpression;
6823 call.InstanceExpressionOnStack = true;
6825 if (ConditionalAccess) {
6826 call.ConditionalAccess = true;
6830 call.Emit (ec, Setter, args, loc);
6832 call.EmitStatement (ec, Setter, args, loc);
6839 if (await_source_arg != null) {
6840 await_source_arg.Release (ec);
6844 public override void FlowAnalysis (FlowAnalysisContext fc)
6846 var prop = best_candidate.MemberDefinition as Property;
6847 if (prop != null && prop.BackingField != null) {
6848 var var = InstanceExpression as IVariableReference;
6850 var vi = var.VariableInfo;
6851 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6852 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6856 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6861 base.FlowAnalysis (fc);
6863 if (conditional_access_receiver)
6864 fc.ConditionalAccessEnd ();
6867 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6869 eclass = ExprClass.PropertyAccess;
6871 if (best_candidate.IsNotCSharpCompatible) {
6872 Error_PropertyNotValid (rc);
6875 ResolveInstanceExpression (rc, right_side);
6877 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6878 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6879 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6881 type = p.MemberType;
6885 DoBestMemberChecks (rc, best_candidate);
6887 // Handling of com-imported properties with any number of default property parameters
6888 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6889 var p = best_candidate.Get.Parameters;
6890 arguments = new Arguments (p.Count);
6891 for (int i = 0; i < p.Count; ++i) {
6892 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6894 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6895 var p = best_candidate.Set.Parameters;
6896 arguments = new Arguments (p.Count - 1);
6897 for (int i = 0; i < p.Count - 1; ++i) {
6898 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6905 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
6907 var prop = best_candidate.MemberDefinition as Property;
6911 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
6914 var spec = prop.BackingField;
6918 if (rc.IsStatic != spec.IsStatic)
6921 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
6924 backing_field = new FieldExpr (prop.BackingField, loc);
6925 backing_field.ResolveLValue (rc, rhs);
6929 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
6931 if (backing_field != null) {
6932 backing_field.SetFieldAssigned (fc);
6936 if (!IsAutoPropertyAccess)
6939 var prop = best_candidate.MemberDefinition as Property;
6940 if (prop != null && prop.BackingField != null) {
6941 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
6942 if (lvalue_instance) {
6943 var var = InstanceExpression as IVariableReference;
6944 if (var != null && var.VariableInfo != null) {
6945 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
6951 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6953 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6957 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6959 // getter and setter can be different for base calls
6960 MethodSpec getter, setter;
6961 protected T best_candidate;
6963 protected LocalTemporary temp;
6964 protected bool emitting_compound_assignment;
6965 protected bool has_await_arguments;
6967 protected PropertyOrIndexerExpr (Location l)
6974 protected abstract Arguments Arguments { get; set; }
6976 public MethodSpec Getter {
6985 public MethodSpec Setter {
6996 protected override Expression DoResolve (ResolveContext ec)
6998 if (eclass == ExprClass.Unresolved) {
6999 ResolveConditionalAccessReceiver (ec);
7001 var expr = OverloadResolve (ec, null);
7006 return expr.Resolve (ec);
7008 if (conditional_access_receiver) {
7009 type = LiftMemberType (ec, type);
7010 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7014 if (!ResolveGetter (ec))
7020 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7022 if (ConditionalAccess)
7023 throw new NotSupportedException ("null propagating operator assignment");
7025 if (right_side == EmptyExpression.OutAccess) {
7026 // TODO: best_candidate can be null at this point
7027 INamedBlockVariable variable = null;
7028 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7029 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7030 best_candidate.Name);
7032 right_side.DoResolveLValue (rc, this);
7037 if (eclass == ExprClass.Unresolved) {
7038 var expr = OverloadResolve (rc, right_side);
7043 return expr.ResolveLValue (rc, right_side);
7045 ResolveInstanceExpression (rc, right_side);
7048 if (!best_candidate.HasSet) {
7049 if (ResolveAutopropertyAssignment (rc, right_side))
7052 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7053 GetSignatureForError ());
7057 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7058 if (best_candidate.HasDifferentAccessibility) {
7059 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7060 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7061 GetSignatureForError ());
7063 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7064 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7068 if (best_candidate.HasDifferentAccessibility)
7069 CheckProtectedMemberAccess (rc, best_candidate.Set);
7071 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7075 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7077 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7079 call.Emit (ec, method, arguments, loc);
7081 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7085 // Implements the IAssignMethod interface for assignments
7087 public virtual void Emit (EmitContext ec, bool leave_copy)
7089 var call = new CallEmitter ();
7090 call.ConditionalAccess = ConditionalAccess;
7091 call.InstanceExpression = InstanceExpression;
7092 if (has_await_arguments)
7093 call.HasAwaitArguments = true;
7095 call.DuplicateArguments = emitting_compound_assignment;
7097 if (conditional_access_receiver)
7098 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7100 call.Emit (ec, Getter, Arguments, loc);
7102 if (call.HasAwaitArguments) {
7103 InstanceExpression = call.InstanceExpression;
7104 Arguments = call.EmittedArguments;
7105 has_await_arguments = true;
7109 ec.Emit (OpCodes.Dup);
7110 temp = new LocalTemporary (Type);
7115 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7117 public override void Emit (EmitContext ec)
7122 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7124 has_await_arguments = true;
7129 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7131 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7133 bool ResolveGetter (ResolveContext rc)
7135 if (!best_candidate.HasGet) {
7136 if (InstanceExpression != EmptyExpression.Null) {
7137 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7138 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7139 best_candidate.GetSignatureForError ());
7142 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7143 if (best_candidate.HasDifferentAccessibility) {
7144 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7145 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7146 TypeManager.CSharpSignature (best_candidate));
7148 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7149 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7153 if (best_candidate.HasDifferentAccessibility) {
7154 CheckProtectedMemberAccess (rc, best_candidate.Get);
7157 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7161 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7168 /// Fully resolved expression that evaluates to an Event
7170 public class EventExpr : MemberExpr, IAssignMethod
7172 readonly EventSpec spec;
7175 public EventExpr (EventSpec spec, Location loc)
7183 protected override TypeSpec DeclaringType {
7185 return spec.DeclaringType;
7189 public override string Name {
7195 public override bool IsInstance {
7197 return !spec.IsStatic;
7201 public override bool IsStatic {
7203 return spec.IsStatic;
7207 public override string KindName {
7208 get { return "event"; }
7211 public MethodSpec Operator {
7219 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7222 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7224 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7225 if (spec.BackingField != null &&
7226 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7228 spec.MemberDefinition.SetIsUsed ();
7230 if (!ec.IsObsolete) {
7231 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7233 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7236 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7237 Error_AssignmentEventOnly (ec);
7239 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7241 InstanceExpression = null;
7243 return ml.ResolveMemberAccess (ec, left, original);
7247 return base.ResolveMemberAccess (ec, left, original);
7250 public override Expression CreateExpressionTree (ResolveContext ec)
7252 throw new NotSupportedException ("ET");
7255 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7257 if (right_side == EmptyExpression.EventAddition) {
7258 op = spec.AccessorAdd;
7259 } else if (right_side == EmptyExpression.EventSubtraction) {
7260 op = spec.AccessorRemove;
7264 Error_AssignmentEventOnly (ec);
7268 op = CandidateToBaseOverride (ec, op);
7272 protected override Expression DoResolve (ResolveContext ec)
7274 eclass = ExprClass.EventAccess;
7275 type = spec.MemberType;
7277 ResolveInstanceExpression (ec, null);
7279 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7280 Error_AssignmentEventOnly (ec);
7283 DoBestMemberChecks (ec, spec);
7287 public override void Emit (EmitContext ec)
7289 throw new NotSupportedException ();
7290 //Error_CannotAssign ();
7293 #region IAssignMethod Members
7295 public void Emit (EmitContext ec, bool leave_copy)
7297 throw new NotImplementedException ();
7300 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7302 if (leave_copy || !isCompound)
7303 throw new NotImplementedException ("EventExpr::EmitAssign");
7305 Arguments args = new Arguments (1);
7306 args.Add (new Argument (source));
7308 // TODO: Wrong, needs receiver
7309 // if (NullShortCircuit) {
7310 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7313 var call = new CallEmitter ();
7314 call.InstanceExpression = InstanceExpression;
7315 call.ConditionalAccess = ConditionalAccess;
7316 call.EmitStatement (ec, op, args, loc);
7318 // if (NullShortCircuit)
7319 // ec.CloseConditionalAccess (null);
7324 void Error_AssignmentEventOnly (ResolveContext ec)
7326 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7327 ec.Report.Error (79, loc,
7328 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7329 GetSignatureForError ());
7331 ec.Report.Error (70, loc,
7332 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7333 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7337 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7339 name = name.Substring (0, name.LastIndexOf ('.'));
7340 base.Error_CannotCallAbstractBase (rc, name);
7343 public override string GetSignatureForError ()
7345 return TypeManager.CSharpSignature (spec);
7348 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7350 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7354 public class TemporaryVariableReference : VariableReference
7356 public class Declarator : Statement
7358 TemporaryVariableReference variable;
7360 public Declarator (TemporaryVariableReference variable)
7362 this.variable = variable;
7366 protected override void DoEmit (EmitContext ec)
7368 variable.li.CreateBuilder (ec);
7371 public override void Emit (EmitContext ec)
7373 // Don't create sequence point
7377 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7382 protected override void CloneTo (CloneContext clonectx, Statement target)
7390 public TemporaryVariableReference (LocalVariable li, Location loc)
7393 this.type = li.Type;
7397 public override bool IsLockedByStatement {
7405 public LocalVariable LocalInfo {
7411 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7413 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7414 return new TemporaryVariableReference (li, loc);
7417 protected override Expression DoResolve (ResolveContext ec)
7419 eclass = ExprClass.Variable;
7422 // Don't capture temporary variables except when using
7423 // state machine redirection and block yields
7425 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7426 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7427 ec.IsVariableCapturingRequired) {
7428 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7429 storey.CaptureLocalVariable (ec, li);
7435 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7437 return Resolve (ec);
7440 public override void Emit (EmitContext ec)
7442 li.CreateBuilder (ec);
7447 public void EmitAssign (EmitContext ec, Expression source)
7449 li.CreateBuilder (ec);
7451 EmitAssign (ec, source, false, false);
7454 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7456 return li.HoistedVariant;
7459 public override bool IsFixed {
7460 get { return true; }
7463 public override bool IsRef {
7464 get { return false; }
7467 public override string Name {
7468 get { throw new NotImplementedException (); }
7471 public override void SetHasAddressTaken ()
7473 throw new NotImplementedException ();
7476 protected override ILocalVariable Variable {
7480 public override VariableInfo VariableInfo {
7481 get { return null; }
7486 /// Handles `var' contextual keyword; var becomes a keyword only
7487 /// if no type called var exists in a variable scope
7489 class VarExpr : SimpleName
7491 public VarExpr (Location loc)
7496 public bool InferType (ResolveContext ec, Expression right_side)
7499 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7501 type = right_side.Type;
7502 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7503 ec.Report.Error (815, loc,
7504 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7505 type.GetSignatureForError ());
7509 eclass = ExprClass.Variable;
7513 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7515 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7516 base.Error_TypeOrNamespaceNotFound (ec);
7518 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");