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;
465 public virtual bool HasConditionalAccess ()
470 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
472 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
473 Nullable.NullableInfo.MakeType (rc.Module, type) :
478 /// Resolves an expression and performs semantic analysis on it.
482 /// Currently Resolve wraps DoResolve to perform sanity
483 /// checking and assertion checking on what we expect from Resolve.
485 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
487 if (eclass != ExprClass.Unresolved) {
488 if ((flags & ExprClassToResolveFlags) == 0) {
489 Error_UnexpectedKind (ec, flags, loc);
503 if ((flags & e.ExprClassToResolveFlags) == 0) {
504 e.Error_UnexpectedKind (ec, flags, loc);
509 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
512 } catch (Exception ex) {
513 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
514 ec.Report.Printer is NullReportPrinter)
517 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
518 return ErrorExpression.Instance; // TODO: Add location
523 /// Resolves an expression and performs semantic analysis on it.
525 public Expression Resolve (ResolveContext rc)
527 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
531 /// Resolves an expression for LValue assignment
535 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
536 /// checking and assertion checking on what we expect from Resolve
538 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
540 int errors = ec.Report.Errors;
541 bool out_access = right_side == EmptyExpression.OutAccess;
543 Expression e = DoResolveLValue (ec, right_side);
545 if (e != null && out_access && !(e is IMemoryLocation)) {
546 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
547 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
549 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
550 // e.GetType () + " " + e.GetSignatureForError ());
555 if (errors == ec.Report.Errors) {
556 Error_ValueAssignment (ec, right_side);
561 if (e.eclass == ExprClass.Unresolved)
562 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
564 if ((e.type == null) && !(e is GenericTypeExpr))
565 throw new Exception ("Expression " + e + " did not set its type after Resolve");
570 public Constant ResolveLabelConstant (ResolveContext rc)
572 var expr = Resolve (rc);
576 Constant c = expr as Constant;
578 if (expr.type != InternalType.ErrorType)
579 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
587 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
589 if (Attribute.IsValidArgumentType (parameterType)) {
590 rc.Module.Compiler.Report.Error (182, loc,
591 "An attribute argument must be a constant expression, typeof expression or array creation expression");
593 rc.Module.Compiler.Report.Error (181, loc,
594 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
595 targetType.GetSignatureForError ());
600 /// Emits the code for the expression
604 /// The Emit method is invoked to generate the code
605 /// for the expression.
607 public abstract void Emit (EmitContext ec);
610 // Emit code to branch to @target if this expression is equivalent to @on_true.
611 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
612 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
613 // including the use of conditional branches. Note also that a branch MUST be emitted
614 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
617 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
620 // Emit this expression for its side effects, not for its value.
621 // The default implementation is to emit the value, and then throw it away.
622 // Subclasses can provide more efficient implementations, but those MUST be equivalent
623 public virtual void EmitSideEffect (EmitContext ec)
626 ec.Emit (OpCodes.Pop);
630 // Emits the expression into temporary field variable. The method
631 // should be used for await expressions only
633 public virtual Expression EmitToField (EmitContext ec)
636 // This is the await prepare Emit method. When emitting code like
637 // a + b we emit code like
643 // For await a + await b we have to interfere the flow to keep the
644 // stack clean because await yields from the expression. The emit
647 // a = a.EmitToField () // a is changed to temporary field access
648 // b = b.EmitToField ()
654 // The idea is to emit expression and leave the stack empty with
655 // result value still available.
657 // Expressions should override this default implementation when
658 // optimized version can be provided (e.g. FieldExpr)
661 // We can optimize for side-effect free expressions, they can be
662 // emitted out of order
664 if (IsSideEffectFree)
667 bool needs_temporary = ContainsEmitWithAwait ();
668 if (!needs_temporary)
671 // Emit original code
672 var field = EmitToFieldSource (ec);
675 // Store the result to temporary field when we
676 // cannot load `this' directly
678 field = ec.GetTemporaryField (type);
679 if (needs_temporary) {
681 // Create temporary local (we cannot load `this' before Emit)
683 var temp = ec.GetTemporaryLocal (type);
684 ec.Emit (OpCodes.Stloc, temp);
687 ec.Emit (OpCodes.Ldloc, temp);
688 field.EmitAssignFromStack (ec);
690 ec.FreeTemporaryLocal (temp, type);
692 field.EmitAssignFromStack (ec);
699 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
702 // Default implementation calls Emit method
708 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
710 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
711 bool contains_await = false;
713 for (int i = 1; i < expressions.Count; ++i) {
714 if (expressions[i].ContainsEmitWithAwait ()) {
715 contains_await = true;
720 if (contains_await) {
721 for (int i = 0; i < expressions.Count; ++i) {
722 expressions[i] = expressions[i].EmitToField (ec);
727 for (int i = 0; i < expressions.Count; ++i) {
728 expressions[i].Emit (ec);
733 /// Protected constructor. Only derivate types should
734 /// be able to be created
737 protected Expression ()
742 /// Returns a fully formed expression after a MemberLookup
745 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
747 if (spec is EventSpec)
748 return new EventExpr ((EventSpec) spec, loc);
749 if (spec is ConstSpec)
750 return new ConstantExpr ((ConstSpec) spec, loc);
751 if (spec is FieldSpec)
752 return new FieldExpr ((FieldSpec) spec, loc);
753 if (spec is PropertySpec)
754 return new PropertyExpr ((PropertySpec) spec, loc);
755 if (spec is TypeSpec)
756 return new TypeExpression (((TypeSpec) spec), loc);
761 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
763 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
766 case MemberKind.Struct:
767 // Every struct has implicit default constructor if not provided by user
771 rc.Report.SymbolRelatedToPreviousError (type);
772 // Report meaningful error for struct as they always have default ctor in C# context
773 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
775 case MemberKind.MissingType:
776 case MemberKind.InternalCompilerType:
777 // LAMESPEC: dynamic is not really object
778 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
782 rc.Report.SymbolRelatedToPreviousError (type);
783 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
784 type.GetSignatureForError ());
791 if (args == null && type.IsStruct) {
792 bool includes_empty = false;
793 foreach (MethodSpec ctor in ctors) {
794 if (ctor.Parameters.IsEmpty) {
795 includes_empty = true;
803 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
804 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
805 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
808 return r.ResolveMember<MethodSpec> (rc, ref args);
812 public enum MemberLookupRestrictions
818 EmptyArguments = 1 << 4,
819 IgnoreArity = 1 << 5,
820 IgnoreAmbiguity = 1 << 6
824 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
825 // `qualifier_type' or null to lookup members in the current class.
827 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
829 var members = MemberCache.FindMembers (queried_type, name, false);
833 MemberSpec non_method = null;
834 MemberSpec ambig_non_method = null;
836 for (int i = 0; i < members.Count; ++i) {
837 var member = members[i];
839 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
840 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
843 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
846 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
850 if (!member.IsAccessible (rc))
854 // With runtime binder we can have a situation where queried type is inaccessible
855 // because it came via dynamic object, the check about inconsisted accessibility
856 // had no effect as the type was unknown during compilation
859 // private class N { }
861 // public dynamic Foo ()
867 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
871 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
872 if (member is MethodSpec) {
874 // Interface members that are hidden by class members are removed from the set. This
875 // step only has an effect if T is a type parameter and T has both an effective base
876 // class other than object and a non-empty effective interface set
878 var tps = queried_type as TypeParameterSpec;
879 if (tps != null && tps.HasTypeConstraint)
880 members = RemoveHiddenTypeParameterMethods (members);
882 return new MethodGroupExpr (members, queried_type, loc);
885 if (!Invocation.IsMemberInvocable (member))
889 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
891 } else if (!errorMode && !member.IsNotCSharpCompatible) {
893 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
894 // T has both an effective base class other than object and a non-empty effective interface set.
896 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
898 var tps = queried_type as TypeParameterSpec;
899 if (tps != null && tps.HasTypeConstraint) {
900 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
903 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
909 ambig_non_method = member;
913 if (non_method != null) {
914 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
915 var report = rc.Module.Compiler.Report;
916 report.SymbolRelatedToPreviousError (non_method);
917 report.SymbolRelatedToPreviousError (ambig_non_method);
918 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
919 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
922 if (non_method is MethodSpec)
923 return new MethodGroupExpr (members, queried_type, loc);
925 return ExprClassFromMemberInfo (non_method, loc);
928 if (members[0].DeclaringType.BaseType == null)
931 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
933 } while (members != null);
938 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
940 if (members.Count < 2)
944 // If M is a method, then all non-method members declared in an interface declaration
945 // are removed from the set, and all methods with the same signature as M declared in
946 // an interface declaration are removed from the set
950 for (int i = 0; i < members.Count; ++i) {
951 var method = members[i] as MethodSpec;
952 if (method == null) {
955 members = new List<MemberSpec> (members);
958 members.RemoveAt (i--);
962 if (!method.DeclaringType.IsInterface)
965 for (int ii = 0; ii < members.Count; ++ii) {
966 var candidate = members[ii] as MethodSpec;
967 if (candidate == null || !candidate.DeclaringType.IsClass)
970 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
975 members = new List<MemberSpec> (members);
978 members.RemoveAt (i--);
986 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
988 throw new NotImplementedException ();
991 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
993 if (t == InternalType.ErrorType)
996 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
997 oper, t.GetSignatureForError ());
1000 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1002 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1005 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1007 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1010 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1015 // Special version of flow analysis for expressions which can return different
1016 // on-true and on-false result. Used by &&, ||, ?: expressions
1018 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1021 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1025 /// Returns an expression that can be used to invoke operator true
1026 /// on the expression if it exists.
1028 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1030 return GetOperatorTrueOrFalse (ec, e, true, loc);
1034 /// Returns an expression that can be used to invoke operator false
1035 /// on the expression if it exists.
1037 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1039 return GetOperatorTrueOrFalse (ec, e, false, loc);
1042 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1044 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1045 var methods = MemberCache.GetUserOperator (e.type, op, false);
1046 if (methods == null)
1049 Arguments arguments = new Arguments (1);
1050 arguments.Add (new Argument (e));
1052 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1053 var oper = res.ResolveOperator (ec, ref arguments);
1058 return new UserOperatorCall (oper, arguments, null, loc);
1061 public virtual string ExprClassName
1065 case ExprClass.Unresolved:
1066 return "Unresolved";
1067 case ExprClass.Value:
1069 case ExprClass.Variable:
1071 case ExprClass.Namespace:
1073 case ExprClass.Type:
1075 case ExprClass.MethodGroup:
1076 return "method group";
1077 case ExprClass.PropertyAccess:
1078 return "property access";
1079 case ExprClass.EventAccess:
1080 return "event access";
1081 case ExprClass.IndexerAccess:
1082 return "indexer access";
1083 case ExprClass.Nothing:
1085 case ExprClass.TypeParameter:
1086 return "type parameter";
1088 throw new Exception ("Should not happen");
1093 /// Reports that we were expecting `expr' to be of class `expected'
1095 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1097 var name = memberExpr.GetSignatureForError ();
1099 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1102 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1104 string [] valid = new string [4];
1107 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1108 valid [count++] = "variable";
1109 valid [count++] = "value";
1112 if ((flags & ResolveFlags.Type) != 0)
1113 valid [count++] = "type";
1115 if ((flags & ResolveFlags.MethodGroup) != 0)
1116 valid [count++] = "method group";
1119 valid [count++] = "unknown";
1121 StringBuilder sb = new StringBuilder (valid [0]);
1122 for (int i = 1; i < count - 1; i++) {
1124 sb.Append (valid [i]);
1127 sb.Append ("' or `");
1128 sb.Append (valid [count - 1]);
1131 ec.Report.Error (119, loc,
1132 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1135 public static void UnsafeError (ResolveContext ec, Location loc)
1137 UnsafeError (ec.Report, loc);
1140 public static void UnsafeError (Report Report, Location loc)
1142 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1146 // Converts `source' to an int, uint, long or ulong.
1148 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1150 var btypes = ec.BuiltinTypes;
1152 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1153 Arguments args = new Arguments (1);
1154 args.Add (new Argument (source));
1155 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1158 Expression converted;
1160 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1161 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1162 if (converted == null)
1163 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1164 if (converted == null)
1165 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1166 if (converted == null)
1167 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1169 if (converted == null) {
1170 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1179 // Only positive constants are allowed at compile time
1181 Constant c = converted as Constant;
1182 if (c != null && c.IsNegative)
1183 Error_NegativeArrayIndex (ec, source.loc);
1185 // No conversion needed to array index
1186 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1189 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1193 // Derived classes implement this method by cloning the fields that
1194 // could become altered during the Resolve stage
1196 // Only expressions that are created for the parser need to implement
1199 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1201 throw new NotImplementedException (
1203 "CloneTo not implemented for expression {0}", this.GetType ()));
1207 // Clones an expression created by the parser.
1209 // We only support expressions created by the parser so far, not
1210 // expressions that have been resolved (many more classes would need
1211 // to implement CloneTo).
1213 // This infrastructure is here merely for Lambda expressions which
1214 // compile the same code using different type values for the same
1215 // arguments to find the correct overload
1217 public virtual Expression Clone (CloneContext clonectx)
1219 Expression cloned = (Expression) MemberwiseClone ();
1220 CloneTo (clonectx, cloned);
1226 // Implementation of expression to expression tree conversion
1228 public abstract Expression CreateExpressionTree (ResolveContext ec);
1230 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1232 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1235 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1237 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1240 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1242 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1245 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1247 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1251 return new TypeExpression (t, loc);
1255 // Implemented by all expressions which support conversion from
1256 // compiler expression to invokable runtime expression. Used by
1257 // dynamic C# binder.
1259 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1261 throw new NotImplementedException ("MakeExpression for " + GetType ());
1264 public virtual object Accept (StructuralVisitor visitor)
1266 return visitor.Visit (this);
1271 /// This is just a base class for expressions that can
1272 /// appear on statements (invocations, object creation,
1273 /// assignments, post/pre increment and decrement). The idea
1274 /// being that they would support an extra Emition interface that
1275 /// does not leave a result on the stack.
1277 public abstract class ExpressionStatement : Expression
1279 public virtual void MarkReachable (Reachability rc)
1283 public ExpressionStatement ResolveStatement (BlockContext ec)
1285 Expression e = Resolve (ec);
1289 ExpressionStatement es = e as ExpressionStatement;
1290 if (es == null || e is AnonymousMethodBody)
1291 Error_InvalidExpressionStatement (ec);
1294 // This is quite expensive warning, try to limit the damage
1296 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1297 WarningAsyncWithoutWait (ec, e);
1303 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1305 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1306 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1311 // Need to do full resolve because GetAwaiter can be extension method
1312 // available only in this context
1314 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1318 var arguments = new Arguments (0);
1319 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1324 // Use same check rules as for real await
1326 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1327 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1330 bc.Report.Warning (4014, 1, e.Location,
1331 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1335 var inv = e as Invocation;
1336 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1337 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1338 bc.Report.Warning (4014, 1, e.Location,
1339 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1345 /// Requests the expression to be emitted in a `statement'
1346 /// context. This means that no new value is left on the
1347 /// stack after invoking this method (constrasted with
1348 /// Emit that will always leave a value on the stack).
1350 public abstract void EmitStatement (EmitContext ec);
1352 public override void EmitSideEffect (EmitContext ec)
1359 /// This kind of cast is used to encapsulate the child
1360 /// whose type is child.Type into an expression that is
1361 /// reported to return "return_type". This is used to encapsulate
1362 /// expressions which have compatible types, but need to be dealt
1363 /// at higher levels with.
1365 /// For example, a "byte" expression could be encapsulated in one
1366 /// of these as an "unsigned int". The type for the expression
1367 /// would be "unsigned int".
1370 public abstract class TypeCast : Expression
1372 protected readonly Expression child;
1374 protected TypeCast (Expression child, TypeSpec return_type)
1376 eclass = child.eclass;
1377 loc = child.Location;
1382 public Expression Child {
1388 public override bool ContainsEmitWithAwait ()
1390 return child.ContainsEmitWithAwait ();
1393 public override Expression CreateExpressionTree (ResolveContext ec)
1395 Arguments args = new Arguments (2);
1396 args.Add (new Argument (child.CreateExpressionTree (ec)));
1397 args.Add (new Argument (new TypeOf (type, loc)));
1399 if (type.IsPointer || child.Type.IsPointer)
1400 Error_PointerInsideExpressionTree (ec);
1402 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1405 protected override Expression DoResolve (ResolveContext ec)
1407 // This should never be invoked, we are born in fully
1408 // initialized state.
1413 public override void Emit (EmitContext ec)
1418 public override void FlowAnalysis (FlowAnalysisContext fc)
1420 child.FlowAnalysis (fc);
1423 public override SLE.Expression MakeExpression (BuilderContext ctx)
1426 return base.MakeExpression (ctx);
1428 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1429 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1430 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1434 protected override void CloneTo (CloneContext clonectx, Expression t)
1439 public override bool IsNull {
1440 get { return child.IsNull; }
1444 public class EmptyCast : TypeCast {
1445 EmptyCast (Expression child, TypeSpec target_type)
1446 : base (child, target_type)
1450 public static Expression Create (Expression child, TypeSpec type)
1452 Constant c = child as Constant;
1454 var enum_constant = c as EnumConstant;
1455 if (enum_constant != null)
1456 c = enum_constant.Child;
1458 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1462 var res = c.ConvertImplicitly (type);
1468 EmptyCast e = child as EmptyCast;
1470 return new EmptyCast (e.child, type);
1472 return new EmptyCast (child, type);
1475 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1477 child.EmitBranchable (ec, label, on_true);
1480 public override void EmitSideEffect (EmitContext ec)
1482 child.EmitSideEffect (ec);
1487 // Used for predefined type user operator (no obsolete check, etc.)
1489 public class OperatorCast : TypeCast
1491 readonly MethodSpec conversion_operator;
1493 public OperatorCast (Expression expr, TypeSpec target_type)
1494 : this (expr, target_type, target_type, false)
1498 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1499 : this (expr, target_type, target_type, find_explicit)
1503 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1504 : base (expr, returnType)
1506 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1507 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1510 foreach (MethodSpec oper in mi) {
1511 if (oper.ReturnType != returnType)
1514 if (oper.Parameters.Types[0] == expr.Type) {
1515 conversion_operator = oper;
1521 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1522 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1525 public override void Emit (EmitContext ec)
1528 ec.Emit (OpCodes.Call, conversion_operator);
1533 // Constant specialization of EmptyCast.
1534 // We need to special case this since an empty cast of
1535 // a constant is still a constant.
1537 public class EmptyConstantCast : Constant
1539 public readonly Constant child;
1541 public EmptyConstantCast (Constant child, TypeSpec type)
1542 : base (child.Location)
1545 throw new ArgumentNullException ("child");
1548 this.eclass = child.eclass;
1552 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1554 if (child.Type == target_type)
1557 // FIXME: check that 'type' can be converted to 'target_type' first
1558 return child.ConvertExplicitly (in_checked_context, target_type);
1561 public override Expression CreateExpressionTree (ResolveContext ec)
1563 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1564 child.CreateExpressionTree (ec),
1565 new TypeOf (type, loc));
1568 Error_PointerInsideExpressionTree (ec);
1570 return CreateExpressionFactoryCall (ec, "Convert", args);
1573 public override bool IsDefaultValue {
1574 get { return child.IsDefaultValue; }
1577 public override bool IsNegative {
1578 get { return child.IsNegative; }
1581 public override bool IsNull {
1582 get { return child.IsNull; }
1585 public override bool IsOneInteger {
1586 get { return child.IsOneInteger; }
1589 public override bool IsSideEffectFree {
1591 return child.IsSideEffectFree;
1595 public override bool IsZeroInteger {
1596 get { return child.IsZeroInteger; }
1599 public override void Emit (EmitContext ec)
1604 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1606 child.EmitBranchable (ec, label, on_true);
1608 // Only to make verifier happy
1609 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1610 ec.Emit (OpCodes.Unbox_Any, type);
1613 public override void EmitSideEffect (EmitContext ec)
1615 child.EmitSideEffect (ec);
1618 public override object GetValue ()
1620 return child.GetValue ();
1623 public override string GetValueAsLiteral ()
1625 return child.GetValueAsLiteral ();
1628 public override long GetValueAsLong ()
1630 return child.GetValueAsLong ();
1633 public override Constant ConvertImplicitly (TypeSpec target_type)
1635 if (type == target_type)
1638 // FIXME: Do we need to check user conversions?
1639 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1642 return child.ConvertImplicitly (target_type);
1647 /// This class is used to wrap literals which belong inside Enums
1649 public class EnumConstant : Constant
1651 public Constant Child;
1653 public EnumConstant (Constant child, TypeSpec enum_type)
1654 : base (child.Location)
1658 this.eclass = ExprClass.Value;
1659 this.type = enum_type;
1662 protected EnumConstant (Location loc)
1667 public override void Emit (EmitContext ec)
1672 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1674 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1677 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1679 Child.EmitBranchable (ec, label, on_true);
1682 public override void EmitSideEffect (EmitContext ec)
1684 Child.EmitSideEffect (ec);
1687 public override string GetSignatureForError()
1689 return Type.GetSignatureForError ();
1692 public override object GetValue ()
1694 return Child.GetValue ();
1698 public override object GetTypedValue ()
1701 // The method can be used in dynamic context only (on closed types)
1703 // System.Enum.ToObject cannot be called on dynamic types
1704 // EnumBuilder has to be used, but we cannot use EnumBuilder
1705 // because it does not properly support generics
1707 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1711 public override string GetValueAsLiteral ()
1713 return Child.GetValueAsLiteral ();
1716 public override long GetValueAsLong ()
1718 return Child.GetValueAsLong ();
1721 public EnumConstant Increment()
1723 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1726 public override bool IsDefaultValue {
1728 return Child.IsDefaultValue;
1732 public override bool IsSideEffectFree {
1734 return Child.IsSideEffectFree;
1738 public override bool IsZeroInteger {
1739 get { return Child.IsZeroInteger; }
1742 public override bool IsNegative {
1744 return Child.IsNegative;
1748 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1750 if (Child.Type == target_type)
1753 return Child.ConvertExplicitly (in_checked_context, target_type);
1756 public override Constant ConvertImplicitly (TypeSpec type)
1758 if (this.type == type) {
1762 if (!Convert.ImplicitStandardConversionExists (this, type)){
1766 return Child.ConvertImplicitly (type);
1771 /// This kind of cast is used to encapsulate Value Types in objects.
1773 /// The effect of it is to box the value type emitted by the previous
1776 public class BoxedCast : TypeCast {
1778 public BoxedCast (Expression expr, TypeSpec target_type)
1779 : base (expr, target_type)
1781 eclass = ExprClass.Value;
1784 protected override Expression DoResolve (ResolveContext ec)
1786 // This should never be invoked, we are born in fully
1787 // initialized state.
1792 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1794 // Only boxing to object type is supported
1795 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1796 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1800 enc.Encode (child.Type);
1801 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1804 public override void Emit (EmitContext ec)
1808 ec.Emit (OpCodes.Box, child.Type);
1811 public override void EmitSideEffect (EmitContext ec)
1813 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1814 // so, we need to emit the box+pop instructions in most cases
1815 if (child.Type.IsStruct &&
1816 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1817 child.EmitSideEffect (ec);
1819 base.EmitSideEffect (ec);
1823 public class UnboxCast : TypeCast {
1824 public UnboxCast (Expression expr, TypeSpec return_type)
1825 : base (expr, return_type)
1829 protected override Expression DoResolve (ResolveContext ec)
1831 // This should never be invoked, we are born in fully
1832 // initialized state.
1837 public override void Emit (EmitContext ec)
1841 ec.Emit (OpCodes.Unbox_Any, type);
1846 /// This is used to perform explicit numeric conversions.
1848 /// Explicit numeric conversions might trigger exceptions in a checked
1849 /// context, so they should generate the conv.ovf opcodes instead of
1852 public class ConvCast : TypeCast {
1853 public enum Mode : byte {
1854 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1856 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1857 U2_I1, U2_U1, U2_I2, U2_CH,
1858 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1859 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1860 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1861 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1862 CH_I1, CH_U1, CH_I2,
1863 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1864 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1870 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1871 : base (child, return_type)
1876 protected override Expression DoResolve (ResolveContext ec)
1878 // This should never be invoked, we are born in fully
1879 // initialized state.
1884 public override string ToString ()
1886 return String.Format ("ConvCast ({0}, {1})", mode, child);
1889 public override void Emit (EmitContext ec)
1895 public static void Emit (EmitContext ec, Mode mode)
1897 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1899 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1900 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1901 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1902 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1903 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1905 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1906 case Mode.U1_CH: /* nothing */ break;
1908 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1909 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1910 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1911 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1912 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1913 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1915 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1916 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1917 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1918 case Mode.U2_CH: /* nothing */ break;
1920 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1921 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1922 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1923 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1924 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1925 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1926 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1929 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1930 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1931 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1932 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1933 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1935 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1936 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1937 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1938 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1939 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1940 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1941 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1942 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1945 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1946 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1947 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1948 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1949 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1950 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1951 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1952 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1953 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1955 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1956 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1957 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1959 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1960 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1961 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1962 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1964 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1965 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1966 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1967 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1969 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1970 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1971 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1972 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1974 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1975 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1976 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1977 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1978 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1980 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1984 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1985 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1986 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1987 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1988 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1990 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1991 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1993 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1994 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1995 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1996 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1997 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1998 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2000 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2001 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2002 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2003 case Mode.U2_CH: /* nothing */ break;
2005 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2006 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2007 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2008 case Mode.I4_U4: /* nothing */ break;
2009 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2010 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2011 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2013 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2014 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2015 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2016 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2017 case Mode.U4_I4: /* nothing */ break;
2018 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2020 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2021 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2022 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2023 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2024 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2025 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2026 case Mode.I8_U8: /* nothing */ break;
2027 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2028 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2030 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2031 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2032 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2033 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2035 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2036 case Mode.U8_I8: /* nothing */ break;
2037 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2038 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2040 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2041 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2042 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2044 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2045 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2046 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2047 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2049 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2050 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2051 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2052 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2054 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2055 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2056 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2057 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2059 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2060 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2061 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2062 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2063 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2065 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2071 class OpcodeCast : TypeCast
2075 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2076 : base (child, return_type)
2081 protected override Expression DoResolve (ResolveContext ec)
2083 // This should never be invoked, we are born in fully
2084 // initialized state.
2089 public override void Emit (EmitContext ec)
2095 public TypeSpec UnderlyingType {
2096 get { return child.Type; }
2101 // Opcode casts expression with 2 opcodes but only
2102 // single expression tree node
2104 class OpcodeCastDuplex : OpcodeCast
2106 readonly OpCode second;
2108 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2109 : base (child, returnType, first)
2111 this.second = second;
2114 public override void Emit (EmitContext ec)
2122 /// This kind of cast is used to encapsulate a child and cast it
2123 /// to the class requested
2125 public sealed class ClassCast : TypeCast {
2126 readonly bool forced;
2128 public ClassCast (Expression child, TypeSpec return_type)
2129 : base (child, return_type)
2133 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2134 : base (child, return_type)
2136 this.forced = forced;
2139 public override void Emit (EmitContext ec)
2143 bool gen = TypeManager.IsGenericParameter (child.Type);
2145 ec.Emit (OpCodes.Box, child.Type);
2147 if (type.IsGenericParameter) {
2148 ec.Emit (OpCodes.Unbox_Any, type);
2155 ec.Emit (OpCodes.Castclass, type);
2160 // Created during resolving pahse when an expression is wrapped or constantified
2161 // and original expression can be used later (e.g. for expression trees)
2163 public class ReducedExpression : Expression
2165 public sealed class ReducedConstantExpression : EmptyConstantCast
2167 readonly Expression orig_expr;
2169 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2170 : base (expr, expr.Type)
2172 this.orig_expr = orig_expr;
2175 public Expression OriginalExpression {
2181 public override Constant ConvertImplicitly (TypeSpec target_type)
2183 Constant c = base.ConvertImplicitly (target_type);
2185 c = new ReducedConstantExpression (c, orig_expr);
2190 public override Expression CreateExpressionTree (ResolveContext ec)
2192 return orig_expr.CreateExpressionTree (ec);
2195 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2197 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2199 c = new ReducedConstantExpression (c, orig_expr);
2203 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2206 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2208 if (orig_expr is Conditional)
2209 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2211 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2215 sealed class ReducedExpressionStatement : ExpressionStatement
2217 readonly Expression orig_expr;
2218 readonly ExpressionStatement stm;
2220 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2222 this.orig_expr = orig;
2224 this.eclass = stm.eclass;
2225 this.type = stm.Type;
2227 this.loc = orig.Location;
2230 public override bool ContainsEmitWithAwait ()
2232 return stm.ContainsEmitWithAwait ();
2235 public override Expression CreateExpressionTree (ResolveContext ec)
2237 return orig_expr.CreateExpressionTree (ec);
2240 protected override Expression DoResolve (ResolveContext ec)
2245 public override void Emit (EmitContext ec)
2250 public override void EmitStatement (EmitContext ec)
2252 stm.EmitStatement (ec);
2255 public override void FlowAnalysis (FlowAnalysisContext fc)
2257 stm.FlowAnalysis (fc);
2261 readonly Expression expr, orig_expr;
2263 private ReducedExpression (Expression expr, Expression orig_expr)
2266 this.eclass = expr.eclass;
2267 this.type = expr.Type;
2268 this.orig_expr = orig_expr;
2269 this.loc = orig_expr.Location;
2274 public override bool IsSideEffectFree {
2276 return expr.IsSideEffectFree;
2280 public Expression OriginalExpression {
2288 public override bool ContainsEmitWithAwait ()
2290 return expr.ContainsEmitWithAwait ();
2294 // Creates fully resolved expression switcher
2296 public static Constant Create (Constant expr, Expression original_expr)
2298 if (expr.eclass == ExprClass.Unresolved)
2299 throw new ArgumentException ("Unresolved expression");
2301 return new ReducedConstantExpression (expr, original_expr);
2304 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2306 return new ReducedExpressionStatement (s, orig);
2309 public static Expression Create (Expression expr, Expression original_expr)
2311 return Create (expr, original_expr, true);
2315 // Creates unresolved reduce expression. The original expression has to be
2316 // already resolved. Created expression is constant based based on `expr'
2317 // value unless canBeConstant is used
2319 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2321 if (canBeConstant) {
2322 Constant c = expr as Constant;
2324 return Create (c, original_expr);
2327 ExpressionStatement s = expr as ExpressionStatement;
2329 return Create (s, original_expr);
2331 if (expr.eclass == ExprClass.Unresolved)
2332 throw new ArgumentException ("Unresolved expression");
2334 return new ReducedExpression (expr, original_expr);
2337 public override Expression CreateExpressionTree (ResolveContext ec)
2339 return orig_expr.CreateExpressionTree (ec);
2342 protected override Expression DoResolve (ResolveContext ec)
2347 public override void Emit (EmitContext ec)
2352 public override Expression EmitToField (EmitContext ec)
2354 return expr.EmitToField(ec);
2357 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2359 expr.EmitBranchable (ec, target, on_true);
2362 public override void FlowAnalysis (FlowAnalysisContext fc)
2364 expr.FlowAnalysis (fc);
2367 public override SLE.Expression MakeExpression (BuilderContext ctx)
2369 return orig_expr.MakeExpression (ctx);
2374 // Standard composite pattern
2376 public abstract class CompositeExpression : Expression
2378 protected Expression expr;
2380 protected CompositeExpression (Expression expr)
2383 this.loc = expr.Location;
2386 public override bool ContainsEmitWithAwait ()
2388 return expr.ContainsEmitWithAwait ();
2391 public override Expression CreateExpressionTree (ResolveContext rc)
2393 return expr.CreateExpressionTree (rc);
2396 public Expression Child {
2397 get { return expr; }
2400 protected override Expression DoResolve (ResolveContext rc)
2402 expr = expr.Resolve (rc);
2407 eclass = expr.eclass;
2411 public override void Emit (EmitContext ec)
2416 public override bool IsNull {
2417 get { return expr.IsNull; }
2422 // Base of expressions used only to narrow resolve flow
2424 public abstract class ShimExpression : Expression
2426 protected Expression expr;
2428 protected ShimExpression (Expression expr)
2433 public Expression Expr {
2439 protected override void CloneTo (CloneContext clonectx, Expression t)
2444 ShimExpression target = (ShimExpression) t;
2445 target.expr = expr.Clone (clonectx);
2448 public override bool ContainsEmitWithAwait ()
2450 return expr.ContainsEmitWithAwait ();
2453 public override Expression CreateExpressionTree (ResolveContext ec)
2455 throw new NotSupportedException ("ET");
2458 public override void Emit (EmitContext ec)
2460 throw new InternalErrorException ("Missing Resolve call");
2464 public class UnreachableExpression : Expression
2466 public UnreachableExpression (Expression expr)
2468 this.loc = expr.Location;
2471 public override Expression CreateExpressionTree (ResolveContext ec)
2474 throw new NotImplementedException ();
2477 protected override Expression DoResolve (ResolveContext rc)
2479 throw new NotSupportedException ();
2482 public override void FlowAnalysis (FlowAnalysisContext fc)
2484 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2487 public override void Emit (EmitContext ec)
2491 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2497 // Unresolved type name expressions
2499 public abstract class ATypeNameExpression : FullNamedExpression
2502 protected TypeArguments targs;
2504 protected ATypeNameExpression (string name, Location l)
2510 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2517 protected ATypeNameExpression (string name, int arity, Location l)
2518 : this (name, new UnboundTypeArguments (arity), l)
2524 protected int Arity {
2526 return targs == null ? 0 : targs.Count;
2530 public bool HasTypeArguments {
2532 return targs != null && !targs.IsEmpty;
2536 public string Name {
2545 public TypeArguments TypeArguments {
2553 public override bool Equals (object obj)
2555 ATypeNameExpression atne = obj as ATypeNameExpression;
2556 return atne != null && atne.Name == Name &&
2557 (targs == null || targs.Equals (atne.targs));
2560 protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
2562 mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
2565 public override int GetHashCode ()
2567 return Name.GetHashCode ();
2570 // TODO: Move it to MemberCore
2571 public static string GetMemberType (MemberCore mc)
2577 if (mc is FieldBase)
2579 if (mc is MethodCore)
2581 if (mc is EnumMember)
2589 public override string GetSignatureForError ()
2591 if (targs != null) {
2592 return Name + "<" + targs.GetSignatureForError () + ">";
2598 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2602 /// SimpleName expressions are formed of a single word and only happen at the beginning
2603 /// of a dotted-name.
2605 public class SimpleName : ATypeNameExpression
2607 public SimpleName (string name, Location l)
2612 public SimpleName (string name, TypeArguments args, Location l)
2613 : base (name, args, l)
2617 public SimpleName (string name, int arity, Location l)
2618 : base (name, arity, l)
2622 public SimpleName GetMethodGroup ()
2624 return new SimpleName (Name, targs, loc);
2627 protected override Expression DoResolve (ResolveContext rc)
2629 return SimpleNameResolve (rc, null);
2632 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2634 return SimpleNameResolve (ec, right_side);
2637 public void Error_NameDoesNotExist (ResolveContext rc)
2639 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2642 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2644 if (ctx.CurrentType != null) {
2645 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2646 if (member != null) {
2647 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2652 var report = ctx.Module.Compiler.Report;
2654 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2655 if (retval != null) {
2656 report.SymbolRelatedToPreviousError (retval.Type);
2657 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2661 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2662 if (retval != null) {
2663 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2667 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2668 if (ns_candidates != null) {
2669 if (ctx is UsingAliasNamespace.AliasContext) {
2670 report.Error (246, loc,
2671 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2672 ns_candidates[0], Name);
2674 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2675 report.Error (246, loc,
2676 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2680 report.Error (246, loc,
2681 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2686 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2688 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2691 if (fne.Type != null && Arity > 0) {
2692 if (HasTypeArguments) {
2693 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2694 if (ct.ResolveAsType (mc) == null)
2700 if (!allowUnboundTypeArguments)
2701 Error_OpenGenericTypeIsNotAllowed (mc);
2703 return new GenericOpenTypeExpr (fne.Type, loc);
2707 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2709 if (!(fne is NamespaceExpression))
2713 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2714 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2715 mc.Module.Compiler.Report.Error (1980, Location,
2716 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2717 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2720 fne = new DynamicTypeExpr (loc);
2721 fne.ResolveAsType (mc);
2727 Error_TypeOrNamespaceNotFound (mc);
2731 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2733 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2736 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2738 int lookup_arity = Arity;
2739 bool errorMode = false;
2741 Block current_block = rc.CurrentBlock;
2742 INamedBlockVariable variable = null;
2743 bool variable_found = false;
2747 // Stage 1: binding to local variables or parameters
2749 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2751 if (current_block != null && lookup_arity == 0) {
2752 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2753 if (!variable.IsDeclared) {
2754 // We found local name in accessible block but it's not
2755 // initialized yet, maybe the user wanted to bind to something else
2757 variable_found = true;
2759 e = variable.CreateReferenceExpression (rc, loc);
2762 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2771 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2773 TypeSpec member_type = rc.CurrentType;
2774 for (; member_type != null; member_type = member_type.DeclaringType) {
2775 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2779 var me = e as MemberExpr;
2781 // The name matches a type, defer to ResolveAsTypeStep
2789 if (variable != null) {
2790 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2791 rc.Report.Error (844, loc,
2792 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2793 Name, me.GetSignatureForError ());
2797 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2798 // Leave it to overload resolution to report correct error
2800 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2801 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2804 // LAMESPEC: again, ignores InvocableOnly
2805 if (variable != null) {
2806 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2807 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2811 // MemberLookup does not check accessors availability, this is actually needed for properties only
2813 var pe = me as PropertyExpr;
2816 // Break as there is no other overload available anyway
2817 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2818 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2821 pe.Getter = pe.PropertyInfo.Get;
2823 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2826 pe.Setter = pe.PropertyInfo.Set;
2831 // TODO: It's used by EventExpr -> FieldExpr transformation only
2832 // TODO: Should go to MemberAccess
2833 me = me.ResolveMemberAccess (rc, null, null);
2837 me.SetTypeArguments (rc, targs);
2844 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2846 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2847 if (IsPossibleTypeOrNamespace (rc)) {
2848 if (variable != null) {
2849 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2850 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2853 return ResolveAsTypeOrNamespace (rc, false);
2857 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2861 mg.SetTypeArguments (rc, targs);
2866 if (Name == "nameof")
2867 return new NameOf (this);
2870 if (variable_found) {
2871 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2874 var tparams = rc.CurrentTypeParameters;
2875 if (tparams != null) {
2876 if (tparams.Find (Name) != null) {
2877 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2882 var ct = rc.CurrentType;
2884 if (ct.MemberDefinition.TypeParametersCount > 0) {
2885 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2886 if (ctp.Name == Name) {
2887 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2893 ct = ct.DeclaringType;
2894 } while (ct != null);
2897 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2898 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2900 rc.Report.SymbolRelatedToPreviousError (e.Type);
2901 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2905 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2907 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2908 return ErrorExpression.Instance;
2912 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2914 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2915 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2919 if (e is TypeExpr) {
2920 // TypeExpression does not have correct location
2921 if (e is TypeExpression)
2922 e = new TypeExpression (e.Type, loc);
2928 Error_NameDoesNotExist (rc);
2931 return ErrorExpression.Instance;
2934 if (rc.Module.Evaluator != null) {
2935 var fi = rc.Module.Evaluator.LookupField (Name);
2937 return new FieldExpr (fi.Item1, loc);
2945 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2947 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2952 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2953 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2957 if (right_side != null) {
2958 e = e.ResolveLValue (ec, right_side);
2966 public override object Accept (StructuralVisitor visitor)
2968 return visitor.Visit (this);
2973 /// Represents a namespace or a type. The name of the class was inspired by
2974 /// section 10.8.1 (Fully Qualified Names).
2976 public abstract class FullNamedExpression : Expression
2978 protected override void CloneTo (CloneContext clonectx, Expression target)
2980 // Do nothing, most unresolved type expressions cannot be
2981 // resolved to different type
2984 public override bool ContainsEmitWithAwait ()
2989 public override Expression CreateExpressionTree (ResolveContext ec)
2991 throw new NotSupportedException ("ET");
2994 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
2997 // This is used to resolve the expression as a type, a null
2998 // value will be returned if the expression is not a type
3001 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3003 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3008 TypeExpr te = fne as TypeExpr;
3010 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3018 var dep = type.GetMissingDependencies ();
3020 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3023 if (type.Kind == MemberKind.Void) {
3024 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3028 // Obsolete checks cannot be done when resolving base context as they
3029 // require type dependencies to be set but we are in process of resolving them
3031 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3032 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3033 if (obsolete_attr != null && !mc.IsObsolete) {
3034 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3042 public override void Emit (EmitContext ec)
3044 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3045 GetSignatureForError ());
3050 /// Expression that evaluates to a type
3052 public abstract class TypeExpr : FullNamedExpression
3054 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3060 protected sealed override Expression DoResolve (ResolveContext ec)
3066 public override bool Equals (object obj)
3068 TypeExpr tobj = obj as TypeExpr;
3072 return Type == tobj.Type;
3075 public override int GetHashCode ()
3077 return Type.GetHashCode ();
3082 /// Fully resolved Expression that already evaluated to a type
3084 public class TypeExpression : TypeExpr
3086 public TypeExpression (TypeSpec t, Location l)
3089 eclass = ExprClass.Type;
3093 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3099 public class NamespaceExpression : FullNamedExpression
3101 readonly Namespace ns;
3103 public NamespaceExpression (Namespace ns, Location loc)
3106 this.Type = InternalType.Namespace;
3107 this.eclass = ExprClass.Namespace;
3111 public Namespace Namespace {
3117 protected override Expression DoResolve (ResolveContext rc)
3119 throw new NotImplementedException ();
3122 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3127 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3129 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3130 if (retval != null) {
3131 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3132 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3136 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3137 if (retval != null) {
3138 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3143 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3144 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3148 string assembly = null;
3149 string possible_name = Namespace.GetSignatureForError () + "." + name;
3151 // Only assembly unique name should be added
3152 switch (possible_name) {
3153 case "System.Drawing":
3154 case "System.Web.Services":
3157 case "System.Configuration":
3158 case "System.Data.Services":
3159 case "System.DirectoryServices":
3161 case "System.Net.Http":
3162 case "System.Numerics":
3163 case "System.Runtime.Caching":
3164 case "System.ServiceModel":
3165 case "System.Transactions":
3166 case "System.Web.Routing":
3167 case "System.Xml.Linq":
3169 assembly = possible_name;
3173 case "System.Linq.Expressions":
3174 assembly = "System.Core";
3177 case "System.Windows.Forms":
3178 case "System.Windows.Forms.Layout":
3179 assembly = "System.Windows.Forms";
3183 assembly = assembly == null ? "an" : "`" + assembly + "'";
3185 if (Namespace is GlobalRootNamespace) {
3186 ctx.Module.Compiler.Report.Error (400, loc,
3187 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3190 ctx.Module.Compiler.Report.Error (234, loc,
3191 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3192 name, GetSignatureForError (), assembly);
3196 public override string GetSignatureForError ()
3198 return ns.GetSignatureForError ();
3201 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3203 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3208 /// This class denotes an expression which evaluates to a member
3209 /// of a struct or a class.
3211 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3213 protected bool conditional_access_receiver;
3216 // An instance expression associated with this member, if it's a
3217 // non-static member
3219 public Expression InstanceExpression;
3222 /// The name of this member.
3224 public abstract string Name {
3229 // When base.member is used
3231 public bool IsBase {
3232 get { return InstanceExpression is BaseThis; }
3236 /// Whether this is an instance member.
3238 public abstract bool IsInstance {
3243 /// Whether this is a static member.
3245 public abstract bool IsStatic {
3249 public abstract string KindName {
3253 public bool ConditionalAccess { get; set; }
3255 protected abstract TypeSpec DeclaringType {
3259 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3261 return InstanceExpression.Type;
3266 // Converts best base candidate for virtual method starting from QueriedBaseType
3268 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3271 // Only when base.member is used and method is virtual
3277 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3278 // means for base.member access we have to find the closest match after we found best candidate
3280 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3282 // The method could already be what we are looking for
3284 TypeSpec[] targs = null;
3285 if (method.DeclaringType != InstanceExpression.Type) {
3287 // Candidate can have inflated MVAR parameters and we need to find
3288 // base match for original definition not inflated parameter types
3290 var parameters = method.Parameters;
3291 if (method.Arity > 0) {
3292 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3293 var inflated = method.DeclaringType as InflatedTypeSpec;
3294 if (inflated != null) {
3295 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3299 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3300 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3301 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3302 if (base_override.IsGeneric)
3303 targs = method.TypeArguments;
3305 method = base_override;
3310 // When base access is used inside anonymous method/iterator/etc we need to
3311 // get back to the context of original type. We do it by emiting proxy
3312 // method in original class and rewriting base call to this compiler
3313 // generated method call which does the actual base invocation. This may
3314 // introduce redundant storey but with `this' only but it's tricky to avoid
3315 // at this stage as we don't know what expressions follow base
3317 if (rc.CurrentAnonymousMethod != null) {
3318 if (targs == null && method.IsGeneric) {
3319 targs = method.TypeArguments;
3320 method = method.GetGenericMethodDefinition ();
3323 if (method.Parameters.HasArglist)
3324 throw new NotImplementedException ("__arglist base call proxy");
3326 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3328 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3329 // get/set member expressions second call would fail to proxy because left expression
3330 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3331 // FIXME: The async check is another hack but will probably fail with mutators
3332 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3333 InstanceExpression = new This (loc).Resolve (rc);
3337 method = method.MakeGenericMethod (rc, targs);
3341 // Only base will allow this invocation to happen.
3343 if (method.IsAbstract) {
3344 rc.Report.SymbolRelatedToPreviousError (method);
3345 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3351 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3353 if (InstanceExpression == null)
3356 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3357 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3358 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3363 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3365 if (InstanceExpression == null)
3368 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3371 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3373 var ct = rc.CurrentType;
3374 if (ct == qualifier)
3377 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3380 qualifier = qualifier.GetDefinition ();
3381 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3388 public override bool ContainsEmitWithAwait ()
3390 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3393 public override bool HasConditionalAccess ()
3395 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3398 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3401 type = type.GetDefinition ();
3403 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3406 type = type.DeclaringType;
3407 } while (type != null);
3412 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3414 if (InstanceExpression != null) {
3415 InstanceExpression = InstanceExpression.Resolve (rc);
3416 CheckProtectedMemberAccess (rc, member);
3419 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3420 UnsafeError (rc, loc);
3423 var dep = member.GetMissingDependencies ();
3425 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3428 if (!rc.IsObsolete) {
3429 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3431 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3434 if (!(member is FieldSpec))
3435 member.MemberDefinition.SetIsUsed ();
3438 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3440 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3443 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3445 rc.Report.SymbolRelatedToPreviousError (member);
3446 rc.Report.Error (1540, loc,
3447 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3448 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3451 public override void FlowAnalysis (FlowAnalysisContext fc)
3453 if (InstanceExpression != null) {
3454 InstanceExpression.FlowAnalysis (fc);
3456 if (ConditionalAccess) {
3457 fc.BranchConditionalAccessDefiniteAssignment ();
3462 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3464 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3465 if (HasConditionalAccess ()) {
3466 conditional_access_receiver = true;
3467 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3472 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3474 if (!ResolveInstanceExpressionCore (rc, rhs))
3478 // Check intermediate value modification which won't have any effect
3480 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3481 var fexpr = InstanceExpression as FieldExpr;
3482 if (fexpr != null) {
3483 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3486 if (fexpr.IsStatic) {
3487 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3488 fexpr.GetSignatureForError ());
3490 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3491 fexpr.GetSignatureForError ());
3497 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3498 if (rc.CurrentInitializerVariable != null) {
3499 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3500 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3502 rc.Report.Error (1612, loc,
3503 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3504 InstanceExpression.GetSignatureForError ());
3510 var lvr = InstanceExpression as LocalVariableReference;
3513 if (!lvr.local_info.IsReadonly)
3516 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3517 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3524 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3527 if (InstanceExpression != null) {
3528 if (InstanceExpression is TypeExpr) {
3529 var t = InstanceExpression.Type;
3531 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3532 if (oa != null && !rc.IsObsolete) {
3533 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3536 t = t.DeclaringType;
3537 } while (t != null);
3539 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3540 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3541 rc.Report.Error (176, loc,
3542 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3543 GetSignatureForError ());
3547 InstanceExpression = null;
3553 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3554 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3555 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3556 rc.Report.Error (236, loc,
3557 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3558 GetSignatureForError ());
3560 var fe = this as FieldExpr;
3561 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3562 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3563 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3565 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3569 rc.Report.Error (120, loc,
3570 "An object reference is required to access non-static member `{0}'",
3571 GetSignatureForError ());
3575 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3579 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3580 rc.Report.Error (38, loc,
3581 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3582 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3585 InstanceExpression = new This (loc).Resolve (rc);
3589 var me = InstanceExpression as MemberExpr;
3591 me.ResolveInstanceExpressionCore (rc, rhs);
3593 var fe = me as FieldExpr;
3594 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3595 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3596 rc.Report.Warning (1690, 1, loc,
3597 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3598 me.GetSignatureForError ());
3605 // Additional checks for l-value member access
3608 if (InstanceExpression is UnboxCast) {
3609 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3616 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3618 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3619 ec.Report.Warning (1720, 1, left.Location,
3620 "Expression will always cause a `{0}'", "System.NullReferenceException");
3623 InstanceExpression = left;
3627 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3629 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3630 inst.Emit (ec, ConditionalAccess);
3632 if (prepare_for_load)
3633 ec.Emit (OpCodes.Dup);
3636 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3639 public class ExtensionMethodCandidates
3641 readonly NamespaceContainer container;
3642 readonly IList<MethodSpec> methods;
3644 readonly IMemberContext context;
3646 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3648 this.context = context;
3649 this.methods = methods;
3650 this.container = nsContainer;
3651 this.index = lookupIndex;
3654 public NamespaceContainer Container {
3660 public IMemberContext Context {
3666 public int LookupIndex {
3672 public IList<MethodSpec> Methods {
3680 // Represents a group of extension method candidates for whole namespace
3682 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3684 ExtensionMethodCandidates candidates;
3685 public Expression ExtensionExpression;
3687 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3688 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3690 this.candidates = candidates;
3691 this.ExtensionExpression = extensionExpr;
3694 public override bool IsStatic {
3695 get { return true; }
3698 public override void FlowAnalysis (FlowAnalysisContext fc)
3700 if (ConditionalAccess) {
3701 fc.BranchConditionalAccessDefiniteAssignment ();
3706 // For extension methodgroup we are not looking for base members but parent
3707 // namespace extension methods
3709 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3711 // TODO: candidates are null only when doing error reporting, that's
3712 // incorrect. We have to discover same extension methods in error mode
3713 if (candidates == null)
3716 int arity = type_arguments == null ? 0 : type_arguments.Count;
3718 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3719 if (candidates == null)
3722 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3725 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3727 // We are already here
3731 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3733 if (arguments == null)
3734 arguments = new Arguments (1);
3736 ExtensionExpression = ExtensionExpression.Resolve (ec);
3737 if (ExtensionExpression == null)
3740 var cand = candidates;
3741 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3742 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3743 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3745 // Restore candidates in case we are running in probing mode
3748 // Store resolved argument and restore original arguments
3750 // Clean-up modified arguments for error reporting
3751 arguments.RemoveAt (0);
3755 var me = ExtensionExpression as MemberExpr;
3757 me.ResolveInstanceExpression (ec, null);
3758 var fe = me as FieldExpr;
3760 fe.Spec.MemberDefinition.SetIsUsed ();
3763 InstanceExpression = null;
3767 #region IErrorHandler Members
3769 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3774 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3776 rc.Report.SymbolRelatedToPreviousError (best);
3777 rc.Report.Error (1928, loc,
3778 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3779 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3782 rc.Report.Error (1929, loc,
3783 "Extension method instance type `{0}' cannot be converted to `{1}'",
3784 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3790 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3795 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3804 /// MethodGroupExpr represents a group of method candidates which
3805 /// can be resolved to the best method overload
3807 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3809 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3811 protected IList<MemberSpec> Methods;
3812 MethodSpec best_candidate;
3813 TypeSpec best_candidate_return;
3814 protected TypeArguments type_arguments;
3816 SimpleName simple_name;
3817 protected TypeSpec queried_type;
3819 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3823 this.type = InternalType.MethodGroup;
3825 eclass = ExprClass.MethodGroup;
3826 queried_type = type;
3829 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3830 : this (new MemberSpec[] { m }, type, loc)
3836 public MethodSpec BestCandidate {
3838 return best_candidate;
3842 public TypeSpec BestCandidateReturnType {
3844 return best_candidate_return;
3848 public IList<MemberSpec> Candidates {
3854 protected override TypeSpec DeclaringType {
3856 return queried_type;
3860 public bool IsConditionallyExcluded {
3862 return Methods == Excluded;
3866 public override bool IsInstance {
3868 if (best_candidate != null)
3869 return !best_candidate.IsStatic;
3875 public override bool IsSideEffectFree {
3877 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3881 public override bool IsStatic {
3883 if (best_candidate != null)
3884 return best_candidate.IsStatic;
3890 public override string KindName {
3891 get { return "method"; }
3894 public override string Name {
3896 if (best_candidate != null)
3897 return best_candidate.Name;
3900 return Methods.First ().Name;
3907 // When best candidate is already know this factory can be used
3908 // to avoid expensive overload resolution to be called
3910 // NOTE: InstanceExpression has to be set manually
3912 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3914 return new MethodGroupExpr (best, queriedType, loc) {
3915 best_candidate = best,
3916 best_candidate_return = best.ReturnType
3920 public override string GetSignatureForError ()
3922 if (best_candidate != null)
3923 return best_candidate.GetSignatureForError ();
3925 return Methods.First ().GetSignatureForError ();
3928 public override Expression CreateExpressionTree (ResolveContext ec)
3930 if (best_candidate == null) {
3931 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3935 if (IsConditionallyExcluded)
3936 ec.Report.Error (765, loc,
3937 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3939 if (ConditionalAccess)
3940 Error_NullShortCircuitInsideExpressionTree (ec);
3942 return new TypeOfMethod (best_candidate, loc);
3945 protected override Expression DoResolve (ResolveContext ec)
3947 this.eclass = ExprClass.MethodGroup;
3949 if (InstanceExpression != null) {
3950 InstanceExpression = InstanceExpression.Resolve (ec);
3951 if (InstanceExpression == null)
3958 public override void Emit (EmitContext ec)
3960 throw new NotSupportedException ();
3963 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3965 var call = new CallEmitter ();
3966 call.InstanceExpression = InstanceExpression;
3967 call.ConditionalAccess = ConditionalAccess;
3970 call.EmitStatement (ec, best_candidate, arguments, loc);
3972 call.Emit (ec, best_candidate, arguments, loc);
3975 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
3977 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
3978 Statement = statement
3981 EmitCall (ec, arguments, statement);
3983 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
3986 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3988 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3989 Name, target.GetSignatureForError ());
3992 public static bool IsExtensionMethodArgument (Expression expr)
3995 // LAMESPEC: No details about which expressions are not allowed
3997 return !(expr is TypeExpr) && !(expr is BaseThis);
4001 /// Find the Applicable Function Members (7.4.2.1)
4003 /// me: Method Group expression with the members to select.
4004 /// it might contain constructors or methods (or anything
4005 /// that maps to a method).
4007 /// Arguments: ArrayList containing resolved Argument objects.
4009 /// loc: The location if we want an error to be reported, or a Null
4010 /// location for "probing" purposes.
4012 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4013 /// that is the best match of me on Arguments.
4016 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4018 // TODO: causes issues with probing mode, remove explicit Kind check
4019 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4022 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4023 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4024 r.BaseMembersProvider = this;
4025 r.InstanceQualifier = this;
4028 if (cerrors != null)
4029 r.CustomErrors = cerrors;
4031 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4032 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4033 if (best_candidate == null) {
4034 if (!r.BestCandidateIsDynamic)
4037 if (simple_name != null && ec.IsStatic)
4038 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4043 // Overload resolver had to create a new method group, all checks bellow have already been executed
4044 if (r.BestCandidateNewMethodGroup != null)
4045 return r.BestCandidateNewMethodGroup;
4047 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4048 if (InstanceExpression != null) {
4049 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4050 InstanceExpression = null;
4052 if (simple_name != null && best_candidate.IsStatic) {
4053 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4056 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4060 ResolveInstanceExpression (ec, null);
4063 var base_override = CandidateToBaseOverride (ec, best_candidate);
4064 if (base_override == best_candidate) {
4065 best_candidate_return = r.BestCandidateReturnType;
4067 best_candidate = base_override;
4068 best_candidate_return = best_candidate.ReturnType;
4071 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4072 ConstraintChecker cc = new ConstraintChecker (ec);
4073 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4077 // Additional check for possible imported base override method which
4078 // could not be done during IsOverrideMethodBaseTypeAccessible
4080 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4081 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4082 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4083 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4086 // Speed up the check by not doing it on disallowed targets
4087 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4093 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4095 var fe = left as FieldExpr;
4098 // Using method-group on struct fields makes the struct assigned. I am not sure
4099 // why but that's what .net does
4101 fe.Spec.MemberDefinition.SetIsAssigned ();
4104 simple_name = original;
4105 return base.ResolveMemberAccess (ec, left, original);
4108 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4110 type_arguments = ta;
4113 #region IBaseMembersProvider Members
4115 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4117 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4120 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4122 if (queried_type == member.DeclaringType)
4125 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4126 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4130 // Extension methods lookup after ordinary methods candidates failed to apply
4132 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4134 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4137 if (!IsExtensionMethodArgument (InstanceExpression))
4140 int arity = type_arguments == null ? 0 : type_arguments.Count;
4141 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4142 if (methods == null)
4145 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4146 emg.SetTypeArguments (rc, type_arguments);
4153 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4155 public ConstructorInstanceQualifier (TypeSpec type)
4158 InstanceType = type;
4161 public TypeSpec InstanceType { get; private set; }
4163 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4165 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4169 public struct OverloadResolver
4172 public enum Restrictions
4176 ProbingOnly = 1 << 1,
4177 CovariantDelegate = 1 << 2,
4178 NoBaseMembers = 1 << 3,
4179 BaseMembersIncluded = 1 << 4,
4180 GetEnumeratorLookup = 1 << 5
4183 public interface IBaseMembersProvider
4185 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4186 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4187 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4190 public interface IErrorHandler
4192 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4193 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4194 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4195 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4198 public interface IInstanceQualifier
4200 TypeSpec InstanceType { get; }
4201 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4204 sealed class NoBaseMembers : IBaseMembersProvider
4206 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4208 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4213 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4218 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4224 struct AmbiguousCandidate
4226 public readonly MemberSpec Member;
4227 public readonly bool Expanded;
4228 public readonly AParametersCollection Parameters;
4230 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4233 Parameters = parameters;
4234 Expanded = expanded;
4239 IList<MemberSpec> members;
4240 TypeArguments type_arguments;
4241 IBaseMembersProvider base_provider;
4242 IErrorHandler custom_errors;
4243 IInstanceQualifier instance_qualifier;
4244 Restrictions restrictions;
4245 MethodGroupExpr best_candidate_extension_group;
4246 TypeSpec best_candidate_return_type;
4248 SessionReportPrinter lambda_conv_msgs;
4250 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4251 : this (members, null, restrictions, loc)
4255 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4258 if (members == null || members.Count == 0)
4259 throw new ArgumentException ("empty members set");
4261 this.members = members;
4263 type_arguments = targs;
4264 this.restrictions = restrictions;
4265 if (IsDelegateInvoke)
4266 this.restrictions |= Restrictions.NoBaseMembers;
4268 base_provider = NoBaseMembers.Instance;
4273 public IBaseMembersProvider BaseMembersProvider {
4275 return base_provider;
4278 base_provider = value;
4282 public bool BestCandidateIsDynamic { get; set; }
4285 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4287 public MethodGroupExpr BestCandidateNewMethodGroup {
4289 return best_candidate_extension_group;
4294 // Return type can be different between best candidate and closest override
4296 public TypeSpec BestCandidateReturnType {
4298 return best_candidate_return_type;
4302 public IErrorHandler CustomErrors {
4304 return custom_errors;
4307 custom_errors = value;
4311 TypeSpec DelegateType {
4313 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4314 throw new InternalErrorException ("Not running in delegate mode", loc);
4316 return members [0].DeclaringType;
4320 public IInstanceQualifier InstanceQualifier {
4322 return instance_qualifier;
4325 instance_qualifier = value;
4329 bool IsProbingOnly {
4331 return (restrictions & Restrictions.ProbingOnly) != 0;
4335 bool IsDelegateInvoke {
4337 return (restrictions & Restrictions.DelegateInvoke) != 0;
4344 // 7.4.3.3 Better conversion from expression
4345 // Returns : 1 if a->p is better,
4346 // 2 if a->q is better,
4347 // 0 if neither is better
4349 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4351 TypeSpec argument_type = a.Type;
4354 // If argument is an anonymous function
4356 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4358 // p and q are delegate types or expression tree types
4360 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4361 if (q.MemberDefinition != p.MemberDefinition) {
4366 // Uwrap delegate from Expression<T>
4368 q = TypeManager.GetTypeArguments (q)[0];
4369 p = TypeManager.GetTypeArguments (p)[0];
4372 var p_m = Delegate.GetInvokeMethod (p);
4373 var q_m = Delegate.GetInvokeMethod (q);
4376 // With identical parameter lists
4378 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4386 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4388 if (p.Kind == MemberKind.Void) {
4389 return q.Kind != MemberKind.Void ? 2 : 0;
4393 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4395 if (q.Kind == MemberKind.Void) {
4396 return p.Kind != MemberKind.Void ? 1: 0;
4399 var am = (AnonymousMethodExpression) a.Expr;
4402 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4403 // better conversion is performed between underlying types Y1 and Y2
4405 if (p.IsGenericTask || q.IsGenericTask) {
4406 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4407 q = q.TypeArguments[0];
4408 p = p.TypeArguments[0];
4414 // An inferred return type X exists for E in the context of that parameter list, and
4415 // the conversion from X to Y1 is better than the conversion from X to Y2
4417 argument_type = am.InferReturnType (ec, null, orig_q);
4418 if (argument_type == null) {
4419 // TODO: Can this be hit?
4423 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4424 argument_type = ec.BuiltinTypes.Object;
4428 if (argument_type == p)
4431 if (argument_type == q)
4435 // The parameters are identicial and return type is not void, use better type conversion
4436 // on return type to determine better one
4438 return BetterTypeConversion (ec, p, q);
4442 // 7.4.3.4 Better conversion from type
4444 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4446 if (p == null || q == null)
4447 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4449 switch (p.BuiltinType) {
4450 case BuiltinTypeSpec.Type.Int:
4451 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4454 case BuiltinTypeSpec.Type.Long:
4455 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4458 case BuiltinTypeSpec.Type.SByte:
4459 switch (q.BuiltinType) {
4460 case BuiltinTypeSpec.Type.Byte:
4461 case BuiltinTypeSpec.Type.UShort:
4462 case BuiltinTypeSpec.Type.UInt:
4463 case BuiltinTypeSpec.Type.ULong:
4467 case BuiltinTypeSpec.Type.Short:
4468 switch (q.BuiltinType) {
4469 case BuiltinTypeSpec.Type.UShort:
4470 case BuiltinTypeSpec.Type.UInt:
4471 case BuiltinTypeSpec.Type.ULong:
4475 case BuiltinTypeSpec.Type.Dynamic:
4476 // Dynamic is never better
4480 switch (q.BuiltinType) {
4481 case BuiltinTypeSpec.Type.Int:
4482 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4485 case BuiltinTypeSpec.Type.Long:
4486 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4489 case BuiltinTypeSpec.Type.SByte:
4490 switch (p.BuiltinType) {
4491 case BuiltinTypeSpec.Type.Byte:
4492 case BuiltinTypeSpec.Type.UShort:
4493 case BuiltinTypeSpec.Type.UInt:
4494 case BuiltinTypeSpec.Type.ULong:
4498 case BuiltinTypeSpec.Type.Short:
4499 switch (p.BuiltinType) {
4500 case BuiltinTypeSpec.Type.UShort:
4501 case BuiltinTypeSpec.Type.UInt:
4502 case BuiltinTypeSpec.Type.ULong:
4506 case BuiltinTypeSpec.Type.Dynamic:
4507 // Dynamic is never better
4511 // FIXME: handle lifted operators
4513 // TODO: this is expensive
4514 Expression p_tmp = new EmptyExpression (p);
4515 Expression q_tmp = new EmptyExpression (q);
4517 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4518 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4520 if (p_to_q && !q_to_p)
4523 if (q_to_p && !p_to_q)
4530 /// Determines "Better function" between candidate
4531 /// and the current best match
4534 /// Returns a boolean indicating :
4535 /// false if candidate ain't better
4536 /// true if candidate is better than the current best match
4538 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4539 MemberSpec best, AParametersCollection bparam, bool best_params)
4541 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4542 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4544 bool better_at_least_one = false;
4545 bool are_equivalent = true;
4546 int args_count = args == null ? 0 : args.Count;
4550 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4553 // Default arguments are ignored for better decision
4554 if (a.IsDefaultArgument)
4558 // When comparing named argument the parameter type index has to be looked up
4559 // in original parameter set (override version for virtual members)
4561 NamedArgument na = a as NamedArgument;
4563 int idx = cparam.GetParameterIndexByName (na.Name);
4564 ct = candidate_pd.Types[idx];
4565 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4566 ct = TypeManager.GetElementType (ct);
4568 idx = bparam.GetParameterIndexByName (na.Name);
4569 bt = best_pd.Types[idx];
4570 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4571 bt = TypeManager.GetElementType (bt);
4573 ct = candidate_pd.Types[c_idx];
4574 bt = best_pd.Types[b_idx];
4576 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4577 ct = TypeManager.GetElementType (ct);
4581 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4582 bt = TypeManager.GetElementType (bt);
4587 if (TypeSpecComparer.IsEqual (ct, bt))
4590 are_equivalent = false;
4591 int result = BetterExpressionConversion (ec, a, ct, bt);
4593 // for each argument, the conversion to 'ct' should be no worse than
4594 // the conversion to 'bt'.
4598 // for at least one argument, the conversion to 'ct' should be better than
4599 // the conversion to 'bt'.
4601 better_at_least_one = true;
4604 if (better_at_least_one)
4608 // Tie-breaking rules are applied only for equivalent parameter types
4610 if (!are_equivalent)
4614 // If candidate is applicable in its normal form and best has a params array and is applicable
4615 // only in its expanded form, then candidate is better
4617 if (candidate_params != best_params)
4618 return !candidate_params;
4621 // We have not reached end of parameters list due to params or used default parameters
4623 while (j < candidate_pd.Count && j < best_pd.Count) {
4624 var cand_param = candidate_pd.FixedParameters [j];
4625 var best_param = best_pd.FixedParameters [j];
4627 if (candidate_pd.Count == best_pd.Count) {
4631 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4632 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4634 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4635 return cand_param.HasDefaultValue;
4637 if (cand_param.HasDefaultValue) {
4643 // Neither is better when not all arguments are provided
4645 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4646 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4647 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4649 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4656 if (candidate_pd.Count != best_pd.Count)
4657 return candidate_pd.Count < best_pd.Count;
4660 // One is a non-generic method and second is a generic method, then non-generic is better
4662 if (best.IsGeneric != candidate.IsGeneric)
4663 return best.IsGeneric;
4666 // Both methods have the same number of parameters, and the parameters have equal types
4667 // Pick the "more specific" signature using rules over original (non-inflated) types
4669 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4670 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4672 bool specific_at_least_once = false;
4673 for (j = 0; j < args_count; ++j) {
4674 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4676 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4677 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4679 ct = candidate_def_pd.Types[j];
4680 bt = best_def_pd.Types[j];
4685 TypeSpec specific = MoreSpecific (ct, bt);
4689 specific_at_least_once = true;
4692 if (specific_at_least_once)
4698 static bool CheckInflatedArguments (MethodSpec ms)
4700 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4703 // Setup constraint checker for probing only
4704 ConstraintChecker cc = new ConstraintChecker (null);
4706 var mp = ms.Parameters.Types;
4707 for (int i = 0; i < mp.Length; ++i) {
4708 var type = mp[i] as InflatedTypeSpec;
4712 var targs = type.TypeArguments;
4713 if (targs.Length == 0)
4716 // TODO: Checking inflated MVAR arguments should be enough
4717 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4724 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4726 rc.Report.Error (1729, loc,
4727 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4728 type.GetSignatureForError (), argCount.ToString ());
4732 // Determines if the candidate method is applicable to the given set of arguments
4733 // There could be two different set of parameters for same candidate where one
4734 // is the closest override for default values and named arguments checks and second
4735 // one being the virtual base for the parameter types and modifiers.
4737 // A return value rates candidate method compatibility,
4739 // 0 = the best, int.MaxValue = the worst
4741 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)
4744 // Each step has allocated 10 values, it can overflow for
4745 // more than 10 arguments but that's ok as it's used for
4746 // better error reporting only
4748 const int ArgumentCountMismatch = 1000000000;
4749 const int NamedArgumentsMismatch = 100000000;
4750 const int DefaultArgumentMismatch = 10000000;
4751 const int UnexpectedTypeArguments = 1000000;
4752 const int TypeArgumentsMismatch = 100000;
4753 const int InflatedTypesMismatch = 10000;
4755 // Parameters of most-derived type used mainly for named and optional parameters
4756 var pd = pm.Parameters;
4758 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4759 // params modifier instead of most-derived type
4760 var cpd = ((IParametersMember) candidate).Parameters;
4761 int param_count = pd.Count;
4762 int optional_count = 0;
4764 Arguments orig_args = arguments;
4766 if (arg_count != param_count) {
4768 // No arguments expansion when doing exact match for delegates
4770 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4771 for (int i = 0; i < pd.Count; ++i) {
4772 if (pd.FixedParameters[i].HasDefaultValue) {
4773 optional_count = pd.Count - i;
4779 if (optional_count != 0) {
4780 // Readjust expected number when params used
4781 if (cpd.HasParams) {
4783 if (arg_count < param_count)
4785 } else if (arg_count > param_count) {
4786 int args_gap = System.Math.Abs (arg_count - param_count);
4787 return ArgumentCountMismatch + args_gap;
4788 } else if (arg_count < param_count - optional_count) {
4789 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4790 return ArgumentCountMismatch + args_gap;
4792 } else if (arg_count != param_count) {
4793 int args_gap = System.Math.Abs (arg_count - param_count);
4795 return ArgumentCountMismatch + args_gap;
4796 if (arg_count < param_count - 1)
4797 return ArgumentCountMismatch + args_gap;
4800 // Resize to fit optional arguments
4801 if (optional_count != 0) {
4802 if (arguments == null) {
4803 arguments = new Arguments (optional_count);
4805 // Have to create a new container, so the next run can do same
4806 var resized = new Arguments (param_count);
4807 resized.AddRange (arguments);
4808 arguments = resized;
4811 for (int i = arg_count; i < param_count; ++i)
4812 arguments.Add (null);
4816 if (arg_count > 0) {
4818 // Shuffle named arguments to the right positions if there are any
4820 if (arguments[arg_count - 1] is NamedArgument) {
4821 arg_count = arguments.Count;
4823 for (int i = 0; i < arg_count; ++i) {
4824 bool arg_moved = false;
4826 NamedArgument na = arguments[i] as NamedArgument;
4830 int index = pd.GetParameterIndexByName (na.Name);
4832 // Named parameter not found
4834 return NamedArgumentsMismatch - i;
4836 // already reordered
4841 if (index >= param_count) {
4842 // When using parameters which should not be available to the user
4843 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4846 arguments.Add (null);
4850 if (index == arg_count)
4851 return NamedArgumentsMismatch - i - 1;
4853 temp = arguments [index];
4855 // The slot has been taken by positional argument
4856 if (temp != null && !(temp is NamedArgument))
4861 arguments = arguments.MarkOrderedArgument (na);
4865 if (arguments == orig_args) {
4866 arguments = new Arguments (orig_args.Count);
4867 arguments.AddRange (orig_args);
4870 arguments[index] = arguments[i];
4871 arguments[i] = temp;
4878 arg_count = arguments.Count;
4880 } else if (arguments != null) {
4881 arg_count = arguments.Count;
4885 // Don't do any expensive checks when the candidate cannot succeed
4887 if (arg_count != param_count && !cpd.HasParams)
4888 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4890 var dep = candidate.GetMissingDependencies ();
4892 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4897 // 1. Handle generic method using type arguments when specified or type inference
4900 var ms = candidate as MethodSpec;
4901 if (ms != null && ms.IsGeneric) {
4902 if (type_arguments != null) {
4903 var g_args_count = ms.Arity;
4904 if (g_args_count != type_arguments.Count)
4905 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4907 if (type_arguments.Arguments != null)
4908 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4911 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4912 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4913 // candidate was found use the set to report more details about what was wrong with lambda body.
4914 // The general idea is to distinguish between code errors and errors caused by
4915 // trial-and-error type inference
4917 if (lambda_conv_msgs == null) {
4918 for (int i = 0; i < arg_count; i++) {
4919 Argument a = arguments[i];
4923 var am = a.Expr as AnonymousMethodExpression;
4925 if (lambda_conv_msgs == null)
4926 lambda_conv_msgs = new SessionReportPrinter ();
4928 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4933 var ti = new TypeInference (arguments);
4934 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4937 return TypeArgumentsMismatch - ti.InferenceScore;
4940 // Clear any error messages when the result was success
4942 if (lambda_conv_msgs != null)
4943 lambda_conv_msgs.ClearSession ();
4945 if (i_args.Length != 0) {
4947 for (int i = 0; i < i_args.Length; ++i) {
4948 var ta = i_args [i];
4949 if (!ta.IsAccessible (ec))
4950 return TypeArgumentsMismatch - i;
4954 ms = ms.MakeGenericMethod (ec, i_args);
4959 // Type arguments constraints have to match for the method to be applicable
4961 if (!CheckInflatedArguments (ms)) {
4963 return InflatedTypesMismatch;
4967 // We have a generic return type and at same time the method is override which
4968 // means we have to also inflate override return type in case the candidate is
4969 // best candidate and override return type is different to base return type.
4971 // virtual Foo<T, object> with override Foo<T, dynamic>
4973 if (candidate != pm) {
4974 MethodSpec override_ms = (MethodSpec) pm;
4975 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4976 returnType = inflator.Inflate (returnType);
4978 returnType = ms.ReturnType;
4985 if (type_arguments != null)
4986 return UnexpectedTypeArguments;
4992 // 2. Each argument has to be implicitly convertible to method parameter
4994 Parameter.Modifier p_mod = 0;
4997 for (int i = 0; i < arg_count; i++) {
4998 Argument a = arguments[i];
5000 var fp = pd.FixedParameters[i];
5001 if (!fp.HasDefaultValue) {
5002 arguments = orig_args;
5003 return arg_count * 2 + 2;
5007 // Get the default value expression, we can use the same expression
5008 // if the type matches
5010 Expression e = fp.DefaultValue;
5012 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5014 // Restore for possible error reporting
5015 for (int ii = i; ii < arg_count; ++ii)
5016 arguments.RemoveAt (i);
5018 return (arg_count - i) * 2 + 1;
5022 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5024 // LAMESPEC: Attributes can be mixed together with build-in priority
5026 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5027 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5028 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5029 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5030 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5031 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5035 arguments[i] = new Argument (e, Argument.AType.Default);
5039 if (p_mod != Parameter.Modifier.PARAMS) {
5040 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5042 } else if (!params_expanded_form) {
5043 params_expanded_form = true;
5044 pt = ((ElementTypeSpec) pt).Element;
5050 if (!params_expanded_form) {
5051 if (a.IsExtensionType) {
5053 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
5055 // LAMESPEC: or implicit type parameter conversion
5058 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
5059 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
5060 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
5065 score = IsArgumentCompatible (ec, a, p_mod, pt);
5068 dynamicArgument = true;
5073 // It can be applicable in expanded form (when not doing exact match like for delegates)
5075 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5076 if (!params_expanded_form) {
5077 pt = ((ElementTypeSpec) pt).Element;
5081 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5084 params_expanded_form = true;
5085 dynamicArgument = true;
5086 } else if (score == 0 || arg_count > pd.Count) {
5087 params_expanded_form = true;
5092 if (params_expanded_form)
5094 return (arg_count - i) * 2 + score;
5099 // Restore original arguments for dynamic binder to keep the intention of original source code
5101 if (dynamicArgument)
5102 arguments = orig_args;
5107 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5109 if (e is Constant && e.Type == ptype)
5113 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5115 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5116 e = new MemberAccess (new MemberAccess (new MemberAccess (
5117 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5118 } else if (e is Constant) {
5120 // Handles int to int? conversions, DefaultParameterValue check
5122 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5126 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5129 return e.Resolve (ec);
5133 // Tests argument compatibility with the parameter
5134 // The possible return values are
5136 // 1 - modifier mismatch
5137 // 2 - type mismatch
5138 // -1 - dynamic binding required
5140 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5143 // Types have to be identical when ref or out modifer
5144 // is used and argument is not of dynamic type
5146 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5147 if (argument.Type != parameter) {
5149 // Do full equality check after quick path
5151 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
5153 // Using dynamic for ref/out parameter can still succeed at runtime
5155 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5162 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5164 // Using dynamic for ref/out parameter can still succeed at runtime
5166 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5173 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5177 // Use implicit conversion in all modes to return same candidates when the expression
5178 // is used as argument or delegate conversion
5180 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5181 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5188 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5190 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5192 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5195 var ac_p = p as ArrayContainer;
5197 var ac_q = q as ArrayContainer;
5201 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5202 if (specific == ac_p.Element)
5204 if (specific == ac_q.Element)
5206 } else if (p.IsGeneric && q.IsGeneric) {
5207 var pargs = TypeManager.GetTypeArguments (p);
5208 var qargs = TypeManager.GetTypeArguments (q);
5210 bool p_specific_at_least_once = false;
5211 bool q_specific_at_least_once = false;
5213 for (int i = 0; i < pargs.Length; i++) {
5214 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5215 if (specific == pargs[i])
5216 p_specific_at_least_once = true;
5217 if (specific == qargs[i])
5218 q_specific_at_least_once = true;
5221 if (p_specific_at_least_once && !q_specific_at_least_once)
5223 if (!p_specific_at_least_once && q_specific_at_least_once)
5231 // Find the best method from candidate list
5233 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5235 List<AmbiguousCandidate> ambiguous_candidates = null;
5237 MemberSpec best_candidate;
5238 Arguments best_candidate_args = null;
5239 bool best_candidate_params = false;
5240 bool best_candidate_dynamic = false;
5241 int best_candidate_rate;
5242 IParametersMember best_parameter_member = null;
5244 int args_count = args != null ? args.Count : 0;
5246 Arguments candidate_args = args;
5247 bool error_mode = false;
5248 MemberSpec invocable_member = null;
5251 best_candidate = null;
5252 best_candidate_rate = int.MaxValue;
5254 var type_members = members;
5256 for (int i = 0; i < type_members.Count; ++i) {
5257 var member = type_members[i];
5260 // Methods in a base class are not candidates if any method in a derived
5261 // class is applicable
5263 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5267 if (!member.IsAccessible (rc))
5270 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5273 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5274 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5279 IParametersMember pm = member as IParametersMember;
5282 // Will use it later to report ambiguity between best method and invocable member
5284 if (Invocation.IsMemberInvocable (member))
5285 invocable_member = member;
5291 // Overload resolution is looking for base member but using parameter names
5292 // and default values from the closest member. That means to do expensive lookup
5293 // for the closest override for virtual or abstract members
5295 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5296 var override_params = base_provider.GetOverrideMemberParameters (member);
5297 if (override_params != null)
5298 pm = override_params;
5302 // Check if the member candidate is applicable
5304 bool params_expanded_form = false;
5305 bool dynamic_argument = false;
5306 TypeSpec rt = pm.MemberType;
5307 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5309 if (lambda_conv_msgs != null)
5310 lambda_conv_msgs.EndSession ();
5313 // How does it score compare to others
5315 if (candidate_rate < best_candidate_rate) {
5317 // Fatal error (missing dependency), cannot continue
5318 if (candidate_rate < 0)
5321 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5322 // Only parameterless methods are considered
5324 best_candidate_rate = candidate_rate;
5325 best_candidate = member;
5326 best_candidate_args = candidate_args;
5327 best_candidate_params = params_expanded_form;
5328 best_candidate_dynamic = dynamic_argument;
5329 best_parameter_member = pm;
5330 best_candidate_return_type = rt;
5332 } else if (candidate_rate == 0) {
5334 // The member look is done per type for most operations but sometimes
5335 // it's not possible like for binary operators overload because they
5336 // are unioned between 2 sides
5338 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5339 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5344 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5346 // We pack all interface members into top level type which makes the overload resolution
5347 // more complicated for interfaces. We compensate it by removing methods with same
5348 // signature when building the cache hence this path should not really be hit often
5351 // interface IA { void Foo (int arg); }
5352 // interface IB : IA { void Foo (params int[] args); }
5354 // IB::Foo is the best overload when calling IB.Foo (1)
5357 if (ambiguous_candidates != null) {
5358 foreach (var amb_cand in ambiguous_candidates) {
5359 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5368 ambiguous_candidates = null;
5371 // Is the new candidate better
5372 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5376 best_candidate = member;
5377 best_candidate_args = candidate_args;
5378 best_candidate_params = params_expanded_form;
5379 best_candidate_dynamic = dynamic_argument;
5380 best_parameter_member = pm;
5381 best_candidate_return_type = rt;
5383 // It's not better but any other found later could be but we are not sure yet
5384 if (ambiguous_candidates == null)
5385 ambiguous_candidates = new List<AmbiguousCandidate> ();
5387 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5391 // Restore expanded arguments
5392 candidate_args = args;
5394 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5397 // We've found exact match
5399 if (best_candidate_rate == 0)
5403 // Try extension methods lookup when no ordinary method match was found and provider enables it
5406 var emg = base_provider.LookupExtensionMethod (rc);
5408 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5410 best_candidate_extension_group = emg;
5411 return (T) (MemberSpec) emg.BestCandidate;
5416 // Don't run expensive error reporting mode for probing
5423 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5426 lambda_conv_msgs = null;
5431 // No best member match found, report an error
5433 if (best_candidate_rate != 0 || error_mode) {
5434 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5438 if (best_candidate_dynamic) {
5439 if (args[0].IsExtensionType) {
5440 rc.Report.Error (1973, loc,
5441 "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",
5442 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5446 // Check type constraints only when explicit type arguments are used
5448 if (best_candidate.IsGeneric && type_arguments != null) {
5449 MethodSpec bc = best_candidate as MethodSpec;
5450 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5451 ConstraintChecker cc = new ConstraintChecker (rc);
5452 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5456 BestCandidateIsDynamic = true;
5461 // These flags indicates we are running delegate probing conversion. No need to
5462 // do more expensive checks
5464 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5465 return (T) best_candidate;
5467 if (ambiguous_candidates != null) {
5469 // Now check that there are no ambiguities i.e the selected method
5470 // should be better than all the others
5472 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5473 var candidate = ambiguous_candidates [ix];
5475 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5476 var ambiguous = candidate.Member;
5477 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5478 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5479 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5480 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5481 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5484 return (T) best_candidate;
5489 if (invocable_member != null && !IsProbingOnly) {
5490 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5491 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5492 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5493 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5497 // And now check if the arguments are all
5498 // compatible, perform conversions if
5499 // necessary etc. and return if everything is
5502 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5505 if (best_candidate == null)
5509 // Don't run possibly expensive checks in probing mode
5511 if (!IsProbingOnly && !rc.IsInProbingMode) {
5513 // Check ObsoleteAttribute on the best method
5515 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5516 if (oa != null && !rc.IsObsolete)
5517 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5519 best_candidate.MemberDefinition.SetIsUsed ();
5522 args = best_candidate_args;
5523 return (T) best_candidate;
5526 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5528 return ResolveMember<MethodSpec> (rc, ref args);
5531 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5532 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5534 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5537 if (a.Type == InternalType.ErrorType)
5540 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5541 ec.Report.SymbolRelatedToPreviousError (method);
5542 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5543 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5544 TypeManager.CSharpSignature (method));
5547 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5548 TypeManager.CSharpSignature (method));
5549 } else if (IsDelegateInvoke) {
5550 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5551 DelegateType.GetSignatureForError ());
5553 ec.Report.SymbolRelatedToPreviousError (method);
5554 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5555 method.GetSignatureForError ());
5558 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5560 string index = (idx + 1).ToString ();
5561 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5562 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5563 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5564 index, Parameter.GetModifierSignature (a.Modifier));
5566 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5567 index, Parameter.GetModifierSignature (mod));
5569 string p1 = a.GetSignatureForError ();
5570 string p2 = paramType.GetSignatureForError ();
5573 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5574 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5577 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5578 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5579 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5582 ec.Report.Error (1503, a.Expr.Location,
5583 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5588 // We have failed to find exact match so we return error info about the closest match
5590 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5592 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5593 int arg_count = args == null ? 0 : args.Count;
5595 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5596 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5597 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5601 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5606 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5607 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5608 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5612 // For candidates which match on parameters count report more details about incorrect arguments
5615 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5616 // Reject any inaccessible member
5617 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5618 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5619 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5623 var ms = best_candidate as MethodSpec;
5624 if (ms != null && ms.IsGeneric) {
5625 bool constr_ok = true;
5626 if (ms.TypeArguments != null)
5627 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5629 if (ta_count == 0 && ms.TypeArguments == null) {
5630 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5634 rc.Report.Error (411, loc,
5635 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5636 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5643 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5649 // We failed to find any method with correct argument count, report best candidate
5651 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5654 if (best_candidate.Kind == MemberKind.Constructor) {
5655 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5656 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5657 } else if (IsDelegateInvoke) {
5658 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5659 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5660 DelegateType.GetSignatureForError (), arg_count.ToString ());
5662 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5663 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5664 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5665 name, arg_count.ToString ());
5669 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5671 var p = ((IParametersMember)best_candidate).Parameters;
5676 for (int i = p.Count - 1; i != 0; --i) {
5677 var fp = p.FixedParameters [i];
5678 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5688 foreach (var arg in args) {
5689 var na = arg as NamedArgument;
5693 if (na.Name == name) {
5702 return args.Count + 1 == pm.Parameters.Count;
5705 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5707 var pd = pm.Parameters;
5708 var cpd = ((IParametersMember) member).Parameters;
5709 var ptypes = cpd.Types;
5711 Parameter.Modifier p_mod = 0;
5713 int a_idx = 0, a_pos = 0;
5715 ArrayInitializer params_initializers = null;
5716 bool has_unsafe_arg = pm.MemberType.IsPointer;
5717 int arg_count = args == null ? 0 : args.Count;
5719 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5724 if (p_mod != Parameter.Modifier.PARAMS) {
5725 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5727 has_unsafe_arg |= pt.IsPointer;
5729 if (p_mod == Parameter.Modifier.PARAMS) {
5730 if (chose_params_expanded) {
5731 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5732 pt = TypeManager.GetElementType (pt);
5738 // Types have to be identical when ref or out modifer is used
5740 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5741 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5744 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5750 NamedArgument na = a as NamedArgument;
5752 int name_index = pd.GetParameterIndexByName (na.Name);
5753 if (name_index < 0 || name_index >= pd.Count) {
5754 if (IsDelegateInvoke) {
5755 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5756 ec.Report.Error (1746, na.Location,
5757 "The delegate `{0}' does not contain a parameter named `{1}'",
5758 DelegateType.GetSignatureForError (), na.Name);
5760 ec.Report.SymbolRelatedToPreviousError (member);
5761 ec.Report.Error (1739, na.Location,
5762 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5763 TypeManager.CSharpSignature (member), na.Name);
5765 } else if (args[name_index] != a && args[name_index] != null) {
5766 if (IsDelegateInvoke)
5767 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5769 ec.Report.SymbolRelatedToPreviousError (member);
5771 ec.Report.Error (1744, na.Location,
5772 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5777 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5780 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5781 custom_errors.NoArgumentMatch (ec, member);
5786 if (a.IsExtensionType) {
5787 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5790 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5792 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5795 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5802 // Convert params arguments to an array initializer
5804 if (params_initializers != null) {
5805 // we choose to use 'a.Expr' rather than 'conv' so that
5806 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5807 params_initializers.Add (a.Expr);
5808 args.RemoveAt (a_idx--);
5814 // Update the argument with the implicit conversion
5818 if (a_idx != arg_count) {
5819 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5824 // Fill not provided arguments required by params modifier
5826 if (params_initializers == null && arg_count + 1 == pd.Count) {
5828 args = new Arguments (1);
5830 pt = ptypes[pd.Count - 1];
5831 pt = TypeManager.GetElementType (pt);
5832 has_unsafe_arg |= pt.IsPointer;
5833 params_initializers = new ArrayInitializer (0, loc);
5837 // Append an array argument with all params arguments
5839 if (params_initializers != null) {
5840 args.Add (new Argument (
5841 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5845 if (has_unsafe_arg && !ec.IsUnsafe) {
5846 Expression.UnsafeError (ec, loc);
5850 // We could infer inaccesible type arguments
5852 if (type_arguments == null && member.IsGeneric) {
5853 var ms = (MethodSpec) member;
5854 foreach (var ta in ms.TypeArguments) {
5855 if (!ta.IsAccessible (ec)) {
5856 ec.Report.SymbolRelatedToPreviousError (ta);
5857 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5867 public class ConstantExpr : MemberExpr
5869 readonly ConstSpec constant;
5871 public ConstantExpr (ConstSpec constant, Location loc)
5873 this.constant = constant;
5877 public override string Name {
5878 get { throw new NotImplementedException (); }
5881 public override string KindName {
5882 get { return "constant"; }
5885 public override bool IsInstance {
5886 get { return !IsStatic; }
5889 public override bool IsStatic {
5890 get { return true; }
5893 protected override TypeSpec DeclaringType {
5894 get { return constant.DeclaringType; }
5897 public override Expression CreateExpressionTree (ResolveContext ec)
5899 throw new NotSupportedException ("ET");
5902 protected override Expression DoResolve (ResolveContext rc)
5904 ResolveInstanceExpression (rc, null);
5905 DoBestMemberChecks (rc, constant);
5907 var c = constant.GetConstant (rc);
5909 // Creates reference expression to the constant value
5910 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5913 public override void Emit (EmitContext ec)
5915 throw new NotSupportedException ();
5918 public override string GetSignatureForError ()
5920 return constant.GetSignatureForError ();
5923 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5925 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5930 // Fully resolved expression that references a Field
5932 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5934 protected FieldSpec spec;
5935 VariableInfo variable_info;
5937 LocalTemporary temp;
5940 protected FieldExpr (Location l)
5945 public FieldExpr (FieldSpec spec, Location loc)
5950 type = spec.MemberType;
5953 public FieldExpr (FieldBase fi, Location l)
5960 public override string Name {
5966 public bool IsHoisted {
5968 IVariableReference hv = InstanceExpression as IVariableReference;
5969 return hv != null && hv.IsHoisted;
5973 public override bool IsInstance {
5975 return !spec.IsStatic;
5979 public override bool IsStatic {
5981 return spec.IsStatic;
5985 public override string KindName {
5986 get { return "field"; }
5989 public FieldSpec Spec {
5995 protected override TypeSpec DeclaringType {
5997 return spec.DeclaringType;
6001 public VariableInfo VariableInfo {
6003 return variable_info;
6009 public override string GetSignatureForError ()
6011 return spec.GetSignatureForError ();
6014 public bool IsMarshalByRefAccess (ResolveContext rc)
6016 // Checks possible ldflda of field access expression
6017 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6018 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6019 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6022 public void SetHasAddressTaken ()
6024 IVariableReference vr = InstanceExpression as IVariableReference;
6026 vr.SetHasAddressTaken ();
6030 protected override void CloneTo (CloneContext clonectx, Expression target)
6032 var t = (FieldExpr) target;
6034 if (InstanceExpression != null)
6035 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6038 public override Expression CreateExpressionTree (ResolveContext ec)
6040 if (ConditionalAccess) {
6041 Error_NullShortCircuitInsideExpressionTree (ec);
6044 return CreateExpressionTree (ec, true);
6047 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6050 Expression instance;
6052 if (InstanceExpression == null) {
6053 instance = new NullLiteral (loc);
6054 } else if (convertInstance) {
6055 instance = InstanceExpression.CreateExpressionTree (ec);
6057 args = new Arguments (1);
6058 args.Add (new Argument (InstanceExpression));
6059 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6062 args = Arguments.CreateForExpressionTree (ec, null,
6064 CreateTypeOfExpression ());
6066 return CreateExpressionFactoryCall (ec, "Field", args);
6069 public Expression CreateTypeOfExpression ()
6071 return new TypeOfField (spec, loc);
6074 protected override Expression DoResolve (ResolveContext ec)
6076 spec.MemberDefinition.SetIsUsed ();
6078 return DoResolve (ec, null);
6081 Expression DoResolve (ResolveContext ec, Expression rhs)
6083 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6086 ResolveConditionalAccessReceiver (ec);
6088 if (ResolveInstanceExpression (ec, rhs)) {
6089 // Resolve the field's instance expression while flow analysis is turned
6090 // off: when accessing a field "a.b", we must check whether the field
6091 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6093 if (lvalue_instance) {
6094 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6096 Expression right_side =
6097 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6099 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6101 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6104 if (InstanceExpression == null)
6108 DoBestMemberChecks (ec, spec);
6110 if (conditional_access_receiver)
6111 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6114 var fb = spec as FixedFieldSpec;
6115 IVariableReference var = InstanceExpression as IVariableReference;
6118 IFixedExpression fe = InstanceExpression as IFixedExpression;
6119 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6120 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6123 if (InstanceExpression.eclass != ExprClass.Variable) {
6124 ec.Report.SymbolRelatedToPreviousError (spec);
6125 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6126 TypeManager.GetFullNameSignature (spec));
6127 } else if (var != null && var.IsHoisted) {
6128 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6131 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6135 // Set flow-analysis variable info for struct member access. It will be check later
6136 // for precise error reporting
6138 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6139 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6142 if (ConditionalAccess) {
6143 if (conditional_access_receiver)
6144 type = LiftMemberType (ec, type);
6146 if (InstanceExpression.IsNull)
6147 return Constant.CreateConstantFromValue (type, null, loc);
6150 eclass = ExprClass.Variable;
6154 public void SetFieldAssigned (FlowAnalysisContext fc)
6159 bool lvalue_instance = spec.DeclaringType.IsStruct;
6160 if (lvalue_instance) {
6161 var var = InstanceExpression as IVariableReference;
6162 if (var != null && var.VariableInfo != null) {
6163 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6167 var fe = InstanceExpression as FieldExpr;
6169 Expression instance;
6172 instance = fe.InstanceExpression;
6173 var fe_instance = instance as FieldExpr;
6174 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6175 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6176 var var = InstanceExpression as IVariableReference;
6177 if (var != null && var.VariableInfo == null) {
6178 var var_inst = instance as IVariableReference;
6179 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6180 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6184 if (fe_instance != null) {
6193 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6194 instance.FlowAnalysis (fc);
6196 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6197 InstanceExpression.FlowAnalysis (fc);
6201 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6203 // The return value is always null. Returning a value simplifies calling code.
6205 if (right_side == EmptyExpression.OutAccess) {
6207 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6208 GetSignatureForError ());
6210 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6211 GetSignatureForError ());
6217 if (right_side == EmptyExpression.LValueMemberAccess) {
6218 // Already reported as CS1648/CS1650
6222 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6224 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6225 GetSignatureForError ());
6227 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6228 GetSignatureForError ());
6234 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6235 GetSignatureForError ());
6237 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6238 GetSignatureForError ());
6244 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6246 if (ConditionalAccess)
6247 throw new NotSupportedException ("null propagating operator assignment");
6249 if (spec is FixedFieldSpec) {
6250 // It could be much better error message but we want to be error compatible
6251 Error_ValueAssignment (ec, right_side);
6254 Expression e = DoResolve (ec, right_side);
6259 spec.MemberDefinition.SetIsAssigned ();
6261 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6262 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6263 ec.Report.Warning (420, 1, loc,
6264 "`{0}': A volatile field references will not be treated as volatile",
6265 spec.GetSignatureForError ());
6268 if (spec.IsReadOnly) {
6269 // InitOnly fields can only be assigned in constructors or initializers
6270 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6271 return Error_AssignToReadonly (ec, right_side);
6273 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6275 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6276 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6277 return Error_AssignToReadonly (ec, right_side);
6278 // static InitOnly fields cannot be assigned-to in an instance constructor
6279 if (IsStatic && !ec.IsStatic)
6280 return Error_AssignToReadonly (ec, right_side);
6281 // instance constructors can't modify InitOnly fields of other instances of the same type
6282 if (!IsStatic && !(InstanceExpression is This))
6283 return Error_AssignToReadonly (ec, right_side);
6287 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6288 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6289 ec.Report.Warning (197, 1, loc,
6290 "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",
6291 GetSignatureForError ());
6294 eclass = ExprClass.Variable;
6298 public override void FlowAnalysis (FlowAnalysisContext fc)
6300 var var = InstanceExpression as IVariableReference;
6302 var vi = var.VariableInfo;
6303 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6304 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6308 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6312 base.FlowAnalysis (fc);
6314 if (conditional_access_receiver)
6315 fc.ConditionalAccessEnd ();
6318 public override int GetHashCode ()
6320 return spec.GetHashCode ();
6323 public bool IsFixed {
6326 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6328 IVariableReference variable = InstanceExpression as IVariableReference;
6329 if (variable != null)
6330 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6332 IFixedExpression fe = InstanceExpression as IFixedExpression;
6333 return fe != null && fe.IsFixed;
6337 public override bool Equals (object obj)
6339 FieldExpr fe = obj as FieldExpr;
6343 if (spec != fe.spec)
6346 if (InstanceExpression == null || fe.InstanceExpression == null)
6349 return InstanceExpression.Equals (fe.InstanceExpression);
6352 public void Emit (EmitContext ec, bool leave_copy)
6354 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6358 ec.Emit (OpCodes.Volatile);
6360 ec.Emit (OpCodes.Ldsfld, spec);
6363 if (conditional_access_receiver)
6364 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6366 EmitInstance (ec, false);
6369 // Optimization for build-in types
6370 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6371 ec.EmitLoadFromPtr (type);
6373 var ff = spec as FixedFieldSpec;
6375 ec.Emit (OpCodes.Ldflda, spec);
6376 ec.Emit (OpCodes.Ldflda, ff.Element);
6379 ec.Emit (OpCodes.Volatile);
6381 ec.Emit (OpCodes.Ldfld, spec);
6385 if (conditional_access_receiver) {
6386 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6391 ec.Emit (OpCodes.Dup);
6393 temp = new LocalTemporary (this.Type);
6399 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6401 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6402 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6407 if (ConditionalAccess)
6408 throw new NotImplementedException ("null operator assignment");
6410 if (has_await_source)
6411 source = source.EmitToField (ec);
6413 EmitInstance (ec, prepared);
6418 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6419 ec.Emit (OpCodes.Dup);
6421 temp = new LocalTemporary (this.Type);
6426 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6427 ec.Emit (OpCodes.Volatile);
6429 spec.MemberDefinition.SetIsAssigned ();
6432 ec.Emit (OpCodes.Stsfld, spec);
6434 ec.Emit (OpCodes.Stfld, spec);
6436 if (ec.NotifyEvaluatorOnStore) {
6438 throw new NotImplementedException ("instance field write");
6441 ec.Emit (OpCodes.Dup);
6443 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6454 // Emits store to field with prepared values on stack
6456 public void EmitAssignFromStack (EmitContext ec)
6459 ec.Emit (OpCodes.Stsfld, spec);
6461 ec.Emit (OpCodes.Stfld, spec);
6465 public override void Emit (EmitContext ec)
6470 public override void EmitSideEffect (EmitContext ec)
6472 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6474 if (is_volatile) // || is_marshal_by_ref ())
6475 base.EmitSideEffect (ec);
6478 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6480 if ((mode & AddressOp.Store) != 0)
6481 spec.MemberDefinition.SetIsAssigned ();
6482 if ((mode & AddressOp.Load) != 0)
6483 spec.MemberDefinition.SetIsUsed ();
6486 // Handle initonly fields specially: make a copy and then
6487 // get the address of the copy.
6490 if (spec.IsReadOnly){
6492 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6504 var temp = ec.GetTemporaryLocal (type);
6505 ec.Emit (OpCodes.Stloc, temp);
6506 ec.Emit (OpCodes.Ldloca, temp);
6512 ec.Emit (OpCodes.Ldsflda, spec);
6515 EmitInstance (ec, false);
6516 ec.Emit (OpCodes.Ldflda, spec);
6520 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6522 return MakeExpression (ctx);
6525 public override SLE.Expression MakeExpression (BuilderContext ctx)
6528 return base.MakeExpression (ctx);
6530 return SLE.Expression.Field (
6531 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6532 spec.GetMetaInfo ());
6536 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6538 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6544 // Expression that evaluates to a Property.
6546 // This is not an LValue because we need to re-write the expression. We
6547 // can not take data from the stack and store it.
6549 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6551 Arguments arguments;
6553 public PropertyExpr (PropertySpec spec, Location l)
6556 best_candidate = spec;
6557 type = spec.MemberType;
6562 protected override Arguments Arguments {
6571 protected override TypeSpec DeclaringType {
6573 return best_candidate.DeclaringType;
6577 public override string Name {
6579 return best_candidate.Name;
6583 public override bool IsInstance {
6589 public override bool IsStatic {
6591 return best_candidate.IsStatic;
6595 public override string KindName {
6596 get { return "property"; }
6599 public PropertySpec PropertyInfo {
6601 return best_candidate;
6607 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6609 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6612 var args_count = arguments == null ? 0 : arguments.Count;
6613 if (args_count != body.Parameters.Count && args_count == 0)
6616 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6617 mg.InstanceExpression = InstanceExpression;
6622 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6624 return new PropertyExpr (spec, loc) {
6630 public override Expression CreateExpressionTree (ResolveContext ec)
6632 if (ConditionalAccess) {
6633 Error_NullShortCircuitInsideExpressionTree (ec);
6637 if (IsSingleDimensionalArrayLength ()) {
6638 args = new Arguments (1);
6639 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6640 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6643 args = new Arguments (2);
6644 if (InstanceExpression == null)
6645 args.Add (new Argument (new NullLiteral (loc)));
6647 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6648 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6649 return CreateExpressionFactoryCall (ec, "Property", args);
6652 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6654 DoResolveLValue (rc, null);
6655 return new TypeOfMethod (Setter, loc);
6658 public override string GetSignatureForError ()
6660 return best_candidate.GetSignatureForError ();
6663 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6666 return base.MakeExpression (ctx);
6668 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6672 public override SLE.Expression MakeExpression (BuilderContext ctx)
6675 return base.MakeExpression (ctx);
6677 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6681 void Error_PropertyNotValid (ResolveContext ec)
6683 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6684 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6685 GetSignatureForError ());
6688 bool IsSingleDimensionalArrayLength ()
6690 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6693 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6694 return ac != null && ac.Rank == 1;
6697 public override void Emit (EmitContext ec, bool leave_copy)
6700 // Special case: length of single dimension array property is turned into ldlen
6702 if (IsSingleDimensionalArrayLength ()) {
6703 if (conditional_access_receiver) {
6704 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6707 EmitInstance (ec, false);
6709 ec.Emit (OpCodes.Ldlen);
6710 ec.Emit (OpCodes.Conv_I4);
6712 if (conditional_access_receiver) {
6713 ec.CloseConditionalAccess (type);
6719 base.Emit (ec, leave_copy);
6722 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6725 LocalTemporary await_source_arg = null;
6727 if (isCompound && !(source is DynamicExpressionStatement)) {
6728 emitting_compound_assignment = true;
6731 if (has_await_arguments) {
6732 await_source_arg = new LocalTemporary (Type);
6733 await_source_arg.Store (ec);
6735 args = new Arguments (1);
6736 args.Add (new Argument (await_source_arg));
6739 temp = await_source_arg;
6742 has_await_arguments = false;
6747 ec.Emit (OpCodes.Dup);
6748 temp = new LocalTemporary (this.Type);
6753 args = arguments ?? new Arguments (1);
6757 temp = new LocalTemporary (this.Type);
6759 args.Add (new Argument (temp));
6761 args.Add (new Argument (source));
6765 emitting_compound_assignment = false;
6767 var call = new CallEmitter ();
6768 call.InstanceExpression = InstanceExpression;
6770 call.InstanceExpressionOnStack = true;
6772 if (ConditionalAccess) {
6773 call.ConditionalAccess = true;
6777 call.Emit (ec, Setter, args, loc);
6779 call.EmitStatement (ec, Setter, args, loc);
6786 if (await_source_arg != null) {
6787 await_source_arg.Release (ec);
6791 public override void FlowAnalysis (FlowAnalysisContext fc)
6793 base.FlowAnalysis (fc);
6795 if (conditional_access_receiver)
6796 fc.ConditionalAccessEnd ();
6799 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6801 eclass = ExprClass.PropertyAccess;
6803 if (best_candidate.IsNotCSharpCompatible) {
6804 Error_PropertyNotValid (rc);
6807 ResolveInstanceExpression (rc, right_side);
6809 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6810 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6811 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6813 type = p.MemberType;
6817 DoBestMemberChecks (rc, best_candidate);
6819 // Handling of com-imported properties with any number of default property parameters
6820 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6821 var p = best_candidate.Get.Parameters;
6822 arguments = new Arguments (p.Count);
6823 for (int i = 0; i < p.Count; ++i) {
6824 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6826 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6827 var p = best_candidate.Set.Parameters;
6828 arguments = new Arguments (p.Count - 1);
6829 for (int i = 0; i < p.Count - 1; ++i) {
6830 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6837 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6839 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6843 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6845 // getter and setter can be different for base calls
6846 MethodSpec getter, setter;
6847 protected T best_candidate;
6849 protected LocalTemporary temp;
6850 protected bool emitting_compound_assignment;
6851 protected bool has_await_arguments;
6853 protected PropertyOrIndexerExpr (Location l)
6860 protected abstract Arguments Arguments { get; set; }
6862 public MethodSpec Getter {
6871 public MethodSpec Setter {
6882 protected override Expression DoResolve (ResolveContext ec)
6884 if (eclass == ExprClass.Unresolved) {
6885 ResolveConditionalAccessReceiver (ec);
6887 var expr = OverloadResolve (ec, null);
6892 return expr.Resolve (ec);
6894 if (conditional_access_receiver) {
6895 type = LiftMemberType (ec, type);
6896 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6900 if (!ResolveGetter (ec))
6906 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6908 if (ConditionalAccess)
6909 throw new NotSupportedException ("null propagating operator assignment");
6911 if (right_side == EmptyExpression.OutAccess) {
6912 // TODO: best_candidate can be null at this point
6913 INamedBlockVariable variable = null;
6914 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6915 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6916 best_candidate.Name);
6918 right_side.DoResolveLValue (ec, this);
6923 if (eclass == ExprClass.Unresolved) {
6924 var expr = OverloadResolve (ec, right_side);
6929 return expr.ResolveLValue (ec, right_side);
6931 ResolveInstanceExpression (ec, right_side);
6934 if (!ResolveSetter (ec))
6940 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
6942 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6944 call.Emit (ec, method, arguments, loc);
6946 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
6950 // Implements the IAssignMethod interface for assignments
6952 public virtual void Emit (EmitContext ec, bool leave_copy)
6954 var call = new CallEmitter ();
6955 call.ConditionalAccess = ConditionalAccess;
6956 call.InstanceExpression = InstanceExpression;
6957 if (has_await_arguments)
6958 call.HasAwaitArguments = true;
6960 call.DuplicateArguments = emitting_compound_assignment;
6962 if (conditional_access_receiver)
6963 EmitConditionalAccess (ec, ref call, Getter, Arguments);
6965 call.Emit (ec, Getter, Arguments, loc);
6967 if (call.HasAwaitArguments) {
6968 InstanceExpression = call.InstanceExpression;
6969 Arguments = call.EmittedArguments;
6970 has_await_arguments = true;
6974 ec.Emit (OpCodes.Dup);
6975 temp = new LocalTemporary (Type);
6980 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6982 public override void Emit (EmitContext ec)
6987 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6989 has_await_arguments = true;
6994 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6996 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6998 bool ResolveGetter (ResolveContext rc)
7000 if (!best_candidate.HasGet) {
7001 if (InstanceExpression != EmptyExpression.Null) {
7002 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7003 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7004 best_candidate.GetSignatureForError ());
7007 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7008 if (best_candidate.HasDifferentAccessibility) {
7009 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7010 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7011 TypeManager.CSharpSignature (best_candidate));
7013 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7014 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7018 if (best_candidate.HasDifferentAccessibility) {
7019 CheckProtectedMemberAccess (rc, best_candidate.Get);
7022 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7026 bool ResolveSetter (ResolveContext rc)
7028 if (!best_candidate.HasSet) {
7029 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7030 GetSignatureForError ());
7034 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7035 if (best_candidate.HasDifferentAccessibility) {
7036 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7037 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7038 GetSignatureForError ());
7040 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7041 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7045 if (best_candidate.HasDifferentAccessibility)
7046 CheckProtectedMemberAccess (rc, best_candidate.Set);
7048 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7054 /// Fully resolved expression that evaluates to an Event
7056 public class EventExpr : MemberExpr, IAssignMethod
7058 readonly EventSpec spec;
7061 public EventExpr (EventSpec spec, Location loc)
7069 protected override TypeSpec DeclaringType {
7071 return spec.DeclaringType;
7075 public override string Name {
7081 public override bool IsInstance {
7083 return !spec.IsStatic;
7087 public override bool IsStatic {
7089 return spec.IsStatic;
7093 public override string KindName {
7094 get { return "event"; }
7097 public MethodSpec Operator {
7105 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7108 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7110 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7111 if (spec.BackingField != null &&
7112 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7114 spec.MemberDefinition.SetIsUsed ();
7116 if (!ec.IsObsolete) {
7117 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7119 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7122 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7123 Error_AssignmentEventOnly (ec);
7125 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7127 InstanceExpression = null;
7129 return ml.ResolveMemberAccess (ec, left, original);
7133 return base.ResolveMemberAccess (ec, left, original);
7136 public override Expression CreateExpressionTree (ResolveContext ec)
7138 throw new NotSupportedException ("ET");
7141 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7143 if (right_side == EmptyExpression.EventAddition) {
7144 op = spec.AccessorAdd;
7145 } else if (right_side == EmptyExpression.EventSubtraction) {
7146 op = spec.AccessorRemove;
7150 Error_AssignmentEventOnly (ec);
7154 op = CandidateToBaseOverride (ec, op);
7158 protected override Expression DoResolve (ResolveContext ec)
7160 eclass = ExprClass.EventAccess;
7161 type = spec.MemberType;
7163 ResolveInstanceExpression (ec, null);
7165 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7166 Error_AssignmentEventOnly (ec);
7169 DoBestMemberChecks (ec, spec);
7173 public override void Emit (EmitContext ec)
7175 throw new NotSupportedException ();
7176 //Error_CannotAssign ();
7179 #region IAssignMethod Members
7181 public void Emit (EmitContext ec, bool leave_copy)
7183 throw new NotImplementedException ();
7186 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7188 if (leave_copy || !isCompound)
7189 throw new NotImplementedException ("EventExpr::EmitAssign");
7191 Arguments args = new Arguments (1);
7192 args.Add (new Argument (source));
7194 // TODO: Wrong, needs receiver
7195 // if (NullShortCircuit) {
7196 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7199 var call = new CallEmitter ();
7200 call.InstanceExpression = InstanceExpression;
7201 call.ConditionalAccess = ConditionalAccess;
7202 call.EmitStatement (ec, op, args, loc);
7204 // if (NullShortCircuit)
7205 // ec.CloseConditionalAccess (null);
7210 void Error_AssignmentEventOnly (ResolveContext ec)
7212 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7213 ec.Report.Error (79, loc,
7214 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7215 GetSignatureForError ());
7217 ec.Report.Error (70, loc,
7218 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7219 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7223 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7225 name = name.Substring (0, name.LastIndexOf ('.'));
7226 base.Error_CannotCallAbstractBase (rc, name);
7229 public override string GetSignatureForError ()
7231 return TypeManager.CSharpSignature (spec);
7234 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7236 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7240 public class TemporaryVariableReference : VariableReference
7242 public class Declarator : Statement
7244 TemporaryVariableReference variable;
7246 public Declarator (TemporaryVariableReference variable)
7248 this.variable = variable;
7252 protected override void DoEmit (EmitContext ec)
7254 variable.li.CreateBuilder (ec);
7257 public override void Emit (EmitContext ec)
7259 // Don't create sequence point
7263 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7268 protected override void CloneTo (CloneContext clonectx, Statement target)
7276 public TemporaryVariableReference (LocalVariable li, Location loc)
7279 this.type = li.Type;
7283 public override bool IsLockedByStatement {
7291 public LocalVariable LocalInfo {
7297 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7299 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7300 return new TemporaryVariableReference (li, loc);
7303 protected override Expression DoResolve (ResolveContext ec)
7305 eclass = ExprClass.Variable;
7308 // Don't capture temporary variables except when using
7309 // state machine redirection and block yields
7311 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7312 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7313 ec.IsVariableCapturingRequired) {
7314 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7315 storey.CaptureLocalVariable (ec, li);
7321 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7323 return Resolve (ec);
7326 public override void Emit (EmitContext ec)
7328 li.CreateBuilder (ec);
7333 public void EmitAssign (EmitContext ec, Expression source)
7335 li.CreateBuilder (ec);
7337 EmitAssign (ec, source, false, false);
7340 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7342 return li.HoistedVariant;
7345 public override bool IsFixed {
7346 get { return true; }
7349 public override bool IsRef {
7350 get { return false; }
7353 public override string Name {
7354 get { throw new NotImplementedException (); }
7357 public override void SetHasAddressTaken ()
7359 throw new NotImplementedException ();
7362 protected override ILocalVariable Variable {
7366 public override VariableInfo VariableInfo {
7367 get { return null; }
7372 /// Handles `var' contextual keyword; var becomes a keyword only
7373 /// if no type called var exists in a variable scope
7375 class VarExpr : SimpleName
7377 public VarExpr (Location loc)
7382 public bool InferType (ResolveContext ec, Expression right_side)
7385 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7387 type = right_side.Type;
7388 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7389 ec.Report.Error (815, loc,
7390 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7391 type.GetSignatureForError ());
7395 eclass = ExprClass.Variable;
7399 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7401 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7402 base.Error_TypeOrNamespaceNotFound (ec);
7404 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");