2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
233 var rc = mc as ResolveContext ?? new ResolveContext (mc);
234 Expression e = Resolve (rc);
236 e.Error_UnexpectedKind (rc, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 public virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 public static bool IsNeverNull (Expression expr)
435 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
438 var c = expr as Constant;
442 var tc = expr as TypeCast;
444 return IsNeverNull (tc.Child);
449 protected static bool IsNullPropagatingValid (TypeSpec type)
452 case MemberKind.Struct:
453 return type.IsNullableType;
454 case MemberKind.Enum:
455 case MemberKind.Void:
456 case MemberKind.PointerType:
458 case MemberKind.InternalCompilerType:
459 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
460 case MemberKind.TypeParameter:
461 return !((TypeParameterSpec) type).IsValueType;
467 public virtual bool HasConditionalAccess ()
472 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
474 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
475 Nullable.NullableInfo.MakeType (rc.Module, type) :
480 /// Resolves an expression and performs semantic analysis on it.
484 /// Currently Resolve wraps DoResolve to perform sanity
485 /// checking and assertion checking on what we expect from Resolve.
487 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
489 if (eclass != ExprClass.Unresolved) {
490 if ((flags & ExprClassToResolveFlags) == 0) {
491 Error_UnexpectedKind (ec, flags, loc);
505 if ((flags & e.ExprClassToResolveFlags) == 0) {
506 e.Error_UnexpectedKind (ec, flags, loc);
511 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
514 } catch (Exception ex) {
515 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
516 ec.Report.Printer is NullReportPrinter)
519 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
520 return ErrorExpression.Instance; // TODO: Add location
525 /// Resolves an expression and performs semantic analysis on it.
527 public Expression Resolve (ResolveContext rc)
529 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
533 /// Resolves an expression for LValue assignment
537 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
538 /// checking and assertion checking on what we expect from Resolve
540 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
542 int errors = ec.Report.Errors;
543 bool out_access = right_side == EmptyExpression.OutAccess;
545 Expression e = DoResolveLValue (ec, right_side);
547 if (e != null && out_access && !(e is IMemoryLocation)) {
548 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
549 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
551 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
552 // e.GetType () + " " + e.GetSignatureForError ());
557 if (errors == ec.Report.Errors) {
558 Error_ValueAssignment (ec, right_side);
563 if (e.eclass == ExprClass.Unresolved)
564 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
566 if ((e.type == null) && !(e is GenericTypeExpr))
567 throw new Exception ("Expression " + e + " did not set its type after Resolve");
572 public Constant ResolveLabelConstant (ResolveContext rc)
574 var expr = Resolve (rc);
578 Constant c = expr as Constant;
580 if (expr.type != InternalType.ErrorType)
581 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
589 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
591 if (Attribute.IsValidArgumentType (parameterType)) {
592 rc.Module.Compiler.Report.Error (182, loc,
593 "An attribute argument must be a constant expression, typeof expression or array creation expression");
595 rc.Module.Compiler.Report.Error (181, loc,
596 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
597 targetType.GetSignatureForError ());
602 /// Emits the code for the expression
606 /// The Emit method is invoked to generate the code
607 /// for the expression.
609 public abstract void Emit (EmitContext ec);
612 // Emit code to branch to @target if this expression is equivalent to @on_true.
613 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
614 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
615 // including the use of conditional branches. Note also that a branch MUST be emitted
616 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
619 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
622 // Emit this expression for its side effects, not for its value.
623 // The default implementation is to emit the value, and then throw it away.
624 // Subclasses can provide more efficient implementations, but those MUST be equivalent
625 public virtual void EmitSideEffect (EmitContext ec)
628 ec.Emit (OpCodes.Pop);
632 // Emits the expression into temporary field variable. The method
633 // should be used for await expressions only
635 public virtual Expression EmitToField (EmitContext ec)
638 // This is the await prepare Emit method. When emitting code like
639 // a + b we emit code like
645 // For await a + await b we have to interfere the flow to keep the
646 // stack clean because await yields from the expression. The emit
649 // a = a.EmitToField () // a is changed to temporary field access
650 // b = b.EmitToField ()
656 // The idea is to emit expression and leave the stack empty with
657 // result value still available.
659 // Expressions should override this default implementation when
660 // optimized version can be provided (e.g. FieldExpr)
663 // We can optimize for side-effect free expressions, they can be
664 // emitted out of order
666 if (IsSideEffectFree)
669 bool needs_temporary = ContainsEmitWithAwait ();
670 if (!needs_temporary)
673 // Emit original code
674 var field = EmitToFieldSource (ec);
677 // Store the result to temporary field when we
678 // cannot load `this' directly
680 field = ec.GetTemporaryField (type);
681 if (needs_temporary) {
683 // Create temporary local (we cannot load `this' before Emit)
685 var temp = ec.GetTemporaryLocal (type);
686 ec.Emit (OpCodes.Stloc, temp);
689 ec.Emit (OpCodes.Ldloc, temp);
690 field.EmitAssignFromStack (ec);
692 ec.FreeTemporaryLocal (temp, type);
694 field.EmitAssignFromStack (ec);
701 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
704 // Default implementation calls Emit method
710 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
712 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
713 bool contains_await = false;
715 for (int i = 1; i < expressions.Count; ++i) {
716 if (expressions[i].ContainsEmitWithAwait ()) {
717 contains_await = true;
722 if (contains_await) {
723 for (int i = 0; i < expressions.Count; ++i) {
724 expressions[i] = expressions[i].EmitToField (ec);
729 for (int i = 0; i < expressions.Count; ++i) {
730 expressions[i].Emit (ec);
735 /// Protected constructor. Only derivate types should
736 /// be able to be created
739 protected Expression ()
744 /// Returns a fully formed expression after a MemberLookup
747 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
749 if (spec is EventSpec)
750 return new EventExpr ((EventSpec) spec, loc);
751 if (spec is ConstSpec)
752 return new ConstantExpr ((ConstSpec) spec, loc);
753 if (spec is FieldSpec)
754 return new FieldExpr ((FieldSpec) spec, loc);
755 if (spec is PropertySpec)
756 return new PropertyExpr ((PropertySpec) spec, loc);
757 if (spec is TypeSpec)
758 return new TypeExpression (((TypeSpec) spec), loc);
763 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
765 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
768 case MemberKind.Struct:
769 // Every struct has implicit default constructor if not provided by user
773 rc.Report.SymbolRelatedToPreviousError (type);
774 // Report meaningful error for struct as they always have default ctor in C# context
775 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
777 case MemberKind.MissingType:
778 case MemberKind.InternalCompilerType:
779 // LAMESPEC: dynamic is not really object
780 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
784 rc.Report.SymbolRelatedToPreviousError (type);
785 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
786 type.GetSignatureForError ());
793 if (args == null && type.IsStruct) {
794 bool includes_empty = false;
795 foreach (MethodSpec ctor in ctors) {
796 if (ctor.Parameters.IsEmpty) {
797 includes_empty = true;
805 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
806 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
807 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
810 return r.ResolveMember<MethodSpec> (rc, ref args);
814 public enum MemberLookupRestrictions
820 EmptyArguments = 1 << 4,
821 IgnoreArity = 1 << 5,
822 IgnoreAmbiguity = 1 << 6,
823 NameOfExcluded = 1 << 7,
827 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
828 // `qualifier_type' or null to lookup members in the current class.
830 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
832 var members = MemberCache.FindMembers (queried_type, name, false);
838 expr = MemberLookupToExpression (rc, members, errorMode, queried_type, name, arity, restrictions, loc);
842 if (members [0].DeclaringType.BaseType == null)
845 members = MemberCache.FindMembers (members [0].DeclaringType.BaseType, name, false);
846 } while (members != null);
851 public static Expression MemberLookupToExpression (IMemberContext rc, IList<MemberSpec> members, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
853 MemberSpec non_method = null;
854 MemberSpec ambig_non_method = null;
856 for (int i = 0; i < members.Count; ++i) {
857 var member = members [i];
859 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
860 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
863 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
866 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
870 if (!member.IsAccessible (rc))
874 // With runtime binder we can have a situation where queried type is inaccessible
875 // because it came via dynamic object, the check about inconsisted accessibility
876 // had no effect as the type was unknown during compilation
879 // private class N { }
881 // public dynamic Foo ()
887 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
891 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
892 if (member is MethodSpec) {
894 // Interface members that are hidden by class members are removed from the set. This
895 // step only has an effect if T is a type parameter and T has both an effective base
896 // class other than object and a non-empty effective interface set
898 var tps = queried_type as TypeParameterSpec;
899 if (tps != null && tps.HasTypeConstraint)
900 members = RemoveHiddenTypeParameterMethods (members);
902 return new MethodGroupExpr (members, queried_type, loc);
905 if (!Invocation.IsMemberInvocable (member))
909 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
911 } else if (!errorMode && !member.IsNotCSharpCompatible) {
913 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
914 // T has both an effective base class other than object and a non-empty effective interface set.
916 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
918 var tps = queried_type as TypeParameterSpec;
919 if (tps != null && tps.HasTypeConstraint) {
920 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
923 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
929 ambig_non_method = member;
933 if (non_method != null) {
934 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
935 var report = rc.Module.Compiler.Report;
936 report.SymbolRelatedToPreviousError (non_method);
937 report.SymbolRelatedToPreviousError (ambig_non_method);
938 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
939 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
942 if (non_method is MethodSpec)
943 return new MethodGroupExpr (members, queried_type, loc);
945 return ExprClassFromMemberInfo (non_method, loc);
951 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
953 if (members.Count < 2)
957 // If M is a method, then all non-method members declared in an interface declaration
958 // are removed from the set, and all methods with the same signature as M declared in
959 // an interface declaration are removed from the set
963 for (int i = 0; i < members.Count; ++i) {
964 var method = members[i] as MethodSpec;
965 if (method == null) {
968 members = new List<MemberSpec> (members);
971 members.RemoveAt (i--);
975 if (!method.DeclaringType.IsInterface)
978 for (int ii = 0; ii < members.Count; ++ii) {
979 var candidate = members[ii] as MethodSpec;
980 if (candidate == null || !candidate.DeclaringType.IsClass)
983 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
988 members = new List<MemberSpec> (members);
991 members.RemoveAt (i--);
999 protected static void Error_NamedArgument (NamedArgument na, Report Report)
1001 Report.Error (1742, na.Location, "An element access expression cannot use named argument");
1004 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
1006 throw new NotImplementedException ();
1009 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
1011 if (t == InternalType.ErrorType)
1014 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
1015 oper, t.GetSignatureForError ());
1018 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1020 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1023 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1025 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1028 protected void Error_NullPropagatingLValue (ResolveContext rc)
1030 rc.Report.Error (-1030, loc, "The left-hand side of an assignment cannot contain a null propagating operator");
1033 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1038 // Special version of flow analysis for expressions which can return different
1039 // on-true and on-false result. Used by &&, ||, ?: expressions
1041 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1044 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1048 /// Returns an expression that can be used to invoke operator true
1049 /// on the expression if it exists.
1051 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1053 return GetOperatorTrueOrFalse (ec, e, true, loc);
1057 /// Returns an expression that can be used to invoke operator false
1058 /// on the expression if it exists.
1060 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1062 return GetOperatorTrueOrFalse (ec, e, false, loc);
1065 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1067 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1069 if (type.IsNullableType)
1070 type = Nullable.NullableInfo.GetUnderlyingType (type);
1072 var methods = MemberCache.GetUserOperator (type, op, false);
1073 if (methods == null)
1076 Arguments arguments = new Arguments (1);
1077 arguments.Add (new Argument (e));
1079 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1080 var oper = res.ResolveOperator (ec, ref arguments);
1085 return new UserOperatorCall (oper, arguments, null, loc);
1088 public virtual string ExprClassName
1092 case ExprClass.Unresolved:
1093 return "Unresolved";
1094 case ExprClass.Value:
1096 case ExprClass.Variable:
1098 case ExprClass.Namespace:
1100 case ExprClass.Type:
1102 case ExprClass.MethodGroup:
1103 return "method group";
1104 case ExprClass.PropertyAccess:
1105 return "property access";
1106 case ExprClass.EventAccess:
1107 return "event access";
1108 case ExprClass.IndexerAccess:
1109 return "indexer access";
1110 case ExprClass.Nothing:
1112 case ExprClass.TypeParameter:
1113 return "type parameter";
1115 throw new Exception ("Should not happen");
1120 /// Reports that we were expecting `expr' to be of class `expected'
1122 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1124 var name = memberExpr.GetSignatureForError ();
1126 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1129 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1131 string [] valid = new string [4];
1134 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1135 valid [count++] = "variable";
1136 valid [count++] = "value";
1139 if ((flags & ResolveFlags.Type) != 0)
1140 valid [count++] = "type";
1142 if ((flags & ResolveFlags.MethodGroup) != 0)
1143 valid [count++] = "method group";
1146 valid [count++] = "unknown";
1148 StringBuilder sb = new StringBuilder (valid [0]);
1149 for (int i = 1; i < count - 1; i++) {
1151 sb.Append (valid [i]);
1154 sb.Append ("' or `");
1155 sb.Append (valid [count - 1]);
1158 ec.Report.Error (119, loc,
1159 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1162 public static void UnsafeError (ResolveContext ec, Location loc)
1164 UnsafeError (ec.Report, loc);
1167 public static void UnsafeError (Report Report, Location loc)
1169 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1173 // Converts `source' to an int, uint, long or ulong.
1175 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1177 var btypes = ec.BuiltinTypes;
1179 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1180 Arguments args = new Arguments (1);
1181 args.Add (new Argument (source));
1182 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, source.loc).Resolve (ec);
1185 Expression converted;
1187 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1188 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1189 if (converted == null)
1190 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1191 if (converted == null)
1192 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1193 if (converted == null)
1194 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1196 if (converted == null) {
1197 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1206 // Only positive constants are allowed at compile time
1208 Constant c = converted as Constant;
1209 if (c != null && c.IsNegative)
1210 Error_NegativeArrayIndex (ec, source.loc);
1212 // No conversion needed to array index
1213 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1216 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1219 public Expression MakePointerAccess (ResolveContext rc, TypeSpec type, Arguments args)
1221 if (args.Count != 1){
1222 rc.Report.Error (196, loc, "A pointer must be indexed by only one value");
1227 if (arg is NamedArgument)
1228 Error_NamedArgument ((NamedArgument) arg, rc.Report);
1230 var index = arg.Expr.Resolve (rc);
1234 index = ConvertExpressionToArrayIndex (rc, index, true);
1236 Expression p = new PointerArithmetic (Binary.Operator.Addition, this, index, type, loc);
1237 return new Indirection (p, loc);
1241 // Derived classes implement this method by cloning the fields that
1242 // could become altered during the Resolve stage
1244 // Only expressions that are created for the parser need to implement
1247 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1249 throw new NotImplementedException (
1251 "CloneTo not implemented for expression {0}", this.GetType ()));
1255 // Clones an expression created by the parser.
1257 // We only support expressions created by the parser so far, not
1258 // expressions that have been resolved (many more classes would need
1259 // to implement CloneTo).
1261 // This infrastructure is here merely for Lambda expressions which
1262 // compile the same code using different type values for the same
1263 // arguments to find the correct overload
1265 public virtual Expression Clone (CloneContext clonectx)
1267 Expression cloned = (Expression) MemberwiseClone ();
1268 CloneTo (clonectx, cloned);
1274 // Implementation of expression to expression tree conversion
1276 public abstract Expression CreateExpressionTree (ResolveContext ec);
1278 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1280 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1283 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1285 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1288 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1290 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1293 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1295 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1299 return new TypeExpression (t, loc);
1303 // Implemented by all expressions which support conversion from
1304 // compiler expression to invokable runtime expression. Used by
1305 // dynamic C# binder.
1307 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1309 throw new NotImplementedException ("MakeExpression for " + GetType ());
1312 public virtual object Accept (StructuralVisitor visitor)
1314 return visitor.Visit (this);
1319 /// This is just a base class for expressions that can
1320 /// appear on statements (invocations, object creation,
1321 /// assignments, post/pre increment and decrement). The idea
1322 /// being that they would support an extra Emition interface that
1323 /// does not leave a result on the stack.
1325 public abstract class ExpressionStatement : Expression
1327 public virtual void MarkReachable (Reachability rc)
1331 public ExpressionStatement ResolveStatement (BlockContext ec)
1333 Expression e = Resolve (ec);
1337 ExpressionStatement es = e as ExpressionStatement;
1338 if (es == null || e is AnonymousMethodBody)
1339 Error_InvalidExpressionStatement (ec);
1342 // This is quite expensive warning, try to limit the damage
1344 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1345 WarningAsyncWithoutWait (ec, e);
1351 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1353 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1354 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1359 // Need to do full resolve because GetAwaiter can be extension method
1360 // available only in this context
1362 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1366 var arguments = new Arguments (0);
1367 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1372 // Use same check rules as for real await
1374 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1375 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1378 bc.Report.Warning (4014, 1, e.Location,
1379 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1383 var inv = e as Invocation;
1384 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1385 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1386 bc.Report.Warning (4014, 1, e.Location,
1387 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1393 /// Requests the expression to be emitted in a `statement'
1394 /// context. This means that no new value is left on the
1395 /// stack after invoking this method (constrasted with
1396 /// Emit that will always leave a value on the stack).
1398 public abstract void EmitStatement (EmitContext ec);
1400 public override void EmitSideEffect (EmitContext ec)
1407 /// This kind of cast is used to encapsulate the child
1408 /// whose type is child.Type into an expression that is
1409 /// reported to return "return_type". This is used to encapsulate
1410 /// expressions which have compatible types, but need to be dealt
1411 /// at higher levels with.
1413 /// For example, a "byte" expression could be encapsulated in one
1414 /// of these as an "unsigned int". The type for the expression
1415 /// would be "unsigned int".
1418 public abstract class TypeCast : Expression
1420 protected readonly Expression child;
1422 protected TypeCast (Expression child, TypeSpec return_type)
1424 eclass = child.eclass;
1425 loc = child.Location;
1430 public Expression Child {
1436 public override bool ContainsEmitWithAwait ()
1438 return child.ContainsEmitWithAwait ();
1441 public override Expression CreateExpressionTree (ResolveContext ec)
1443 Arguments args = new Arguments (2);
1444 args.Add (new Argument (child.CreateExpressionTree (ec)));
1445 args.Add (new Argument (new TypeOf (type, loc)));
1447 if (type.IsPointer || child.Type.IsPointer)
1448 Error_PointerInsideExpressionTree (ec);
1450 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1453 protected override Expression DoResolve (ResolveContext ec)
1455 // This should never be invoked, we are born in fully
1456 // initialized state.
1461 public override void Emit (EmitContext ec)
1466 public override void FlowAnalysis (FlowAnalysisContext fc)
1468 child.FlowAnalysis (fc);
1471 public override SLE.Expression MakeExpression (BuilderContext ctx)
1474 return base.MakeExpression (ctx);
1476 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1477 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1478 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1482 protected override void CloneTo (CloneContext clonectx, Expression t)
1487 public override bool IsNull {
1488 get { return child.IsNull; }
1492 public class EmptyCast : TypeCast {
1493 EmptyCast (Expression child, TypeSpec target_type)
1494 : base (child, target_type)
1498 public static Expression Create (Expression child, TypeSpec type)
1500 Constant c = child as Constant;
1502 var enum_constant = c as EnumConstant;
1503 if (enum_constant != null)
1504 c = enum_constant.Child;
1506 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1510 var res = c.ConvertImplicitly (type);
1516 EmptyCast e = child as EmptyCast;
1518 return new EmptyCast (e.child, type);
1520 return new EmptyCast (child, type);
1523 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1525 child.EmitBranchable (ec, label, on_true);
1528 public override void EmitSideEffect (EmitContext ec)
1530 child.EmitSideEffect (ec);
1535 // Used for predefined type user operator (no obsolete check, etc.)
1537 public class OperatorCast : TypeCast
1539 readonly MethodSpec conversion_operator;
1541 public OperatorCast (Expression expr, TypeSpec target_type)
1542 : this (expr, target_type, target_type, false)
1546 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1547 : this (expr, target_type, target_type, find_explicit)
1551 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1552 : base (expr, returnType)
1554 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1555 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1558 foreach (MethodSpec oper in mi) {
1559 if (oper.ReturnType != returnType)
1562 if (oper.Parameters.Types[0] == expr.Type) {
1563 conversion_operator = oper;
1569 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1570 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1573 public override void Emit (EmitContext ec)
1576 ec.Emit (OpCodes.Call, conversion_operator);
1581 // Constant specialization of EmptyCast.
1582 // We need to special case this since an empty cast of
1583 // a constant is still a constant.
1585 public class EmptyConstantCast : Constant
1587 public readonly Constant child;
1589 public EmptyConstantCast (Constant child, TypeSpec type)
1590 : base (child.Location)
1593 throw new ArgumentNullException ("child");
1596 this.eclass = child.eclass;
1600 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1602 if (child.Type == target_type)
1605 // FIXME: check that 'type' can be converted to 'target_type' first
1606 return child.ConvertExplicitly (in_checked_context, target_type);
1609 public override Expression CreateExpressionTree (ResolveContext ec)
1611 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1612 child.CreateExpressionTree (ec),
1613 new TypeOf (type, loc));
1616 Error_PointerInsideExpressionTree (ec);
1618 return CreateExpressionFactoryCall (ec, "Convert", args);
1621 public override bool IsDefaultValue {
1622 get { return child.IsDefaultValue; }
1625 public override bool IsNegative {
1626 get { return child.IsNegative; }
1629 public override bool IsNull {
1630 get { return child.IsNull; }
1633 public override bool IsOneInteger {
1634 get { return child.IsOneInteger; }
1637 public override bool IsSideEffectFree {
1639 return child.IsSideEffectFree;
1643 public override bool IsZeroInteger {
1644 get { return child.IsZeroInteger; }
1647 public override void Emit (EmitContext ec)
1652 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1654 child.EmitBranchable (ec, label, on_true);
1656 // Only to make verifier happy
1657 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1658 ec.Emit (OpCodes.Unbox_Any, type);
1661 public override void EmitSideEffect (EmitContext ec)
1663 child.EmitSideEffect (ec);
1666 public override object GetValue ()
1668 return child.GetValue ();
1671 public override string GetValueAsLiteral ()
1673 return child.GetValueAsLiteral ();
1676 public override long GetValueAsLong ()
1678 return child.GetValueAsLong ();
1681 public override Constant ConvertImplicitly (TypeSpec target_type)
1683 if (type == target_type)
1686 // FIXME: Do we need to check user conversions?
1687 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1690 return child.ConvertImplicitly (target_type);
1695 /// This class is used to wrap literals which belong inside Enums
1697 public class EnumConstant : Constant
1699 public Constant Child;
1701 public EnumConstant (Constant child, TypeSpec enum_type)
1702 : base (child.Location)
1706 this.eclass = ExprClass.Value;
1707 this.type = enum_type;
1710 protected EnumConstant (Location loc)
1715 public override void Emit (EmitContext ec)
1720 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1722 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1725 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1727 Child.EmitBranchable (ec, label, on_true);
1730 public override void EmitSideEffect (EmitContext ec)
1732 Child.EmitSideEffect (ec);
1735 public override string GetSignatureForError()
1737 return Type.GetSignatureForError ();
1740 public override object GetValue ()
1742 return Child.GetValue ();
1746 public override object GetTypedValue ()
1749 // The method can be used in dynamic context only (on closed types)
1751 // System.Enum.ToObject cannot be called on dynamic types
1752 // EnumBuilder has to be used, but we cannot use EnumBuilder
1753 // because it does not properly support generics
1755 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1759 public override string GetValueAsLiteral ()
1761 return Child.GetValueAsLiteral ();
1764 public override long GetValueAsLong ()
1766 return Child.GetValueAsLong ();
1769 public EnumConstant Increment()
1771 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1774 public override bool IsDefaultValue {
1776 return Child.IsDefaultValue;
1780 public override bool IsSideEffectFree {
1782 return Child.IsSideEffectFree;
1786 public override bool IsZeroInteger {
1787 get { return Child.IsZeroInteger; }
1790 public override bool IsNegative {
1792 return Child.IsNegative;
1796 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1798 if (Child.Type == target_type)
1801 return Child.ConvertExplicitly (in_checked_context, target_type);
1804 public override Constant ConvertImplicitly (TypeSpec type)
1806 if (this.type == type) {
1810 if (!Convert.ImplicitStandardConversionExists (this, type)){
1814 return Child.ConvertImplicitly (type);
1819 /// This kind of cast is used to encapsulate Value Types in objects.
1821 /// The effect of it is to box the value type emitted by the previous
1824 public class BoxedCast : TypeCast {
1826 public BoxedCast (Expression expr, TypeSpec target_type)
1827 : base (expr, target_type)
1829 eclass = ExprClass.Value;
1832 protected override Expression DoResolve (ResolveContext ec)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1840 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1842 // Only boxing to object type is supported
1843 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1844 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1848 enc.Encode (child.Type);
1849 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1852 public override void Emit (EmitContext ec)
1856 ec.Emit (OpCodes.Box, child.Type);
1859 public override void EmitSideEffect (EmitContext ec)
1861 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1862 // so, we need to emit the box+pop instructions in most cases
1863 if (child.Type.IsStruct &&
1864 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1865 child.EmitSideEffect (ec);
1867 base.EmitSideEffect (ec);
1871 public class UnboxCast : TypeCast {
1872 public UnboxCast (Expression expr, TypeSpec return_type)
1873 : base (expr, return_type)
1877 protected override Expression DoResolve (ResolveContext ec)
1879 // This should never be invoked, we are born in fully
1880 // initialized state.
1885 public override void Emit (EmitContext ec)
1889 ec.Emit (OpCodes.Unbox_Any, type);
1894 /// This is used to perform explicit numeric conversions.
1896 /// Explicit numeric conversions might trigger exceptions in a checked
1897 /// context, so they should generate the conv.ovf opcodes instead of
1900 public class ConvCast : TypeCast {
1901 public enum Mode : byte {
1902 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1904 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1905 U2_I1, U2_U1, U2_I2, U2_CH,
1906 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1907 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1908 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1909 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1910 CH_I1, CH_U1, CH_I2,
1911 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1912 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1918 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1919 : base (child, return_type)
1924 protected override Expression DoResolve (ResolveContext ec)
1926 // This should never be invoked, we are born in fully
1927 // initialized state.
1932 public override string ToString ()
1934 return String.Format ("ConvCast ({0}, {1})", mode, child);
1937 public override void Emit (EmitContext ec)
1943 public static void Emit (EmitContext ec, Mode mode)
1945 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1947 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1948 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1950 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1951 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1954 case Mode.U1_CH: /* nothing */ break;
1956 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1957 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1958 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1959 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1960 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1963 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1964 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1965 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.U2_CH: /* nothing */ break;
1968 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1969 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1970 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1971 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1972 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1973 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1979 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1980 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1981 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1983 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1984 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1985 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1986 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1987 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1988 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1989 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1990 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1991 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1993 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1994 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1995 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1996 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1997 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1998 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1999 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2000 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
2001 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
2003 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
2004 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
2005 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2007 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2008 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2009 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2010 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2012 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2013 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2014 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2015 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2017 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
2018 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
2019 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
2020 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2021 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
2022 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
2023 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
2024 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
2025 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
2026 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2028 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2032 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
2033 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
2035 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
2036 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
2038 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
2039 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
2041 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2042 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2043 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2046 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U2_CH: /* nothing */ break;
2053 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2054 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2055 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2056 case Mode.I4_U4: /* nothing */ break;
2057 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2058 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2059 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2061 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2062 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2063 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2064 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2065 case Mode.U4_I4: /* nothing */ break;
2066 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2068 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2069 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2070 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2071 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2072 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2073 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2074 case Mode.I8_U8: /* nothing */ break;
2075 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2076 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2078 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2079 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2080 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2081 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2082 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2083 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2084 case Mode.U8_I8: /* nothing */ break;
2085 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2086 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2088 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2089 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2090 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2092 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2093 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2094 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2095 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2097 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2098 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2099 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2100 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2102 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2103 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2104 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2105 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2106 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2107 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2108 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2109 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2110 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2111 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2113 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2119 class OpcodeCast : TypeCast
2123 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2124 : base (child, return_type)
2129 protected override Expression DoResolve (ResolveContext ec)
2131 // This should never be invoked, we are born in fully
2132 // initialized state.
2137 public override void Emit (EmitContext ec)
2143 public TypeSpec UnderlyingType {
2144 get { return child.Type; }
2149 // Opcode casts expression with 2 opcodes but only
2150 // single expression tree node
2152 class OpcodeCastDuplex : OpcodeCast
2154 readonly OpCode second;
2156 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2157 : base (child, returnType, first)
2159 this.second = second;
2162 public override void Emit (EmitContext ec)
2170 /// This kind of cast is used to encapsulate a child and cast it
2171 /// to the class requested
2173 public sealed class ClassCast : TypeCast {
2174 readonly bool forced;
2176 public ClassCast (Expression child, TypeSpec return_type)
2177 : base (child, return_type)
2181 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2182 : base (child, return_type)
2184 this.forced = forced;
2187 public override void Emit (EmitContext ec)
2191 bool gen = TypeManager.IsGenericParameter (child.Type);
2193 ec.Emit (OpCodes.Box, child.Type);
2195 if (type.IsGenericParameter) {
2196 ec.Emit (OpCodes.Unbox_Any, type);
2203 ec.Emit (OpCodes.Castclass, type);
2208 // Created during resolving pahse when an expression is wrapped or constantified
2209 // and original expression can be used later (e.g. for expression trees)
2211 public class ReducedExpression : Expression
2213 public sealed class ReducedConstantExpression : EmptyConstantCast
2215 readonly Expression orig_expr;
2217 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2218 : base (expr, expr.Type)
2220 this.orig_expr = orig_expr;
2223 public Expression OriginalExpression {
2229 public override Constant ConvertImplicitly (TypeSpec target_type)
2231 Constant c = base.ConvertImplicitly (target_type);
2233 c = new ReducedConstantExpression (c, orig_expr);
2238 public override Expression CreateExpressionTree (ResolveContext ec)
2240 return orig_expr.CreateExpressionTree (ec);
2243 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2245 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2247 c = new ReducedConstantExpression (c, orig_expr);
2251 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2254 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2256 if (orig_expr is Conditional)
2257 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2259 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2263 sealed class ReducedExpressionStatement : ExpressionStatement
2265 readonly Expression orig_expr;
2266 readonly ExpressionStatement stm;
2268 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2270 this.orig_expr = orig;
2272 this.eclass = stm.eclass;
2273 this.type = stm.Type;
2275 this.loc = orig.Location;
2278 public override bool ContainsEmitWithAwait ()
2280 return stm.ContainsEmitWithAwait ();
2283 public override Expression CreateExpressionTree (ResolveContext ec)
2285 return orig_expr.CreateExpressionTree (ec);
2288 protected override Expression DoResolve (ResolveContext ec)
2293 public override void Emit (EmitContext ec)
2298 public override void EmitStatement (EmitContext ec)
2300 stm.EmitStatement (ec);
2303 public override void FlowAnalysis (FlowAnalysisContext fc)
2305 stm.FlowAnalysis (fc);
2309 readonly Expression expr, orig_expr;
2311 private ReducedExpression (Expression expr, Expression orig_expr)
2314 this.eclass = expr.eclass;
2315 this.type = expr.Type;
2316 this.orig_expr = orig_expr;
2317 this.loc = orig_expr.Location;
2322 public override bool IsSideEffectFree {
2324 return expr.IsSideEffectFree;
2328 public Expression OriginalExpression {
2336 public override bool ContainsEmitWithAwait ()
2338 return expr.ContainsEmitWithAwait ();
2342 // Creates fully resolved expression switcher
2344 public static Constant Create (Constant expr, Expression original_expr)
2346 if (expr.eclass == ExprClass.Unresolved)
2347 throw new ArgumentException ("Unresolved expression");
2349 return new ReducedConstantExpression (expr, original_expr);
2352 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2354 return new ReducedExpressionStatement (s, orig);
2357 public static Expression Create (Expression expr, Expression original_expr)
2359 return Create (expr, original_expr, true);
2363 // Creates unresolved reduce expression. The original expression has to be
2364 // already resolved. Created expression is constant based based on `expr'
2365 // value unless canBeConstant is used
2367 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2369 if (canBeConstant) {
2370 Constant c = expr as Constant;
2372 return Create (c, original_expr);
2375 ExpressionStatement s = expr as ExpressionStatement;
2377 return Create (s, original_expr);
2379 if (expr.eclass == ExprClass.Unresolved)
2380 throw new ArgumentException ("Unresolved expression");
2382 return new ReducedExpression (expr, original_expr);
2385 public override Expression CreateExpressionTree (ResolveContext ec)
2387 return orig_expr.CreateExpressionTree (ec);
2390 protected override Expression DoResolve (ResolveContext ec)
2395 public override void Emit (EmitContext ec)
2400 public override Expression EmitToField (EmitContext ec)
2402 return expr.EmitToField(ec);
2405 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2407 expr.EmitBranchable (ec, target, on_true);
2410 public override void FlowAnalysis (FlowAnalysisContext fc)
2412 expr.FlowAnalysis (fc);
2415 public override SLE.Expression MakeExpression (BuilderContext ctx)
2417 return orig_expr.MakeExpression (ctx);
2422 // Standard composite pattern
2424 public abstract class CompositeExpression : Expression
2426 protected Expression expr;
2428 protected CompositeExpression (Expression expr)
2431 this.loc = expr.Location;
2434 public override bool ContainsEmitWithAwait ()
2436 return expr.ContainsEmitWithAwait ();
2439 public override Expression CreateExpressionTree (ResolveContext rc)
2441 return expr.CreateExpressionTree (rc);
2444 public Expression Child {
2445 get { return expr; }
2448 protected override Expression DoResolve (ResolveContext rc)
2450 expr = expr.Resolve (rc);
2455 eclass = expr.eclass;
2459 public override void Emit (EmitContext ec)
2464 public override bool IsNull {
2465 get { return expr.IsNull; }
2470 // Base of expressions used only to narrow resolve flow
2472 public abstract class ShimExpression : Expression
2474 protected Expression expr;
2476 protected ShimExpression (Expression expr)
2481 public Expression Expr {
2487 protected override void CloneTo (CloneContext clonectx, Expression t)
2492 ShimExpression target = (ShimExpression) t;
2493 target.expr = expr.Clone (clonectx);
2496 public override bool ContainsEmitWithAwait ()
2498 return expr.ContainsEmitWithAwait ();
2501 public override Expression CreateExpressionTree (ResolveContext ec)
2503 throw new NotSupportedException ("ET");
2506 public override void Emit (EmitContext ec)
2508 throw new InternalErrorException ("Missing Resolve call");
2512 public class UnreachableExpression : Expression
2514 public UnreachableExpression (Expression expr)
2516 this.loc = expr.Location;
2519 public override Expression CreateExpressionTree (ResolveContext ec)
2522 throw new NotImplementedException ();
2525 protected override Expression DoResolve (ResolveContext rc)
2527 throw new NotSupportedException ();
2530 public override void FlowAnalysis (FlowAnalysisContext fc)
2532 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2535 public override void Emit (EmitContext ec)
2539 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2545 // Unresolved type name expressions
2547 public abstract class ATypeNameExpression : FullNamedExpression
2550 protected TypeArguments targs;
2552 protected ATypeNameExpression (string name, Location l)
2558 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2565 protected ATypeNameExpression (string name, int arity, Location l)
2566 : this (name, new UnboundTypeArguments (arity, l), l)
2574 return targs == null ? 0 : targs.Count;
2578 public bool HasTypeArguments {
2580 return targs != null && !targs.IsEmpty;
2584 public string Name {
2593 public TypeArguments TypeArguments {
2601 public override bool Equals (object obj)
2603 ATypeNameExpression atne = obj as ATypeNameExpression;
2604 return atne != null && atne.Name == Name &&
2605 (targs == null || targs.Equals (atne.targs));
2608 public override int GetHashCode ()
2610 return Name.GetHashCode ();
2613 // TODO: Move it to MemberCore
2614 public static string GetMemberType (MemberCore mc)
2620 if (mc is FieldBase)
2622 if (mc is MethodCore)
2624 if (mc is EnumMember)
2632 public override string GetSignatureForError ()
2634 if (targs != null) {
2635 return Name + "<" + targs.GetSignatureForError () + ">";
2641 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2645 /// SimpleName expressions are formed of a single word and only happen at the beginning
2646 /// of a dotted-name.
2648 public class SimpleName : ATypeNameExpression
2650 public SimpleName (string name, Location l)
2655 public SimpleName (string name, TypeArguments args, Location l)
2656 : base (name, args, l)
2660 public SimpleName (string name, int arity, Location l)
2661 : base (name, arity, l)
2665 public SimpleName GetMethodGroup ()
2667 return new SimpleName (Name, targs, loc);
2670 protected override Expression DoResolve (ResolveContext rc)
2672 return SimpleNameResolve (rc, null);
2675 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2677 return SimpleNameResolve (ec, right_side);
2680 public void Error_NameDoesNotExist (ResolveContext rc)
2682 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2685 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2687 if (ctx.CurrentType != null) {
2688 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2689 if (member != null) {
2690 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2695 var report = ctx.Module.Compiler.Report;
2697 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2698 if (retval != null) {
2699 report.SymbolRelatedToPreviousError (retval.Type);
2700 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2704 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2705 if (retval != null) {
2706 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2710 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2711 if (ns_candidates != null) {
2712 if (ctx is UsingAliasNamespace.AliasContext) {
2713 report.Error (246, loc,
2714 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2715 ns_candidates[0], Name);
2717 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2718 report.Error (246, loc,
2719 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2723 report.Error (246, loc,
2724 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2729 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2731 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2734 if (fne.Type != null && Arity > 0) {
2735 if (HasTypeArguments) {
2736 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2737 if (ct.ResolveAsType (mc) == null)
2743 targs.Resolve (mc, allowUnboundTypeArguments);
2745 return new GenericOpenTypeExpr (fne.Type, loc);
2749 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2751 if (!(fne is NamespaceExpression))
2755 if (Arity == 0 && Name == "dynamic" && !(mc is NamespaceContainer) && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2756 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2757 mc.Module.Compiler.Report.Error (1980, Location,
2758 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2759 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2762 fne = new DynamicTypeExpr (loc);
2763 fne.ResolveAsType (mc);
2769 Error_TypeOrNamespaceNotFound (mc);
2773 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2775 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2778 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2780 int lookup_arity = Arity;
2781 bool errorMode = false;
2783 Block current_block = rc.CurrentBlock;
2784 INamedBlockVariable variable = null;
2785 bool variable_found = false;
2789 // Stage 1: binding to local variables or parameters
2791 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2793 if (current_block != null && lookup_arity == 0) {
2794 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2795 if (!variable.IsDeclared) {
2796 // We found local name in accessible block but it's not
2797 // initialized yet, maybe the user wanted to bind to something else
2799 variable_found = true;
2801 e = variable.CreateReferenceExpression (rc, loc);
2804 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2813 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2815 TypeSpec member_type = rc.CurrentType;
2816 for (; member_type != null; member_type = member_type.DeclaringType) {
2817 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2821 var me = e as MemberExpr;
2823 // The name matches a type, defer to ResolveAsTypeStep
2831 if (variable != null) {
2832 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2833 rc.Report.Error (844, loc,
2834 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2835 Name, me.GetSignatureForError ());
2839 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2840 // Leave it to overload resolution to report correct error
2842 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2843 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2847 // MemberLookup does not check accessors availability, this is actually needed for properties only
2849 var pe = me as PropertyExpr;
2852 // Break as there is no other overload available anyway
2853 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2854 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2857 pe.Getter = pe.PropertyInfo.Get;
2859 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2862 pe.Setter = pe.PropertyInfo.Set;
2867 // TODO: It's used by EventExpr -> FieldExpr transformation only
2868 // TODO: Should go to MemberAccess
2869 me = me.ResolveMemberAccess (rc, null, null);
2872 targs.Resolve (rc, false);
2873 me.SetTypeArguments (rc, targs);
2880 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2882 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2883 if (IsPossibleTypeOrNamespace (rc)) {
2884 return ResolveAsTypeOrNamespace (rc, false);
2888 var expr = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2891 targs.Resolve (rc, false);
2893 var me = expr as MemberExpr;
2895 me.SetTypeArguments (rc, targs);
2900 if ((restrictions & MemberLookupRestrictions.NameOfExcluded) == 0 && Name == "nameof")
2901 return new NameOf (this);
2904 if (variable_found) {
2905 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2908 var tparams = rc.CurrentTypeParameters;
2909 if (tparams != null) {
2910 if (tparams.Find (Name) != null) {
2911 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2916 var ct = rc.CurrentType;
2918 if (ct.MemberDefinition.TypeParametersCount > 0) {
2919 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2920 if (ctp.Name == Name) {
2921 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2927 ct = ct.DeclaringType;
2928 } while (ct != null);
2931 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2932 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2934 rc.Report.SymbolRelatedToPreviousError (e.Type);
2935 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2939 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2941 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2942 return ErrorExpression.Instance;
2946 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2948 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2949 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2953 if (e is TypeExpr) {
2954 // TypeExpression does not have correct location
2955 if (e is TypeExpression)
2956 e = new TypeExpression (e.Type, loc);
2962 Error_NameDoesNotExist (rc);
2965 return ErrorExpression.Instance;
2968 if (rc.Module.Evaluator != null) {
2969 var fi = rc.Module.Evaluator.LookupField (Name);
2971 return new FieldExpr (fi.Item1, loc);
2979 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2981 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2986 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2987 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2991 if (right_side != null) {
2992 e = e.ResolveLValue (ec, right_side);
3000 public override object Accept (StructuralVisitor visitor)
3002 return visitor.Visit (this);
3007 /// Represents a namespace or a type. The name of the class was inspired by
3008 /// section 10.8.1 (Fully Qualified Names).
3010 public abstract class FullNamedExpression : Expression
3012 protected override void CloneTo (CloneContext clonectx, Expression target)
3014 // Do nothing, most unresolved type expressions cannot be
3015 // resolved to different type
3018 public override bool ContainsEmitWithAwait ()
3023 public override Expression CreateExpressionTree (ResolveContext ec)
3025 throw new NotSupportedException ("ET");
3028 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3031 // This is used to resolve the expression as a type, a null
3032 // value will be returned if the expression is not a type
3035 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3037 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3042 TypeExpr te = fne as TypeExpr;
3044 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3052 var dep = type.GetMissingDependencies ();
3054 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3057 if (type.Kind == MemberKind.Void) {
3058 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3062 // Obsolete checks cannot be done when resolving base context as they
3063 // require type dependencies to be set but we are in process of resolving them
3065 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3066 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3067 if (obsolete_attr != null && !mc.IsObsolete) {
3068 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3076 public override void Emit (EmitContext ec)
3078 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3079 GetSignatureForError ());
3084 /// Expression that evaluates to a type
3086 public abstract class TypeExpr : FullNamedExpression
3088 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3094 protected sealed override Expression DoResolve (ResolveContext ec)
3100 public override bool Equals (object obj)
3102 TypeExpr tobj = obj as TypeExpr;
3106 return Type == tobj.Type;
3109 public override int GetHashCode ()
3111 return Type.GetHashCode ();
3116 /// Fully resolved Expression that already evaluated to a type
3118 public class TypeExpression : TypeExpr
3120 public TypeExpression (TypeSpec t, Location l)
3123 eclass = ExprClass.Type;
3127 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3133 public class NamespaceExpression : FullNamedExpression
3135 readonly Namespace ns;
3137 public NamespaceExpression (Namespace ns, Location loc)
3140 this.Type = InternalType.Namespace;
3141 this.eclass = ExprClass.Namespace;
3145 public Namespace Namespace {
3151 protected override Expression DoResolve (ResolveContext rc)
3153 throw new NotImplementedException ();
3156 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3161 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity, Location loc)
3163 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3164 if (retval != null) {
3165 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3166 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3170 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3171 if (retval != null) {
3172 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3177 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3178 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3182 string assembly = null;
3183 string possible_name = Namespace.GetSignatureForError () + "." + name;
3185 // Only assembly unique name should be added
3186 switch (possible_name) {
3187 case "System.Drawing":
3188 case "System.Web.Services":
3191 case "System.Configuration":
3192 case "System.Data.Services":
3193 case "System.DirectoryServices":
3195 case "System.Net.Http":
3196 case "System.Numerics":
3197 case "System.Runtime.Caching":
3198 case "System.ServiceModel":
3199 case "System.Transactions":
3200 case "System.Web.Routing":
3201 case "System.Xml.Linq":
3203 assembly = possible_name;
3207 case "System.Linq.Expressions":
3208 assembly = "System.Core";
3211 case "System.Windows.Forms":
3212 case "System.Windows.Forms.Layout":
3213 assembly = "System.Windows.Forms";
3217 assembly = assembly == null ? "an" : "`" + assembly + "'";
3219 if (Namespace is GlobalRootNamespace) {
3220 ctx.Module.Compiler.Report.Error (400, loc,
3221 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3224 ctx.Module.Compiler.Report.Error (234, loc,
3225 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3226 name, GetSignatureForError (), assembly);
3230 public override string GetSignatureForError ()
3232 return ns.GetSignatureForError ();
3235 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3237 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3240 public override string ToString ()
3242 return Namespace.Name;
3247 /// This class denotes an expression which evaluates to a member
3248 /// of a struct or a class.
3250 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3252 protected bool conditional_access_receiver;
3255 // An instance expression associated with this member, if it's a
3256 // non-static member
3258 public Expression InstanceExpression;
3261 /// The name of this member.
3263 public abstract string Name {
3268 // When base.member is used
3270 public bool IsBase {
3271 get { return InstanceExpression is BaseThis; }
3275 /// Whether this is an instance member.
3277 public abstract bool IsInstance {
3282 /// Whether this is a static member.
3284 public abstract bool IsStatic {
3288 public abstract string KindName {
3292 public bool ConditionalAccess { get; set; }
3294 protected abstract TypeSpec DeclaringType {
3298 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3300 return InstanceExpression.Type;
3305 // Converts best base candidate for virtual method starting from QueriedBaseType
3307 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3310 // Only when base.member is used and method is virtual
3316 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3317 // means for base.member access we have to find the closest match after we found best candidate
3319 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3321 // The method could already be what we are looking for
3323 TypeSpec[] targs = null;
3324 if (method.DeclaringType != InstanceExpression.Type) {
3326 // Candidate can have inflated MVAR parameters and we need to find
3327 // base match for original definition not inflated parameter types
3329 var parameters = method.Parameters;
3330 if (method.Arity > 0) {
3331 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3332 var inflated = method.DeclaringType as InflatedTypeSpec;
3333 if (inflated != null) {
3334 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3338 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3339 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3340 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3341 if (base_override.IsGeneric)
3342 targs = method.TypeArguments;
3344 method = base_override;
3349 // When base access is used inside anonymous method/iterator/etc we need to
3350 // get back to the context of original type. We do it by emiting proxy
3351 // method in original class and rewriting base call to this compiler
3352 // generated method call which does the actual base invocation. This may
3353 // introduce redundant storey but with `this' only but it's tricky to avoid
3354 // at this stage as we don't know what expressions follow base
3356 if (rc.CurrentAnonymousMethod != null) {
3357 if (targs == null && method.IsGeneric) {
3358 targs = method.TypeArguments;
3359 method = method.GetGenericMethodDefinition ();
3362 if (method.Parameters.HasArglist)
3363 throw new NotImplementedException ("__arglist base call proxy");
3365 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3367 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3368 // get/set member expressions second call would fail to proxy because left expression
3369 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3370 // FIXME: The async check is another hack but will probably fail with mutators
3371 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3372 InstanceExpression = new This (loc).Resolve (rc);
3376 method = method.MakeGenericMethod (rc, targs);
3380 // Only base will allow this invocation to happen.
3382 if (method.IsAbstract) {
3383 rc.Report.SymbolRelatedToPreviousError (method);
3384 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3390 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3392 if (InstanceExpression == null)
3395 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3396 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3397 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3402 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3404 if (InstanceExpression == null)
3407 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3410 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3412 var ct = rc.CurrentType;
3413 if (ct == qualifier)
3416 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3419 qualifier = qualifier.GetDefinition ();
3420 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3427 public override bool ContainsEmitWithAwait ()
3429 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3432 public override bool HasConditionalAccess ()
3434 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3437 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3440 type = type.GetDefinition ();
3442 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3445 type = type.DeclaringType;
3446 } while (type != null);
3451 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3453 if (InstanceExpression != null) {
3454 InstanceExpression = InstanceExpression.Resolve (rc);
3455 CheckProtectedMemberAccess (rc, member);
3458 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3459 UnsafeError (rc, loc);
3462 var dep = member.GetMissingDependencies ();
3464 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3467 if (!rc.IsObsolete) {
3468 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3470 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3473 if (!(member is FieldSpec))
3474 member.MemberDefinition.SetIsUsed ();
3477 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3479 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3482 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3484 rc.Report.SymbolRelatedToPreviousError (member);
3485 rc.Report.Error (1540, loc,
3486 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3487 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3490 public override void FlowAnalysis (FlowAnalysisContext fc)
3492 if (InstanceExpression != null) {
3493 InstanceExpression.FlowAnalysis (fc);
3495 if (ConditionalAccess) {
3496 fc.BranchConditionalAccessDefiniteAssignment ();
3501 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3503 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3504 if (HasConditionalAccess ()) {
3505 conditional_access_receiver = true;
3506 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3511 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3513 if (!ResolveInstanceExpressionCore (rc, rhs))
3517 // Check intermediate value modification which won't have any effect
3519 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3520 var fexpr = InstanceExpression as FieldExpr;
3521 if (fexpr != null) {
3522 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3525 if (fexpr.IsStatic) {
3526 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3527 fexpr.GetSignatureForError ());
3529 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3530 fexpr.GetSignatureForError ());
3536 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3537 if (rc.CurrentInitializerVariable != null) {
3538 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3539 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3541 rc.Report.Error (1612, loc,
3542 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3543 InstanceExpression.GetSignatureForError ());
3549 var lvr = InstanceExpression as LocalVariableReference;
3552 if (!lvr.local_info.IsReadonly)
3555 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3556 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3563 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3566 if (InstanceExpression != null) {
3567 if (InstanceExpression is TypeExpr) {
3568 var t = InstanceExpression.Type;
3570 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3571 if (oa != null && !rc.IsObsolete) {
3572 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3575 t = t.DeclaringType;
3576 } while (t != null);
3578 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3579 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3580 rc.Report.Error (176, loc,
3581 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3582 GetSignatureForError ());
3586 InstanceExpression = null;
3592 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3593 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3594 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3595 rc.Report.Error (236, loc,
3596 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3597 GetSignatureForError ());
3599 var fe = this as FieldExpr;
3600 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3601 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3602 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3604 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3608 rc.Report.Error (120, loc,
3609 "An object reference is required to access non-static member `{0}'",
3610 GetSignatureForError ());
3614 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3618 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3619 rc.Report.Error (38, loc,
3620 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3621 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3624 InstanceExpression = new This (loc).Resolve (rc);
3628 var me = InstanceExpression as MemberExpr;
3630 me.ResolveInstanceExpressionCore (rc, rhs);
3632 var fe = me as FieldExpr;
3633 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3634 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3635 rc.Report.Warning (1690, 1, loc,
3636 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3637 me.GetSignatureForError ());
3644 // Additional checks for l-value member access
3647 if (InstanceExpression is UnboxCast) {
3648 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3655 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3657 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3658 ec.Report.Warning (1720, 1, left.Location,
3659 "Expression will always cause a `{0}'", "System.NullReferenceException");
3662 InstanceExpression = left;
3666 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3668 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3669 inst.Emit (ec, ConditionalAccess);
3671 if (prepare_for_load)
3672 ec.Emit (OpCodes.Dup);
3675 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3678 public class ExtensionMethodCandidates
3680 readonly NamespaceContainer container;
3681 readonly IList<MethodSpec> methods;
3683 readonly IMemberContext context;
3685 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3687 this.context = context;
3688 this.methods = methods;
3689 this.container = nsContainer;
3690 this.index = lookupIndex;
3693 public NamespaceContainer Container {
3699 public IMemberContext Context {
3705 public int LookupIndex {
3711 public IList<MethodSpec> Methods {
3719 // Represents a group of extension method candidates for whole namespace
3721 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3723 ExtensionMethodCandidates candidates;
3724 public Expression ExtensionExpression;
3726 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3727 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3729 this.candidates = candidates;
3730 this.ExtensionExpression = extensionExpr;
3733 public override bool IsStatic {
3734 get { return true; }
3737 public override void FlowAnalysis (FlowAnalysisContext fc)
3739 if (ConditionalAccess) {
3740 fc.BranchConditionalAccessDefiniteAssignment ();
3745 // For extension methodgroup we are not looking for base members but parent
3746 // namespace extension methods
3748 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3750 // TODO: candidates are null only when doing error reporting, that's
3751 // incorrect. We have to discover same extension methods in error mode
3752 if (candidates == null)
3755 int arity = type_arguments == null ? 0 : type_arguments.Count;
3757 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, Name, arity, candidates.LookupIndex);
3758 if (candidates == null)
3761 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3764 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3767 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3769 // LAMESPEC: or implicit type parameter conversion
3771 return argType == extensionType ||
3772 TypeSpecComparer.IsEqual (argType, extensionType) ||
3773 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3774 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3777 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3779 rc.Report.Error (8093, ma.Location, "An argument to nameof operator cannot be extension method group");
3781 // Not included in C#6
3783 ExtensionExpression = ExtensionExpression.Resolve (rc);
3784 if (ExtensionExpression == null)
3787 var argType = ExtensionExpression.Type;
3788 foreach (MethodSpec candidate in Candidates) {
3789 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3793 // TODO: Scan full hierarchy
3795 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3800 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3802 // We are already here
3806 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3808 if (arguments == null)
3809 arguments = new Arguments (1);
3811 ExtensionExpression = ExtensionExpression.Resolve (ec);
3812 if (ExtensionExpression == null)
3815 var cand = candidates;
3816 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3817 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3818 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3820 // Restore candidates in case we are running in probing mode
3823 // Store resolved argument and restore original arguments
3825 // Clean-up modified arguments for error reporting
3826 arguments.RemoveAt (0);
3830 var me = ExtensionExpression as MemberExpr;
3832 me.ResolveInstanceExpression (ec, null);
3833 var fe = me as FieldExpr;
3835 fe.Spec.MemberDefinition.SetIsUsed ();
3838 InstanceExpression = null;
3842 #region IErrorHandler Members
3844 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3849 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3851 rc.Report.SymbolRelatedToPreviousError (best);
3854 rc.Report.Error (1929, loc,
3855 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' requires an instance of type `{3}'",
3856 queried_type.GetSignatureForError (), Name, best.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3858 rc.Report.Error (1928, loc,
3859 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3860 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3866 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3871 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3880 /// MethodGroupExpr represents a group of method candidates which
3881 /// can be resolved to the best method overload
3883 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3885 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3887 protected IList<MemberSpec> Methods;
3888 MethodSpec best_candidate;
3889 TypeSpec best_candidate_return;
3890 protected TypeArguments type_arguments;
3892 SimpleName simple_name;
3893 protected TypeSpec queried_type;
3895 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3899 this.type = InternalType.MethodGroup;
3901 eclass = ExprClass.MethodGroup;
3902 queried_type = type;
3905 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3906 : this (new MemberSpec[] { m }, type, loc)
3912 public MethodSpec BestCandidate {
3914 return best_candidate;
3918 public TypeSpec BestCandidateReturnType {
3920 return best_candidate_return;
3924 public IList<MemberSpec> Candidates {
3930 protected override TypeSpec DeclaringType {
3932 return queried_type;
3936 public bool IsConditionallyExcluded {
3938 return Methods == Excluded;
3942 public override bool IsInstance {
3944 if (best_candidate != null)
3945 return !best_candidate.IsStatic;
3951 public override bool IsSideEffectFree {
3953 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3957 public override bool IsStatic {
3959 if (best_candidate != null)
3960 return best_candidate.IsStatic;
3966 public override string KindName {
3967 get { return "method"; }
3970 public override string Name {
3972 if (best_candidate != null)
3973 return best_candidate.Name;
3976 return Methods.First ().Name;
3983 // When best candidate is already know this factory can be used
3984 // to avoid expensive overload resolution to be called
3986 // NOTE: InstanceExpression has to be set manually
3988 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3990 return new MethodGroupExpr (best, queriedType, loc) {
3991 best_candidate = best,
3992 best_candidate_return = best.ReturnType
3996 public override string GetSignatureForError ()
3998 if (best_candidate != null)
3999 return best_candidate.GetSignatureForError ();
4001 return Methods.First ().GetSignatureForError ();
4004 public override Expression CreateExpressionTree (ResolveContext ec)
4006 if (best_candidate == null) {
4007 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
4011 if (IsConditionallyExcluded)
4012 ec.Report.Error (765, loc,
4013 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
4015 if (ConditionalAccess)
4016 Error_NullShortCircuitInsideExpressionTree (ec);
4018 return new TypeOfMethod (best_candidate, loc);
4021 protected override Expression DoResolve (ResolveContext ec)
4023 this.eclass = ExprClass.MethodGroup;
4025 if (InstanceExpression != null) {
4026 InstanceExpression = InstanceExpression.Resolve (ec);
4027 if (InstanceExpression == null)
4034 public override void Emit (EmitContext ec)
4036 throw new NotSupportedException ();
4039 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4041 var call = new CallEmitter ();
4042 call.InstanceExpression = InstanceExpression;
4043 call.ConditionalAccess = ConditionalAccess;
4046 call.EmitStatement (ec, best_candidate, arguments, loc);
4048 call.Emit (ec, best_candidate, arguments, loc);
4051 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4053 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4054 Statement = statement
4057 EmitCall (ec, arguments, statement);
4059 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4062 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4064 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4065 Name, target.GetSignatureForError ());
4068 public bool HasAccessibleCandidate (ResolveContext rc)
4070 foreach (var candidate in Candidates) {
4071 if (candidate.IsAccessible (rc))
4078 public static bool IsExtensionMethodArgument (Expression expr)
4081 // LAMESPEC: No details about which expressions are not allowed
4083 return !(expr is TypeExpr) && !(expr is BaseThis);
4087 /// Find the Applicable Function Members (7.4.2.1)
4089 /// me: Method Group expression with the members to select.
4090 /// it might contain constructors or methods (or anything
4091 /// that maps to a method).
4093 /// Arguments: ArrayList containing resolved Argument objects.
4095 /// loc: The location if we want an error to be reported, or a Null
4096 /// location for "probing" purposes.
4098 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4099 /// that is the best match of me on Arguments.
4102 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4104 // TODO: causes issues with probing mode, remove explicit Kind check
4105 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4108 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4109 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4110 r.BaseMembersProvider = this;
4111 r.InstanceQualifier = this;
4114 if (cerrors != null)
4115 r.CustomErrors = cerrors;
4117 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4118 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4119 if (best_candidate == null) {
4120 if (!r.BestCandidateIsDynamic)
4123 if (simple_name != null && ec.IsStatic)
4124 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4129 // Overload resolver had to create a new method group, all checks bellow have already been executed
4130 if (r.BestCandidateNewMethodGroup != null)
4131 return r.BestCandidateNewMethodGroup;
4133 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4134 if (InstanceExpression != null) {
4135 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4136 InstanceExpression = null;
4138 if (simple_name != null && best_candidate.IsStatic) {
4139 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4142 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4146 ResolveInstanceExpression (ec, null);
4149 var base_override = CandidateToBaseOverride (ec, best_candidate);
4150 if (base_override == best_candidate) {
4151 best_candidate_return = r.BestCandidateReturnType;
4153 best_candidate = base_override;
4154 best_candidate_return = best_candidate.ReturnType;
4157 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4158 ConstraintChecker cc = new ConstraintChecker (ec);
4159 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4163 // Additional check for possible imported base override method which
4164 // could not be done during IsOverrideMethodBaseTypeAccessible
4166 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4167 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4168 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4169 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4172 // Speed up the check by not doing it on disallowed targets
4173 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4179 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4181 var fe = left as FieldExpr;
4184 // Using method-group on struct fields makes the struct assigned. I am not sure
4185 // why but that's what .net does
4187 fe.Spec.MemberDefinition.SetIsAssigned ();
4190 simple_name = original;
4191 return base.ResolveMemberAccess (ec, left, original);
4194 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4196 type_arguments = ta;
4199 #region IBaseMembersProvider Members
4201 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4203 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4206 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4208 if (queried_type == member.DeclaringType)
4211 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4212 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4216 // Extension methods lookup after ordinary methods candidates failed to apply
4218 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4220 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4223 if (!IsExtensionMethodArgument (InstanceExpression))
4226 int arity = type_arguments == null ? 0 : type_arguments.Count;
4227 var methods = rc.LookupExtensionMethod (Methods[0].Name, arity);
4228 if (methods == null)
4231 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4232 emg.SetTypeArguments (rc, type_arguments);
4239 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4241 public ConstructorInstanceQualifier (TypeSpec type)
4244 InstanceType = type;
4247 public TypeSpec InstanceType { get; private set; }
4249 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4251 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4255 public struct OverloadResolver
4258 public enum Restrictions
4262 ProbingOnly = 1 << 1,
4263 CovariantDelegate = 1 << 2,
4264 NoBaseMembers = 1 << 3,
4265 BaseMembersIncluded = 1 << 4,
4266 GetEnumeratorLookup = 1 << 5
4269 public interface IBaseMembersProvider
4271 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4272 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4273 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4276 public interface IErrorHandler
4278 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4279 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4280 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4281 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4284 public interface IInstanceQualifier
4286 TypeSpec InstanceType { get; }
4287 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4290 sealed class NoBaseMembers : IBaseMembersProvider
4292 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4294 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4299 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4304 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4310 struct AmbiguousCandidate
4312 public readonly MemberSpec Member;
4313 public readonly bool Expanded;
4314 public readonly AParametersCollection Parameters;
4316 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4319 Parameters = parameters;
4320 Expanded = expanded;
4325 IList<MemberSpec> members;
4326 TypeArguments type_arguments;
4327 IBaseMembersProvider base_provider;
4328 IErrorHandler custom_errors;
4329 IInstanceQualifier instance_qualifier;
4330 Restrictions restrictions;
4331 MethodGroupExpr best_candidate_extension_group;
4332 TypeSpec best_candidate_return_type;
4334 SessionReportPrinter lambda_conv_msgs;
4336 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4337 : this (members, null, restrictions, loc)
4341 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4344 if (members == null || members.Count == 0)
4345 throw new ArgumentException ("empty members set");
4347 this.members = members;
4349 type_arguments = targs;
4350 this.restrictions = restrictions;
4351 if (IsDelegateInvoke)
4352 this.restrictions |= Restrictions.NoBaseMembers;
4354 base_provider = NoBaseMembers.Instance;
4359 public IBaseMembersProvider BaseMembersProvider {
4361 return base_provider;
4364 base_provider = value;
4368 public bool BestCandidateIsDynamic { get; set; }
4371 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4373 public MethodGroupExpr BestCandidateNewMethodGroup {
4375 return best_candidate_extension_group;
4380 // Return type can be different between best candidate and closest override
4382 public TypeSpec BestCandidateReturnType {
4384 return best_candidate_return_type;
4388 public IErrorHandler CustomErrors {
4390 return custom_errors;
4393 custom_errors = value;
4397 TypeSpec DelegateType {
4399 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4400 throw new InternalErrorException ("Not running in delegate mode", loc);
4402 return members [0].DeclaringType;
4406 public IInstanceQualifier InstanceQualifier {
4408 return instance_qualifier;
4411 instance_qualifier = value;
4415 bool IsProbingOnly {
4417 return (restrictions & Restrictions.ProbingOnly) != 0;
4421 bool IsDelegateInvoke {
4423 return (restrictions & Restrictions.DelegateInvoke) != 0;
4430 // 7.4.3.3 Better conversion from expression
4431 // Returns : 1 if a->p is better,
4432 // 2 if a->q is better,
4433 // 0 if neither is better
4435 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4437 TypeSpec argument_type = a.Type;
4440 // If argument is an anonymous function
4442 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4444 // p and q are delegate types or expression tree types
4446 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4447 if (q.MemberDefinition != p.MemberDefinition) {
4452 // Uwrap delegate from Expression<T>
4454 q = TypeManager.GetTypeArguments (q)[0];
4455 p = TypeManager.GetTypeArguments (p)[0];
4458 var p_m = Delegate.GetInvokeMethod (p);
4459 var q_m = Delegate.GetInvokeMethod (q);
4462 // With identical parameter lists
4464 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4472 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4474 if (p.Kind == MemberKind.Void) {
4475 return q.Kind != MemberKind.Void ? 2 : 0;
4479 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4481 if (q.Kind == MemberKind.Void) {
4482 return p.Kind != MemberKind.Void ? 1: 0;
4485 var am = (AnonymousMethodExpression) a.Expr;
4488 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4489 // better conversion is performed between underlying types Y1 and Y2
4491 if (p.IsGenericTask || q.IsGenericTask) {
4492 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4493 q = q.TypeArguments[0];
4494 p = p.TypeArguments[0];
4500 // An inferred return type X exists for E in the context of that parameter list, and
4501 // the conversion from X to Y1 is better than the conversion from X to Y2
4503 argument_type = am.InferReturnType (ec, null, orig_q);
4504 if (argument_type == null) {
4505 // TODO: Can this be hit?
4509 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4510 argument_type = ec.BuiltinTypes.Object;
4514 if (argument_type == p)
4517 if (argument_type == q)
4521 // The parameters are identicial and return type is not void, use better type conversion
4522 // on return type to determine better one
4524 return BetterTypeConversion (ec, p, q);
4528 // 7.4.3.4 Better conversion from type
4530 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4532 if (p == null || q == null)
4533 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4535 switch (p.BuiltinType) {
4536 case BuiltinTypeSpec.Type.Int:
4537 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4540 case BuiltinTypeSpec.Type.Long:
4541 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4544 case BuiltinTypeSpec.Type.SByte:
4545 switch (q.BuiltinType) {
4546 case BuiltinTypeSpec.Type.Byte:
4547 case BuiltinTypeSpec.Type.UShort:
4548 case BuiltinTypeSpec.Type.UInt:
4549 case BuiltinTypeSpec.Type.ULong:
4553 case BuiltinTypeSpec.Type.Short:
4554 switch (q.BuiltinType) {
4555 case BuiltinTypeSpec.Type.UShort:
4556 case BuiltinTypeSpec.Type.UInt:
4557 case BuiltinTypeSpec.Type.ULong:
4561 case BuiltinTypeSpec.Type.Dynamic:
4562 // Dynamic is never better
4566 switch (q.BuiltinType) {
4567 case BuiltinTypeSpec.Type.Int:
4568 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4571 case BuiltinTypeSpec.Type.Long:
4572 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4575 case BuiltinTypeSpec.Type.SByte:
4576 switch (p.BuiltinType) {
4577 case BuiltinTypeSpec.Type.Byte:
4578 case BuiltinTypeSpec.Type.UShort:
4579 case BuiltinTypeSpec.Type.UInt:
4580 case BuiltinTypeSpec.Type.ULong:
4584 case BuiltinTypeSpec.Type.Short:
4585 switch (p.BuiltinType) {
4586 case BuiltinTypeSpec.Type.UShort:
4587 case BuiltinTypeSpec.Type.UInt:
4588 case BuiltinTypeSpec.Type.ULong:
4592 case BuiltinTypeSpec.Type.Dynamic:
4593 // Dynamic is never better
4597 // FIXME: handle lifted operators
4599 // TODO: this is expensive
4600 Expression p_tmp = new EmptyExpression (p);
4601 Expression q_tmp = new EmptyExpression (q);
4603 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4604 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4606 if (p_to_q && !q_to_p)
4609 if (q_to_p && !p_to_q)
4616 /// Determines "Better function" between candidate
4617 /// and the current best match
4620 /// Returns a boolean indicating :
4621 /// false if candidate ain't better
4622 /// true if candidate is better than the current best match
4624 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4625 MemberSpec best, AParametersCollection bparam, bool best_params)
4627 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4628 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4630 bool better_at_least_one = false;
4631 bool are_equivalent = true;
4632 int args_count = args == null ? 0 : args.Count;
4636 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4639 // Default arguments are ignored for better decision
4640 if (a.IsDefaultArgument)
4644 // When comparing named argument the parameter type index has to be looked up
4645 // in original parameter set (override version for virtual members)
4647 NamedArgument na = a as NamedArgument;
4649 int idx = cparam.GetParameterIndexByName (na.Name);
4650 ct = candidate_pd.Types[idx];
4651 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4652 ct = TypeManager.GetElementType (ct);
4654 idx = bparam.GetParameterIndexByName (na.Name);
4655 bt = best_pd.Types[idx];
4656 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4657 bt = TypeManager.GetElementType (bt);
4659 ct = candidate_pd.Types[c_idx];
4660 bt = best_pd.Types[b_idx];
4662 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4663 ct = TypeManager.GetElementType (ct);
4667 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4668 bt = TypeManager.GetElementType (bt);
4673 if (TypeSpecComparer.IsEqual (ct, bt))
4676 are_equivalent = false;
4677 int result = BetterExpressionConversion (ec, a, ct, bt);
4679 // for each argument, the conversion to 'ct' should be no worse than
4680 // the conversion to 'bt'.
4684 // for at least one argument, the conversion to 'ct' should be better than
4685 // the conversion to 'bt'.
4687 better_at_least_one = true;
4690 if (better_at_least_one)
4694 // Tie-breaking rules are applied only for equivalent parameter types
4696 if (!are_equivalent) {
4698 // LAMESPEC: A candidate with less default parameters is still better when there
4699 // is no better expression conversion
4701 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4709 // If candidate is applicable in its normal form and best has a params array and is applicable
4710 // only in its expanded form, then candidate is better
4712 if (candidate_params != best_params)
4713 return !candidate_params;
4716 // We have not reached end of parameters list due to params or used default parameters
4718 while (j < candidate_pd.Count && j < best_pd.Count) {
4719 var cand_param = candidate_pd.FixedParameters [j];
4720 var best_param = best_pd.FixedParameters [j];
4722 if (candidate_pd.Count == best_pd.Count) {
4726 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4727 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4729 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4730 return cand_param.HasDefaultValue;
4732 if (cand_param.HasDefaultValue) {
4738 // Neither is better when not all arguments are provided
4740 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4741 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4742 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4744 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4751 if (candidate_pd.Count != best_pd.Count)
4752 return candidate_pd.Count < best_pd.Count;
4755 // One is a non-generic method and second is a generic method, then non-generic is better
4757 if (best.IsGeneric != candidate.IsGeneric)
4758 return best.IsGeneric;
4761 // Both methods have the same number of parameters, and the parameters have equal types
4762 // Pick the "more specific" signature using rules over original (non-inflated) types
4764 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4765 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4767 bool specific_at_least_once = false;
4768 for (j = 0; j < args_count; ++j) {
4769 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4771 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4772 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4774 ct = candidate_def_pd.Types[j];
4775 bt = best_def_pd.Types[j];
4780 TypeSpec specific = MoreSpecific (ct, bt);
4784 specific_at_least_once = true;
4787 if (specific_at_least_once)
4793 static bool CheckInflatedArguments (MethodSpec ms)
4795 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4798 // Setup constraint checker for probing only
4799 ConstraintChecker cc = new ConstraintChecker (null);
4801 var mp = ms.Parameters.Types;
4802 for (int i = 0; i < mp.Length; ++i) {
4803 var type = mp[i] as InflatedTypeSpec;
4807 var targs = type.TypeArguments;
4808 if (targs.Length == 0)
4811 // TODO: Checking inflated MVAR arguments should be enough
4812 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4819 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4821 rc.Report.Error (1729, loc,
4822 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4823 type.GetSignatureForError (), argCount.ToString ());
4827 // Determines if the candidate method is applicable to the given set of arguments
4828 // There could be two different set of parameters for same candidate where one
4829 // is the closest override for default values and named arguments checks and second
4830 // one being the virtual base for the parameter types and modifiers.
4832 // A return value rates candidate method compatibility,
4834 // 0 = the best, int.MaxValue = the worst
4836 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)
4839 // Each step has allocated 10 values, it can overflow for
4840 // more than 10 arguments but that's ok as it's used for
4841 // better error reporting only
4843 const int ArgumentCountMismatch = 1000000000;
4844 const int NamedArgumentsMismatch = 100000000;
4845 const int DefaultArgumentMismatch = 10000000;
4846 const int UnexpectedTypeArguments = 1000000;
4847 const int TypeArgumentsMismatch = 100000;
4848 const int InflatedTypesMismatch = 10000;
4850 // Parameters of most-derived type used mainly for named and optional parameters
4851 var pd = pm.Parameters;
4853 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4854 // params modifier instead of most-derived type
4855 var cpd = ((IParametersMember) candidate).Parameters;
4856 int param_count = pd.Count;
4857 int optional_count = 0;
4859 Arguments orig_args = arguments;
4861 if (arg_count != param_count) {
4863 // No arguments expansion when doing exact match for delegates
4865 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4866 for (int i = 0; i < pd.Count; ++i) {
4867 if (pd.FixedParameters[i].HasDefaultValue) {
4868 optional_count = pd.Count - i;
4874 if (optional_count != 0) {
4875 // Readjust expected number when params used
4876 if (cpd.HasParams) {
4878 if (arg_count < param_count)
4880 } else if (arg_count > param_count) {
4881 int args_gap = System.Math.Abs (arg_count - param_count);
4882 return ArgumentCountMismatch + args_gap;
4883 } else if (arg_count < param_count - optional_count) {
4884 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4885 return ArgumentCountMismatch + args_gap;
4887 } else if (arg_count != param_count) {
4888 int args_gap = System.Math.Abs (arg_count - param_count);
4890 return ArgumentCountMismatch + args_gap;
4891 if (arg_count < param_count - 1)
4892 return ArgumentCountMismatch + args_gap;
4895 // Resize to fit optional arguments
4896 if (optional_count != 0) {
4897 if (arguments == null) {
4898 arguments = new Arguments (optional_count);
4900 // Have to create a new container, so the next run can do same
4901 var resized = new Arguments (param_count);
4902 resized.AddRange (arguments);
4903 arguments = resized;
4906 for (int i = arg_count; i < param_count; ++i)
4907 arguments.Add (null);
4911 if (arg_count > 0) {
4913 // Shuffle named arguments to the right positions if there are any
4915 if (arguments[arg_count - 1] is NamedArgument) {
4916 arg_count = arguments.Count;
4918 for (int i = 0; i < arg_count; ++i) {
4919 bool arg_moved = false;
4921 NamedArgument na = arguments[i] as NamedArgument;
4925 int index = pd.GetParameterIndexByName (na.Name);
4927 // Named parameter not found
4929 return NamedArgumentsMismatch - i;
4931 // already reordered
4936 if (index >= param_count) {
4937 // When using parameters which should not be available to the user
4938 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4941 arguments.Add (null);
4945 if (index == arg_count)
4946 return NamedArgumentsMismatch - i - 1;
4948 temp = arguments [index];
4950 // The slot has been taken by positional argument
4951 if (temp != null && !(temp is NamedArgument))
4956 arguments = arguments.MarkOrderedArgument (na);
4960 if (arguments == orig_args) {
4961 arguments = new Arguments (orig_args.Count);
4962 arguments.AddRange (orig_args);
4965 arguments[index] = arguments[i];
4966 arguments[i] = temp;
4973 arg_count = arguments.Count;
4975 } else if (arguments != null) {
4976 arg_count = arguments.Count;
4980 // Don't do any expensive checks when the candidate cannot succeed
4982 if (arg_count != param_count && !cpd.HasParams)
4983 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4985 var dep = candidate.GetMissingDependencies ();
4987 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4992 // 1. Handle generic method using type arguments when specified or type inference
4995 var ms = candidate as MethodSpec;
4996 if (ms != null && ms.IsGeneric) {
4997 if (type_arguments != null) {
4998 var g_args_count = ms.Arity;
4999 if (g_args_count != type_arguments.Count)
5000 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
5002 if (type_arguments.Arguments != null)
5003 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
5006 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
5007 // probing lambda methods keep all errors reported in separate set and once we are done and no best
5008 // candidate was found use the set to report more details about what was wrong with lambda body.
5009 // The general idea is to distinguish between code errors and errors caused by
5010 // trial-and-error type inference
5012 if (lambda_conv_msgs == null) {
5013 for (int i = 0; i < arg_count; i++) {
5014 Argument a = arguments[i];
5018 var am = a.Expr as AnonymousMethodExpression;
5020 if (lambda_conv_msgs == null)
5021 lambda_conv_msgs = new SessionReportPrinter ();
5023 am.TypeInferenceReportPrinter = lambda_conv_msgs;
5028 var ti = new TypeInference (arguments);
5029 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
5032 return TypeArgumentsMismatch - ti.InferenceScore;
5035 // Clear any error messages when the result was success
5037 if (lambda_conv_msgs != null)
5038 lambda_conv_msgs.ClearSession ();
5040 if (i_args.Length != 0) {
5042 for (int i = 0; i < i_args.Length; ++i) {
5043 var ta = i_args [i];
5044 if (!ta.IsAccessible (ec))
5045 return TypeArgumentsMismatch - i;
5049 ms = ms.MakeGenericMethod (ec, i_args);
5054 // Type arguments constraints have to match for the method to be applicable
5056 if (!CheckInflatedArguments (ms)) {
5058 return InflatedTypesMismatch;
5062 // We have a generic return type and at same time the method is override which
5063 // means we have to also inflate override return type in case the candidate is
5064 // best candidate and override return type is different to base return type.
5066 // virtual Foo<T, object> with override Foo<T, dynamic>
5068 if (candidate != pm) {
5069 MethodSpec override_ms = (MethodSpec) pm;
5070 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5071 returnType = inflator.Inflate (returnType);
5073 returnType = ms.ReturnType;
5080 if (type_arguments != null)
5081 return UnexpectedTypeArguments;
5087 // 2. Each argument has to be implicitly convertible to method parameter
5089 Parameter.Modifier p_mod = 0;
5092 for (int i = 0; i < arg_count; i++) {
5093 Argument a = arguments[i];
5095 var fp = pd.FixedParameters[i];
5096 if (!fp.HasDefaultValue) {
5097 arguments = orig_args;
5098 return arg_count * 2 + 2;
5102 // Get the default value expression, we can use the same expression
5103 // if the type matches
5105 Expression e = fp.DefaultValue;
5107 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5109 // Restore for possible error reporting
5110 for (int ii = i; ii < arg_count; ++ii)
5111 arguments.RemoveAt (i);
5113 return (arg_count - i) * 2 + 1;
5117 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5119 // LAMESPEC: Attributes can be mixed together with build-in priority
5121 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5122 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5123 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5124 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5125 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5126 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5130 arguments[i] = new Argument (e, Argument.AType.Default);
5134 if (p_mod != Parameter.Modifier.PARAMS) {
5135 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5137 } else if (!params_expanded_form) {
5138 params_expanded_form = true;
5139 pt = ((ElementTypeSpec) pt).Element;
5145 if (!params_expanded_form) {
5146 if (a.IsExtensionType) {
5147 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5152 score = IsArgumentCompatible (ec, a, p_mod, pt);
5155 dynamicArgument = true;
5160 // It can be applicable in expanded form (when not doing exact match like for delegates)
5162 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5163 if (!params_expanded_form) {
5164 pt = ((ElementTypeSpec) pt).Element;
5168 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5171 params_expanded_form = true;
5172 dynamicArgument = true;
5173 } else if (score == 0 || arg_count > pd.Count) {
5174 params_expanded_form = true;
5179 if (params_expanded_form)
5181 return (arg_count - i) * 2 + score;
5186 // Restore original arguments for dynamic binder to keep the intention of original source code
5188 if (dynamicArgument)
5189 arguments = orig_args;
5194 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5196 if (e is Constant && e.Type == ptype)
5200 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5202 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5203 e = new MemberAccess (new MemberAccess (new MemberAccess (
5204 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5205 } else if (e is Constant) {
5207 // Handles int to int? conversions, DefaultParameterValue check
5209 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5213 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5216 return e.Resolve (ec);
5220 // Tests argument compatibility with the parameter
5221 // The possible return values are
5223 // 1 - modifier mismatch
5224 // 2 - type mismatch
5225 // -1 - dynamic binding required
5227 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5230 // Types have to be identical when ref or out modifer
5231 // is used and argument is not of dynamic type
5233 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5234 var arg_type = argument.Type;
5236 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5238 // Using dynamic for ref/out parameter can still succeed at runtime
5240 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5246 if (arg_type != parameter) {
5247 if (arg_type == InternalType.VarOutType)
5251 // Do full equality check after quick path
5253 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5255 // Using dynamic for ref/out parameter can still succeed at runtime
5257 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5265 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5269 // Use implicit conversion in all modes to return same candidates when the expression
5270 // is used as argument or delegate conversion
5272 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5273 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5280 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5282 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5284 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5287 var ac_p = p as ArrayContainer;
5289 var ac_q = q as ArrayContainer;
5293 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5294 if (specific == ac_p.Element)
5296 if (specific == ac_q.Element)
5298 } else if (p.IsGeneric && q.IsGeneric) {
5299 var pargs = TypeManager.GetTypeArguments (p);
5300 var qargs = TypeManager.GetTypeArguments (q);
5302 bool p_specific_at_least_once = false;
5303 bool q_specific_at_least_once = false;
5305 for (int i = 0; i < pargs.Length; i++) {
5306 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5307 if (specific == pargs[i])
5308 p_specific_at_least_once = true;
5309 if (specific == qargs[i])
5310 q_specific_at_least_once = true;
5313 if (p_specific_at_least_once && !q_specific_at_least_once)
5315 if (!p_specific_at_least_once && q_specific_at_least_once)
5323 // Find the best method from candidate list
5325 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5327 List<AmbiguousCandidate> ambiguous_candidates = null;
5329 MemberSpec best_candidate;
5330 Arguments best_candidate_args = null;
5331 bool best_candidate_params = false;
5332 bool best_candidate_dynamic = false;
5333 int best_candidate_rate;
5334 IParametersMember best_parameter_member = null;
5336 int args_count = args != null ? args.Count : 0;
5338 Arguments candidate_args = args;
5339 bool error_mode = false;
5340 MemberSpec invocable_member = null;
5343 best_candidate = null;
5344 best_candidate_rate = int.MaxValue;
5346 var type_members = members;
5348 for (int i = 0; i < type_members.Count; ++i) {
5349 var member = type_members[i];
5352 // Methods in a base class are not candidates if any method in a derived
5353 // class is applicable
5355 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5359 if (!member.IsAccessible (rc))
5362 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5365 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5366 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5371 IParametersMember pm = member as IParametersMember;
5374 // Will use it later to report ambiguity between best method and invocable member
5376 if (Invocation.IsMemberInvocable (member))
5377 invocable_member = member;
5383 // Overload resolution is looking for base member but using parameter names
5384 // and default values from the closest member. That means to do expensive lookup
5385 // for the closest override for virtual or abstract members
5387 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5388 var override_params = base_provider.GetOverrideMemberParameters (member);
5389 if (override_params != null)
5390 pm = override_params;
5394 // Check if the member candidate is applicable
5396 bool params_expanded_form = false;
5397 bool dynamic_argument = false;
5398 TypeSpec rt = pm.MemberType;
5399 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5401 if (lambda_conv_msgs != null)
5402 lambda_conv_msgs.EndSession ();
5405 // How does it score compare to others
5407 if (candidate_rate < best_candidate_rate) {
5409 // Fatal error (missing dependency), cannot continue
5410 if (candidate_rate < 0)
5413 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5414 // Only parameterless methods are considered
5416 best_candidate_rate = candidate_rate;
5417 best_candidate = member;
5418 best_candidate_args = candidate_args;
5419 best_candidate_params = params_expanded_form;
5420 best_candidate_dynamic = dynamic_argument;
5421 best_parameter_member = pm;
5422 best_candidate_return_type = rt;
5424 } else if (candidate_rate == 0) {
5426 // The member look is done per type for most operations but sometimes
5427 // it's not possible like for binary operators overload because they
5428 // are unioned between 2 sides
5430 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5431 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5436 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5438 // We pack all interface members into top level type which makes the overload resolution
5439 // more complicated for interfaces. We compensate it by removing methods with same
5440 // signature when building the cache hence this path should not really be hit often
5443 // interface IA { void Foo (int arg); }
5444 // interface IB : IA { void Foo (params int[] args); }
5446 // IB::Foo is the best overload when calling IB.Foo (1)
5449 if (ambiguous_candidates != null) {
5450 foreach (var amb_cand in ambiguous_candidates) {
5451 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5460 ambiguous_candidates = null;
5463 // Is the new candidate better
5464 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5468 best_candidate = member;
5469 best_candidate_args = candidate_args;
5470 best_candidate_params = params_expanded_form;
5471 best_candidate_dynamic = dynamic_argument;
5472 best_parameter_member = pm;
5473 best_candidate_return_type = rt;
5475 // It's not better but any other found later could be but we are not sure yet
5476 if (ambiguous_candidates == null)
5477 ambiguous_candidates = new List<AmbiguousCandidate> ();
5479 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5483 // Restore expanded arguments
5484 candidate_args = args;
5486 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5489 // We've found exact match
5491 if (best_candidate_rate == 0)
5495 // Try extension methods lookup when no ordinary method match was found and provider enables it
5498 var emg = base_provider.LookupExtensionMethod (rc);
5500 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5502 best_candidate_extension_group = emg;
5503 return (T) (MemberSpec) emg.BestCandidate;
5508 // Don't run expensive error reporting mode for probing
5515 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5518 lambda_conv_msgs = null;
5523 // No best member match found, report an error
5525 if (best_candidate_rate != 0 || error_mode) {
5526 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5530 if (best_candidate_dynamic) {
5531 if (args[0].IsExtensionType) {
5532 rc.Report.Error (1973, loc,
5533 "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",
5534 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5538 // Check type constraints only when explicit type arguments are used
5540 if (best_candidate.IsGeneric && type_arguments != null) {
5541 MethodSpec bc = best_candidate as MethodSpec;
5542 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5543 ConstraintChecker cc = new ConstraintChecker (rc);
5544 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5548 BestCandidateIsDynamic = true;
5553 // These flags indicates we are running delegate probing conversion. No need to
5554 // do more expensive checks
5556 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5557 return (T) best_candidate;
5559 if (ambiguous_candidates != null) {
5561 // Now check that there are no ambiguities i.e the selected method
5562 // should be better than all the others
5564 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5565 var candidate = ambiguous_candidates [ix];
5567 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5568 var ambiguous = candidate.Member;
5569 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5570 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5571 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5572 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5573 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5576 return (T) best_candidate;
5581 if (invocable_member != null && !IsProbingOnly) {
5582 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5583 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5584 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5585 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5589 // And now check if the arguments are all
5590 // compatible, perform conversions if
5591 // necessary etc. and return if everything is
5594 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5597 if (best_candidate == null)
5601 // Don't run possibly expensive checks in probing mode
5603 if (!IsProbingOnly && !rc.IsInProbingMode) {
5605 // Check ObsoleteAttribute on the best method
5607 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5608 if (oa != null && !rc.IsObsolete)
5609 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5611 best_candidate.MemberDefinition.SetIsUsed ();
5614 args = best_candidate_args;
5615 return (T) best_candidate;
5618 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5620 return ResolveMember<MethodSpec> (rc, ref args);
5623 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5624 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5626 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5629 if (a.Type == InternalType.ErrorType)
5632 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5633 ec.Report.SymbolRelatedToPreviousError (method);
5634 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5635 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5636 TypeManager.CSharpSignature (method));
5639 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5640 TypeManager.CSharpSignature (method));
5641 } else if (IsDelegateInvoke) {
5642 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5643 DelegateType.GetSignatureForError ());
5645 ec.Report.SymbolRelatedToPreviousError (method);
5646 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5647 method.GetSignatureForError ());
5650 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5652 string index = (idx + 1).ToString ();
5653 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5654 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5655 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5656 index, Parameter.GetModifierSignature (a.Modifier));
5658 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5659 index, Parameter.GetModifierSignature (mod));
5661 string p1 = a.GetSignatureForError ();
5662 string p2 = paramType.GetSignatureForError ();
5665 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5666 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5669 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5670 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5671 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5674 ec.Report.Error (1503, a.Expr.Location,
5675 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5680 // We have failed to find exact match so we return error info about the closest match
5682 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5684 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5685 int arg_count = args == null ? 0 : args.Count;
5687 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5688 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5689 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5693 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5698 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5699 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5700 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5704 // For candidates which match on parameters count report more details about incorrect arguments
5707 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5708 // Reject any inaccessible member
5709 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5710 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5711 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5715 var ms = best_candidate as MethodSpec;
5716 if (ms != null && ms.IsGeneric) {
5717 bool constr_ok = true;
5718 if (ms.TypeArguments != null)
5719 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5721 if (ta_count == 0 && ms.TypeArguments == null) {
5722 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5726 rc.Report.Error (411, loc,
5727 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5728 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5735 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5741 // We failed to find any method with correct argument count, report best candidate
5743 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5746 if (best_candidate.Kind == MemberKind.Constructor) {
5747 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5748 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5749 } else if (IsDelegateInvoke) {
5750 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5751 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5752 DelegateType.GetSignatureForError (), arg_count.ToString ());
5754 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5755 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5756 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5757 name, arg_count.ToString ());
5761 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5763 var p = ((IParametersMember)best_candidate).Parameters;
5768 for (int i = p.Count - 1; i != 0; --i) {
5769 var fp = p.FixedParameters [i];
5770 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5780 foreach (var arg in args) {
5781 var na = arg as NamedArgument;
5785 if (na.Name == name) {
5794 return args.Count + 1 == pm.Parameters.Count;
5797 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5799 var pd = pm.Parameters;
5800 var cpd = ((IParametersMember) member).Parameters;
5801 var ptypes = cpd.Types;
5803 Parameter.Modifier p_mod = 0;
5805 int a_idx = 0, a_pos = 0;
5807 ArrayInitializer params_initializers = null;
5808 bool has_unsafe_arg = pm.MemberType.IsPointer;
5809 int arg_count = args == null ? 0 : args.Count;
5811 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5816 if (p_mod != Parameter.Modifier.PARAMS) {
5817 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5819 has_unsafe_arg |= pt.IsPointer;
5821 if (p_mod == Parameter.Modifier.PARAMS) {
5822 if (chose_params_expanded) {
5823 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5824 pt = TypeManager.GetElementType (pt);
5830 // Types have to be identical when ref or out modifer is used
5832 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5833 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5836 var arg_type = a.Type;
5840 if (arg_type == InternalType.VarOutType) {
5842 // Set underlying variable type based on parameter type
5844 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5848 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5852 NamedArgument na = a as NamedArgument;
5854 int name_index = pd.GetParameterIndexByName (na.Name);
5855 if (name_index < 0 || name_index >= pd.Count) {
5856 if (IsDelegateInvoke) {
5857 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5858 ec.Report.Error (1746, na.Location,
5859 "The delegate `{0}' does not contain a parameter named `{1}'",
5860 DelegateType.GetSignatureForError (), na.Name);
5862 ec.Report.SymbolRelatedToPreviousError (member);
5863 ec.Report.Error (1739, na.Location,
5864 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5865 TypeManager.CSharpSignature (member), na.Name);
5867 } else if (args[name_index] != a && args[name_index] != null) {
5868 if (IsDelegateInvoke)
5869 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5871 ec.Report.SymbolRelatedToPreviousError (member);
5873 ec.Report.Error (1744, na.Location,
5874 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5879 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5882 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5883 if (a.IsExtensionType) {
5884 // TODO: Should report better message type, something similar to CS1928/1929 instead of
5885 // CS1061 but that still better than confusing CS0123
5886 var ma = new MemberAccess (a.Expr, member.Name, loc);
5887 ma.Error_TypeDoesNotContainDefinition (ec, a.Expr.Type, ma.Name);
5889 custom_errors.NoArgumentMatch (ec, member);
5895 if (a.IsExtensionType) {
5896 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5899 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5901 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5904 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5911 // Convert params arguments to an array initializer
5913 if (params_initializers != null) {
5914 // we choose to use 'a.Expr' rather than 'conv' so that
5915 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5916 params_initializers.Add (a.Expr);
5917 args.RemoveAt (a_idx--);
5923 // Update the argument with the implicit conversion
5927 if (a_idx != arg_count) {
5929 // Convert all var out argument to error type for less confusing error reporting
5930 // when no matching overload is found
5932 for (; a_idx < arg_count; a_idx++) {
5933 var arg = args [a_idx];
5937 if (arg.Type == InternalType.VarOutType) {
5938 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5942 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5947 // Fill not provided arguments required by params modifier
5949 if (params_initializers == null && arg_count + 1 == pd.Count) {
5951 args = new Arguments (1);
5953 pt = ptypes[pd.Count - 1];
5954 pt = TypeManager.GetElementType (pt);
5955 has_unsafe_arg |= pt.IsPointer;
5956 params_initializers = new ArrayInitializer (0, loc);
5960 // Append an array argument with all params arguments
5962 if (params_initializers != null) {
5963 args.Add (new Argument (
5964 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5968 if (has_unsafe_arg && !ec.IsUnsafe) {
5969 Expression.UnsafeError (ec, loc);
5973 // We could infer inaccesible type arguments
5975 if (type_arguments == null && member.IsGeneric) {
5976 var ms = (MethodSpec) member;
5977 foreach (var ta in ms.TypeArguments) {
5978 if (!ta.IsAccessible (ec)) {
5979 ec.Report.SymbolRelatedToPreviousError (ta);
5980 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5990 public class ConstantExpr : MemberExpr
5992 readonly ConstSpec constant;
5994 public ConstantExpr (ConstSpec constant, Location loc)
5996 this.constant = constant;
6000 public override string Name {
6001 get { throw new NotImplementedException (); }
6004 public override string KindName {
6005 get { return "constant"; }
6008 public override bool IsInstance {
6009 get { return !IsStatic; }
6012 public override bool IsStatic {
6013 get { return true; }
6016 protected override TypeSpec DeclaringType {
6017 get { return constant.DeclaringType; }
6020 public override Expression CreateExpressionTree (ResolveContext ec)
6022 throw new NotSupportedException ("ET");
6025 protected override Expression DoResolve (ResolveContext rc)
6027 ResolveInstanceExpression (rc, null);
6028 DoBestMemberChecks (rc, constant);
6030 var c = constant.GetConstant (rc);
6032 // Creates reference expression to the constant value
6033 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
6036 public override void Emit (EmitContext ec)
6038 throw new NotSupportedException ();
6041 public override string GetSignatureForError ()
6043 return constant.GetSignatureForError ();
6046 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6048 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6053 // Fully resolved expression that references a Field
6055 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6057 protected FieldSpec spec;
6058 VariableInfo variable_info;
6060 LocalTemporary temp;
6063 protected FieldExpr (Location l)
6068 public FieldExpr (FieldSpec spec, Location loc)
6073 type = spec.MemberType;
6076 public FieldExpr (FieldBase fi, Location l)
6083 public override string Name {
6089 public bool IsHoisted {
6091 IVariableReference hv = InstanceExpression as IVariableReference;
6092 return hv != null && hv.IsHoisted;
6096 public override bool IsInstance {
6098 return !spec.IsStatic;
6102 public override bool IsStatic {
6104 return spec.IsStatic;
6108 public override string KindName {
6109 get { return "field"; }
6112 public FieldSpec Spec {
6118 protected override TypeSpec DeclaringType {
6120 return spec.DeclaringType;
6124 public VariableInfo VariableInfo {
6126 return variable_info;
6132 public override string GetSignatureForError ()
6134 return spec.GetSignatureForError ();
6137 public bool IsMarshalByRefAccess (ResolveContext rc)
6139 // Checks possible ldflda of field access expression
6140 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6141 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6142 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6145 public void SetHasAddressTaken ()
6147 IVariableReference vr = InstanceExpression as IVariableReference;
6149 vr.SetHasAddressTaken ();
6153 protected override void CloneTo (CloneContext clonectx, Expression target)
6155 var t = (FieldExpr) target;
6157 if (InstanceExpression != null)
6158 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6161 public override Expression CreateExpressionTree (ResolveContext ec)
6163 if (ConditionalAccess) {
6164 Error_NullShortCircuitInsideExpressionTree (ec);
6167 return CreateExpressionTree (ec, true);
6170 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6173 Expression instance;
6175 if (InstanceExpression == null) {
6176 instance = new NullLiteral (loc);
6177 } else if (convertInstance) {
6178 instance = InstanceExpression.CreateExpressionTree (ec);
6180 args = new Arguments (1);
6181 args.Add (new Argument (InstanceExpression));
6182 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6185 args = Arguments.CreateForExpressionTree (ec, null,
6187 CreateTypeOfExpression ());
6189 return CreateExpressionFactoryCall (ec, "Field", args);
6192 public Expression CreateTypeOfExpression ()
6194 return new TypeOfField (spec, loc);
6197 protected override Expression DoResolve (ResolveContext ec)
6199 spec.MemberDefinition.SetIsUsed ();
6201 return DoResolve (ec, null);
6204 Expression DoResolve (ResolveContext ec, Expression rhs)
6206 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6209 ResolveConditionalAccessReceiver (ec);
6211 if (ResolveInstanceExpression (ec, rhs)) {
6212 // Resolve the field's instance expression while flow analysis is turned
6213 // off: when accessing a field "a.b", we must check whether the field
6214 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6216 if (lvalue_instance) {
6217 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6219 Expression right_side =
6220 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6222 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6224 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6227 if (InstanceExpression == null)
6231 DoBestMemberChecks (ec, spec);
6233 if (conditional_access_receiver)
6234 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6237 var fb = spec as FixedFieldSpec;
6238 IVariableReference var = InstanceExpression as IVariableReference;
6241 IFixedExpression fe = InstanceExpression as IFixedExpression;
6242 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6243 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6246 if (InstanceExpression.eclass != ExprClass.Variable) {
6247 ec.Report.SymbolRelatedToPreviousError (spec);
6248 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6249 TypeManager.GetFullNameSignature (spec));
6250 } else if (var != null && var.IsHoisted) {
6251 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6254 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6258 // Set flow-analysis variable info for struct member access. It will be check later
6259 // for precise error reporting
6261 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6262 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6265 if (ConditionalAccess) {
6266 if (conditional_access_receiver)
6267 type = LiftMemberType (ec, type);
6269 if (InstanceExpression.IsNull)
6270 return Constant.CreateConstantFromValue (type, null, loc);
6273 eclass = ExprClass.Variable;
6277 public void SetFieldAssigned (FlowAnalysisContext fc)
6282 bool lvalue_instance = spec.DeclaringType.IsStruct;
6283 if (lvalue_instance) {
6284 var var = InstanceExpression as IVariableReference;
6285 if (var != null && var.VariableInfo != null) {
6286 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6290 var fe = InstanceExpression as FieldExpr;
6292 Expression instance;
6295 instance = fe.InstanceExpression;
6296 var fe_instance = instance as FieldExpr;
6297 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6298 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6299 var var = InstanceExpression as IVariableReference;
6300 if (var != null && var.VariableInfo == null) {
6301 var var_inst = instance as IVariableReference;
6302 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6303 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6307 if (fe_instance != null) {
6316 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6317 instance.FlowAnalysis (fc);
6319 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6320 InstanceExpression.FlowAnalysis (fc);
6324 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6326 // The return value is always null. Returning a value simplifies calling code.
6328 if (right_side == EmptyExpression.OutAccess) {
6330 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6331 GetSignatureForError ());
6333 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6334 GetSignatureForError ());
6340 if (right_side == EmptyExpression.LValueMemberAccess) {
6341 // Already reported as CS1648/CS1650
6345 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6347 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6348 GetSignatureForError ());
6350 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6351 GetSignatureForError ());
6357 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6358 GetSignatureForError ());
6360 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6361 GetSignatureForError ());
6367 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6369 if (ConditionalAccess)
6370 Error_NullPropagatingLValue (ec);
6372 if (spec is FixedFieldSpec) {
6373 // It could be much better error message but we want to be error compatible
6374 Error_ValueAssignment (ec, right_side);
6377 Expression e = DoResolve (ec, right_side);
6382 spec.MemberDefinition.SetIsAssigned ();
6384 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6385 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6386 ec.Report.Warning (420, 1, loc,
6387 "`{0}': A volatile field references will not be treated as volatile",
6388 spec.GetSignatureForError ());
6391 if (spec.IsReadOnly) {
6392 // InitOnly fields can only be assigned in constructors or initializers
6393 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6394 return Error_AssignToReadonly (ec, right_side);
6396 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6398 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6399 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6400 return Error_AssignToReadonly (ec, right_side);
6401 // static InitOnly fields cannot be assigned-to in an instance constructor
6402 if (IsStatic && !ec.IsStatic)
6403 return Error_AssignToReadonly (ec, right_side);
6404 // instance constructors can't modify InitOnly fields of other instances of the same type
6405 if (!IsStatic && !(InstanceExpression is This))
6406 return Error_AssignToReadonly (ec, right_side);
6410 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6411 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6412 ec.Report.Warning (197, 1, loc,
6413 "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",
6414 GetSignatureForError ());
6417 eclass = ExprClass.Variable;
6421 public override void FlowAnalysis (FlowAnalysisContext fc)
6423 var var = InstanceExpression as IVariableReference;
6425 var vi = var.VariableInfo;
6426 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6427 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6431 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6435 base.FlowAnalysis (fc);
6437 if (conditional_access_receiver)
6438 fc.ConditionalAccessEnd ();
6441 public override int GetHashCode ()
6443 return spec.GetHashCode ();
6446 public bool IsFixed {
6449 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6451 IVariableReference variable = InstanceExpression as IVariableReference;
6452 if (variable != null)
6453 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6455 IFixedExpression fe = InstanceExpression as IFixedExpression;
6456 return fe != null && fe.IsFixed;
6460 public override bool Equals (object obj)
6462 FieldExpr fe = obj as FieldExpr;
6466 if (spec != fe.spec)
6469 if (InstanceExpression == null || fe.InstanceExpression == null)
6472 return InstanceExpression.Equals (fe.InstanceExpression);
6475 public void Emit (EmitContext ec, bool leave_copy)
6477 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6481 ec.Emit (OpCodes.Volatile);
6483 ec.Emit (OpCodes.Ldsfld, spec);
6486 if (conditional_access_receiver)
6487 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6489 EmitInstance (ec, false);
6492 // Optimization for build-in types
6493 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6494 ec.EmitLoadFromPtr (type);
6496 var ff = spec as FixedFieldSpec;
6498 ec.Emit (OpCodes.Ldflda, spec);
6499 ec.Emit (OpCodes.Ldflda, ff.Element);
6502 ec.Emit (OpCodes.Volatile);
6504 ec.Emit (OpCodes.Ldfld, spec);
6508 if (conditional_access_receiver) {
6509 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6514 ec.Emit (OpCodes.Dup);
6516 temp = new LocalTemporary (this.Type);
6522 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6524 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6525 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6530 if (ConditionalAccess)
6531 throw new NotImplementedException ("null operator assignment");
6533 if (has_await_source)
6534 source = source.EmitToField (ec);
6536 EmitInstance (ec, prepared);
6541 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6542 ec.Emit (OpCodes.Dup);
6544 temp = new LocalTemporary (this.Type);
6549 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6550 ec.Emit (OpCodes.Volatile);
6552 spec.MemberDefinition.SetIsAssigned ();
6555 ec.Emit (OpCodes.Stsfld, spec);
6557 ec.Emit (OpCodes.Stfld, spec);
6559 if (ec.NotifyEvaluatorOnStore) {
6561 throw new NotImplementedException ("instance field write");
6564 ec.Emit (OpCodes.Dup);
6566 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6577 // Emits store to field with prepared values on stack
6579 public void EmitAssignFromStack (EmitContext ec)
6582 ec.Emit (OpCodes.Stsfld, spec);
6584 ec.Emit (OpCodes.Stfld, spec);
6588 public override void Emit (EmitContext ec)
6593 public override void EmitSideEffect (EmitContext ec)
6595 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6597 if (is_volatile) // || is_marshal_by_ref ())
6598 base.EmitSideEffect (ec);
6601 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6603 if ((mode & AddressOp.Store) != 0)
6604 spec.MemberDefinition.SetIsAssigned ();
6605 if ((mode & AddressOp.Load) != 0)
6606 spec.MemberDefinition.SetIsUsed ();
6609 // Handle initonly fields specially: make a copy and then
6610 // get the address of the copy.
6613 if (spec.IsReadOnly){
6615 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6627 var temp = ec.GetTemporaryLocal (type);
6628 ec.Emit (OpCodes.Stloc, temp);
6629 ec.Emit (OpCodes.Ldloca, temp);
6635 ec.Emit (OpCodes.Ldsflda, spec);
6638 EmitInstance (ec, false);
6639 ec.Emit (OpCodes.Ldflda, spec);
6643 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6645 return MakeExpression (ctx);
6648 public override SLE.Expression MakeExpression (BuilderContext ctx)
6651 return base.MakeExpression (ctx);
6653 return SLE.Expression.Field (
6654 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6655 spec.GetMetaInfo ());
6659 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6661 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6667 // Expression that evaluates to a Property.
6669 // This is not an LValue because we need to re-write the expression. We
6670 // can not take data from the stack and store it.
6672 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6674 Arguments arguments;
6675 FieldExpr backing_field;
6677 public PropertyExpr (PropertySpec spec, Location l)
6680 best_candidate = spec;
6681 type = spec.MemberType;
6686 protected override Arguments Arguments {
6695 protected override TypeSpec DeclaringType {
6697 return best_candidate.DeclaringType;
6701 public override string Name {
6703 return best_candidate.Name;
6707 public bool IsAutoPropertyAccess {
6709 var prop = best_candidate.MemberDefinition as Property;
6710 return prop != null && prop.BackingField != null;
6714 public override bool IsInstance {
6720 public override bool IsStatic {
6722 return best_candidate.IsStatic;
6726 public override string KindName {
6727 get { return "property"; }
6730 public PropertySpec PropertyInfo {
6732 return best_candidate;
6738 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6740 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6743 var args_count = arguments == null ? 0 : arguments.Count;
6744 if (args_count != body.Parameters.Count && args_count == 0)
6747 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6748 mg.InstanceExpression = InstanceExpression;
6753 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6755 return new PropertyExpr (spec, loc) {
6761 public override Expression CreateExpressionTree (ResolveContext ec)
6763 if (ConditionalAccess) {
6764 Error_NullShortCircuitInsideExpressionTree (ec);
6768 if (IsSingleDimensionalArrayLength ()) {
6769 args = new Arguments (1);
6770 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6771 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6774 args = new Arguments (2);
6775 if (InstanceExpression == null)
6776 args.Add (new Argument (new NullLiteral (loc)));
6778 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6779 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6780 return CreateExpressionFactoryCall (ec, "Property", args);
6783 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6785 DoResolveLValue (rc, null);
6786 return new TypeOfMethod (Setter, loc);
6789 public override string GetSignatureForError ()
6791 return best_candidate.GetSignatureForError ();
6794 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6797 return base.MakeExpression (ctx);
6799 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6803 public override SLE.Expression MakeExpression (BuilderContext ctx)
6806 return base.MakeExpression (ctx);
6808 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6812 void Error_PropertyNotValid (ResolveContext ec)
6814 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6815 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6816 GetSignatureForError ());
6819 bool IsSingleDimensionalArrayLength ()
6821 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6824 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6825 return ac != null && ac.Rank == 1;
6828 public override void Emit (EmitContext ec, bool leave_copy)
6831 // Special case: length of single dimension array property is turned into ldlen
6833 if (IsSingleDimensionalArrayLength ()) {
6834 if (conditional_access_receiver) {
6835 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6838 EmitInstance (ec, false);
6840 ec.Emit (OpCodes.Ldlen);
6841 ec.Emit (OpCodes.Conv_I4);
6843 if (conditional_access_receiver) {
6844 ec.CloseConditionalAccess (type);
6850 base.Emit (ec, leave_copy);
6853 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6855 if (backing_field != null) {
6856 backing_field.EmitAssign (ec, source, false, false);
6861 LocalTemporary await_source_arg = null;
6863 if (isCompound && !(source is DynamicExpressionStatement)) {
6864 emitting_compound_assignment = true;
6867 if (has_await_arguments) {
6868 await_source_arg = new LocalTemporary (Type);
6869 await_source_arg.Store (ec);
6871 args = new Arguments (1);
6872 args.Add (new Argument (await_source_arg));
6875 temp = await_source_arg;
6878 has_await_arguments = false;
6883 ec.Emit (OpCodes.Dup);
6884 temp = new LocalTemporary (this.Type);
6889 args = arguments ?? new Arguments (1);
6893 temp = new LocalTemporary (this.Type);
6895 args.Add (new Argument (temp));
6897 args.Add (new Argument (source));
6901 emitting_compound_assignment = false;
6903 var call = new CallEmitter ();
6904 call.InstanceExpression = InstanceExpression;
6906 call.InstanceExpressionOnStack = true;
6908 if (ConditionalAccess) {
6909 call.ConditionalAccess = true;
6913 call.Emit (ec, Setter, args, loc);
6915 call.EmitStatement (ec, Setter, args, loc);
6922 if (await_source_arg != null) {
6923 await_source_arg.Release (ec);
6927 public override void FlowAnalysis (FlowAnalysisContext fc)
6929 var prop = best_candidate.MemberDefinition as Property;
6930 if (prop != null && prop.BackingField != null) {
6931 var var = InstanceExpression as IVariableReference;
6933 var vi = var.VariableInfo;
6934 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6935 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6939 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6944 base.FlowAnalysis (fc);
6946 if (conditional_access_receiver)
6947 fc.ConditionalAccessEnd ();
6950 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6952 eclass = ExprClass.PropertyAccess;
6954 if (best_candidate.IsNotCSharpCompatible) {
6955 Error_PropertyNotValid (rc);
6958 ResolveInstanceExpression (rc, right_side);
6960 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6961 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6962 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6964 type = p.MemberType;
6968 DoBestMemberChecks (rc, best_candidate);
6970 // Handling of com-imported properties with any number of default property parameters
6971 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6972 var p = best_candidate.Get.Parameters;
6973 arguments = new Arguments (p.Count);
6974 for (int i = 0; i < p.Count; ++i) {
6975 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6977 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6978 var p = best_candidate.Set.Parameters;
6979 arguments = new Arguments (p.Count - 1);
6980 for (int i = 0; i < p.Count - 1; ++i) {
6981 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6988 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
6990 var prop = best_candidate.MemberDefinition as Property;
6994 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
6997 var spec = prop.BackingField;
7001 if (rc.IsStatic != spec.IsStatic)
7004 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
7007 backing_field = new FieldExpr (prop.BackingField, loc);
7008 backing_field.ResolveLValue (rc, rhs);
7012 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
7014 if (backing_field != null) {
7015 backing_field.SetFieldAssigned (fc);
7019 if (!IsAutoPropertyAccess)
7022 var prop = best_candidate.MemberDefinition as Property;
7023 if (prop != null && prop.BackingField != null) {
7024 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
7025 if (lvalue_instance) {
7026 var var = InstanceExpression as IVariableReference;
7027 if (var != null && var.VariableInfo != null) {
7028 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
7034 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7036 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
7040 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7042 // getter and setter can be different for base calls
7043 MethodSpec getter, setter;
7044 protected T best_candidate;
7046 protected LocalTemporary temp;
7047 protected bool emitting_compound_assignment;
7048 protected bool has_await_arguments;
7050 protected PropertyOrIndexerExpr (Location l)
7057 protected abstract Arguments Arguments { get; set; }
7059 public MethodSpec Getter {
7068 public MethodSpec Setter {
7079 protected override Expression DoResolve (ResolveContext ec)
7081 if (eclass == ExprClass.Unresolved) {
7082 ResolveConditionalAccessReceiver (ec);
7084 var expr = OverloadResolve (ec, null);
7089 return expr.Resolve (ec);
7091 if (conditional_access_receiver) {
7092 type = LiftMemberType (ec, type);
7093 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7097 if (!ResolveGetter (ec))
7103 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7105 if (ConditionalAccess)
7106 Error_NullPropagatingLValue (rc);
7108 if (right_side == EmptyExpression.OutAccess) {
7109 // TODO: best_candidate can be null at this point
7110 INamedBlockVariable variable = null;
7111 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7112 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7113 best_candidate.Name);
7115 right_side.DoResolveLValue (rc, this);
7120 if (eclass == ExprClass.Unresolved) {
7121 var expr = OverloadResolve (rc, right_side);
7126 return expr.ResolveLValue (rc, right_side);
7128 ResolveInstanceExpression (rc, right_side);
7131 if (!best_candidate.HasSet) {
7132 if (ResolveAutopropertyAssignment (rc, right_side))
7135 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7136 GetSignatureForError ());
7140 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7141 if (best_candidate.HasDifferentAccessibility) {
7142 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7143 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7144 GetSignatureForError ());
7146 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7147 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7151 if (best_candidate.HasDifferentAccessibility)
7152 CheckProtectedMemberAccess (rc, best_candidate.Set);
7154 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7158 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7160 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7162 call.Emit (ec, method, arguments, loc);
7164 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7168 // Implements the IAssignMethod interface for assignments
7170 public virtual void Emit (EmitContext ec, bool leave_copy)
7172 var call = new CallEmitter ();
7173 call.ConditionalAccess = ConditionalAccess;
7174 call.InstanceExpression = InstanceExpression;
7175 if (has_await_arguments)
7176 call.HasAwaitArguments = true;
7178 call.DuplicateArguments = emitting_compound_assignment;
7180 if (conditional_access_receiver)
7181 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7183 call.Emit (ec, Getter, Arguments, loc);
7185 if (call.HasAwaitArguments) {
7186 InstanceExpression = call.InstanceExpression;
7187 Arguments = call.EmittedArguments;
7188 has_await_arguments = true;
7192 ec.Emit (OpCodes.Dup);
7193 temp = new LocalTemporary (Type);
7198 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7200 public override void Emit (EmitContext ec)
7205 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7207 has_await_arguments = true;
7212 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7214 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7216 bool ResolveGetter (ResolveContext rc)
7218 if (!best_candidate.HasGet) {
7219 if (InstanceExpression != EmptyExpression.Null) {
7220 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7221 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7222 best_candidate.GetSignatureForError ());
7225 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7226 if (best_candidate.HasDifferentAccessibility) {
7227 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7228 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7229 TypeManager.CSharpSignature (best_candidate));
7231 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7232 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7236 if (best_candidate.HasDifferentAccessibility) {
7237 CheckProtectedMemberAccess (rc, best_candidate.Get);
7240 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7244 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7251 /// Fully resolved expression that evaluates to an Event
7253 public class EventExpr : MemberExpr, IAssignMethod
7255 readonly EventSpec spec;
7258 public EventExpr (EventSpec spec, Location loc)
7266 protected override TypeSpec DeclaringType {
7268 return spec.DeclaringType;
7272 public override string Name {
7278 public override bool IsInstance {
7280 return !spec.IsStatic;
7284 public override bool IsStatic {
7286 return spec.IsStatic;
7290 public override string KindName {
7291 get { return "event"; }
7294 public MethodSpec Operator {
7302 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7305 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7307 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7308 if (spec.BackingField != null &&
7309 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7311 spec.MemberDefinition.SetIsUsed ();
7313 if (!ec.IsObsolete) {
7314 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7316 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7319 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7320 Error_AssignmentEventOnly (ec);
7322 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7324 InstanceExpression = null;
7326 return ml.ResolveMemberAccess (ec, left, original);
7330 return base.ResolveMemberAccess (ec, left, original);
7333 public override Expression CreateExpressionTree (ResolveContext ec)
7335 throw new NotSupportedException ("ET");
7338 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7340 if (right_side == EmptyExpression.EventAddition) {
7341 op = spec.AccessorAdd;
7342 } else if (right_side == EmptyExpression.EventSubtraction) {
7343 op = spec.AccessorRemove;
7347 Error_AssignmentEventOnly (ec);
7351 if (ConditionalAccess)
7352 Error_NullPropagatingLValue (ec);
7354 op = CandidateToBaseOverride (ec, op);
7358 protected override Expression DoResolve (ResolveContext ec)
7360 eclass = ExprClass.EventAccess;
7361 type = spec.MemberType;
7363 ResolveInstanceExpression (ec, null);
7365 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7366 Error_AssignmentEventOnly (ec);
7369 DoBestMemberChecks (ec, spec);
7373 public override void Emit (EmitContext ec)
7375 throw new NotSupportedException ();
7376 //Error_CannotAssign ();
7379 #region IAssignMethod Members
7381 public void Emit (EmitContext ec, bool leave_copy)
7383 throw new NotImplementedException ();
7386 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7388 if (leave_copy || !isCompound)
7389 throw new NotImplementedException ("EventExpr::EmitAssign");
7391 Arguments args = new Arguments (1);
7392 args.Add (new Argument (source));
7394 // TODO: Wrong, needs receiver
7395 // if (NullShortCircuit) {
7396 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7399 var call = new CallEmitter ();
7400 call.InstanceExpression = InstanceExpression;
7401 call.ConditionalAccess = ConditionalAccess;
7402 call.EmitStatement (ec, op, args, loc);
7404 // if (NullShortCircuit)
7405 // ec.CloseConditionalAccess (null);
7410 void Error_AssignmentEventOnly (ResolveContext ec)
7412 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7413 ec.Report.Error (79, loc,
7414 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7415 GetSignatureForError ());
7417 ec.Report.Error (70, loc,
7418 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7419 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7423 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7425 name = name.Substring (0, name.LastIndexOf ('.'));
7426 base.Error_CannotCallAbstractBase (rc, name);
7429 public override string GetSignatureForError ()
7431 return TypeManager.CSharpSignature (spec);
7434 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7436 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7440 public class TemporaryVariableReference : VariableReference
7442 public class Declarator : Statement
7444 TemporaryVariableReference variable;
7446 public Declarator (TemporaryVariableReference variable)
7448 this.variable = variable;
7452 protected override void DoEmit (EmitContext ec)
7454 variable.li.CreateBuilder (ec);
7457 public override void Emit (EmitContext ec)
7459 // Don't create sequence point
7463 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7468 protected override void CloneTo (CloneContext clonectx, Statement target)
7476 public TemporaryVariableReference (LocalVariable li, Location loc)
7479 this.type = li.Type;
7483 public override bool IsLockedByStatement {
7491 public LocalVariable LocalInfo {
7497 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7499 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7500 return new TemporaryVariableReference (li, loc);
7503 protected override Expression DoResolve (ResolveContext ec)
7505 eclass = ExprClass.Variable;
7508 // Don't capture temporary variables except when using
7509 // state machine redirection and block yields
7511 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7512 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7513 ec.IsVariableCapturingRequired) {
7514 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7515 storey.CaptureLocalVariable (ec, li);
7521 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7523 return Resolve (ec);
7526 public override void Emit (EmitContext ec)
7528 li.CreateBuilder (ec);
7533 public void EmitAssign (EmitContext ec, Expression source)
7535 li.CreateBuilder (ec);
7537 EmitAssign (ec, source, false, false);
7540 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7542 return li.HoistedVariant;
7545 public override bool IsFixed {
7546 get { return true; }
7549 public override bool IsRef {
7550 get { return false; }
7553 public override string Name {
7554 get { throw new NotImplementedException (); }
7557 public override void SetHasAddressTaken ()
7559 throw new NotImplementedException ();
7562 protected override ILocalVariable Variable {
7566 public override VariableInfo VariableInfo {
7567 get { return null; }
7572 /// Handles `var' contextual keyword; var becomes a keyword only
7573 /// if no type called var exists in a variable scope
7575 class VarExpr : SimpleName
7577 public VarExpr (Location loc)
7582 public bool InferType (ResolveContext ec, Expression right_side)
7585 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7587 type = right_side.Type;
7588 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7589 ec.Report.Error (815, loc,
7590 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7591 type.GetSignatureForError ());
7595 eclass = ExprClass.Variable;
7599 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7601 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7602 base.Error_TypeOrNamespaceNotFound (ec);
7604 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");