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
826 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
827 // `qualifier_type' or null to lookup members in the current class.
829 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
831 var members = MemberCache.FindMembers (queried_type, name, false);
835 MemberSpec non_method = null;
836 MemberSpec ambig_non_method = null;
838 for (int i = 0; i < members.Count; ++i) {
839 var member = members[i];
841 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
842 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
845 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
848 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
852 if (!member.IsAccessible (rc))
856 // With runtime binder we can have a situation where queried type is inaccessible
857 // because it came via dynamic object, the check about inconsisted accessibility
858 // had no effect as the type was unknown during compilation
861 // private class N { }
863 // public dynamic Foo ()
869 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
873 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
874 if (member is MethodSpec) {
876 // Interface members that are hidden by class members are removed from the set. This
877 // step only has an effect if T is a type parameter and T has both an effective base
878 // class other than object and a non-empty effective interface set
880 var tps = queried_type as TypeParameterSpec;
881 if (tps != null && tps.HasTypeConstraint)
882 members = RemoveHiddenTypeParameterMethods (members);
884 return new MethodGroupExpr (members, queried_type, loc);
887 if (!Invocation.IsMemberInvocable (member))
891 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
893 } else if (!errorMode && !member.IsNotCSharpCompatible) {
895 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
896 // T has both an effective base class other than object and a non-empty effective interface set.
898 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
900 var tps = queried_type as TypeParameterSpec;
901 if (tps != null && tps.HasTypeConstraint) {
902 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
905 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
911 ambig_non_method = member;
915 if (non_method != null) {
916 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
917 var report = rc.Module.Compiler.Report;
918 report.SymbolRelatedToPreviousError (non_method);
919 report.SymbolRelatedToPreviousError (ambig_non_method);
920 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
921 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
924 if (non_method is MethodSpec)
925 return new MethodGroupExpr (members, queried_type, loc);
927 return ExprClassFromMemberInfo (non_method, loc);
930 if (members[0].DeclaringType.BaseType == null)
933 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
935 } while (members != null);
940 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
942 if (members.Count < 2)
946 // If M is a method, then all non-method members declared in an interface declaration
947 // are removed from the set, and all methods with the same signature as M declared in
948 // an interface declaration are removed from the set
952 for (int i = 0; i < members.Count; ++i) {
953 var method = members[i] as MethodSpec;
954 if (method == null) {
957 members = new List<MemberSpec> (members);
960 members.RemoveAt (i--);
964 if (!method.DeclaringType.IsInterface)
967 for (int ii = 0; ii < members.Count; ++ii) {
968 var candidate = members[ii] as MethodSpec;
969 if (candidate == null || !candidate.DeclaringType.IsClass)
972 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
977 members = new List<MemberSpec> (members);
980 members.RemoveAt (i--);
988 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
990 throw new NotImplementedException ();
993 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
995 if (t == InternalType.ErrorType)
998 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
999 oper, t.GetSignatureForError ());
1002 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
1004 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
1007 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
1009 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
1012 public virtual void FlowAnalysis (FlowAnalysisContext fc)
1017 // Special version of flow analysis for expressions which can return different
1018 // on-true and on-false result. Used by &&, ||, ?: expressions
1020 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1023 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1027 /// Returns an expression that can be used to invoke operator true
1028 /// on the expression if it exists.
1030 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1032 return GetOperatorTrueOrFalse (ec, e, true, loc);
1036 /// Returns an expression that can be used to invoke operator false
1037 /// on the expression if it exists.
1039 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1041 return GetOperatorTrueOrFalse (ec, e, false, loc);
1044 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1046 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1048 if (type.IsNullableType)
1049 type = Nullable.NullableInfo.GetUnderlyingType (type);
1051 var methods = MemberCache.GetUserOperator (type, op, false);
1052 if (methods == null)
1055 Arguments arguments = new Arguments (1);
1056 arguments.Add (new Argument (e));
1058 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1059 var oper = res.ResolveOperator (ec, ref arguments);
1064 return new UserOperatorCall (oper, arguments, null, loc);
1067 public virtual string ExprClassName
1071 case ExprClass.Unresolved:
1072 return "Unresolved";
1073 case ExprClass.Value:
1075 case ExprClass.Variable:
1077 case ExprClass.Namespace:
1079 case ExprClass.Type:
1081 case ExprClass.MethodGroup:
1082 return "method group";
1083 case ExprClass.PropertyAccess:
1084 return "property access";
1085 case ExprClass.EventAccess:
1086 return "event access";
1087 case ExprClass.IndexerAccess:
1088 return "indexer access";
1089 case ExprClass.Nothing:
1091 case ExprClass.TypeParameter:
1092 return "type parameter";
1094 throw new Exception ("Should not happen");
1099 /// Reports that we were expecting `expr' to be of class `expected'
1101 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1103 var name = memberExpr.GetSignatureForError ();
1105 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1108 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1110 string [] valid = new string [4];
1113 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1114 valid [count++] = "variable";
1115 valid [count++] = "value";
1118 if ((flags & ResolveFlags.Type) != 0)
1119 valid [count++] = "type";
1121 if ((flags & ResolveFlags.MethodGroup) != 0)
1122 valid [count++] = "method group";
1125 valid [count++] = "unknown";
1127 StringBuilder sb = new StringBuilder (valid [0]);
1128 for (int i = 1; i < count - 1; i++) {
1130 sb.Append (valid [i]);
1133 sb.Append ("' or `");
1134 sb.Append (valid [count - 1]);
1137 ec.Report.Error (119, loc,
1138 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1141 public static void UnsafeError (ResolveContext ec, Location loc)
1143 UnsafeError (ec.Report, loc);
1146 public static void UnsafeError (Report Report, Location loc)
1148 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1152 // Converts `source' to an int, uint, long or ulong.
1154 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1156 var btypes = ec.BuiltinTypes;
1158 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1159 Arguments args = new Arguments (1);
1160 args.Add (new Argument (source));
1161 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1164 Expression converted;
1166 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1167 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1168 if (converted == null)
1169 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1170 if (converted == null)
1171 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1172 if (converted == null)
1173 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1175 if (converted == null) {
1176 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1185 // Only positive constants are allowed at compile time
1187 Constant c = converted as Constant;
1188 if (c != null && c.IsNegative)
1189 Error_NegativeArrayIndex (ec, source.loc);
1191 // No conversion needed to array index
1192 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1195 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1199 // Derived classes implement this method by cloning the fields that
1200 // could become altered during the Resolve stage
1202 // Only expressions that are created for the parser need to implement
1205 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1207 throw new NotImplementedException (
1209 "CloneTo not implemented for expression {0}", this.GetType ()));
1213 // Clones an expression created by the parser.
1215 // We only support expressions created by the parser so far, not
1216 // expressions that have been resolved (many more classes would need
1217 // to implement CloneTo).
1219 // This infrastructure is here merely for Lambda expressions which
1220 // compile the same code using different type values for the same
1221 // arguments to find the correct overload
1223 public virtual Expression Clone (CloneContext clonectx)
1225 Expression cloned = (Expression) MemberwiseClone ();
1226 CloneTo (clonectx, cloned);
1232 // Implementation of expression to expression tree conversion
1234 public abstract Expression CreateExpressionTree (ResolveContext ec);
1236 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1238 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1241 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1243 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1246 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1248 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1251 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1253 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1257 return new TypeExpression (t, loc);
1261 // Implemented by all expressions which support conversion from
1262 // compiler expression to invokable runtime expression. Used by
1263 // dynamic C# binder.
1265 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1267 throw new NotImplementedException ("MakeExpression for " + GetType ());
1270 public virtual object Accept (StructuralVisitor visitor)
1272 return visitor.Visit (this);
1277 /// This is just a base class for expressions that can
1278 /// appear on statements (invocations, object creation,
1279 /// assignments, post/pre increment and decrement). The idea
1280 /// being that they would support an extra Emition interface that
1281 /// does not leave a result on the stack.
1283 public abstract class ExpressionStatement : Expression
1285 public virtual void MarkReachable (Reachability rc)
1289 public ExpressionStatement ResolveStatement (BlockContext ec)
1291 Expression e = Resolve (ec);
1295 ExpressionStatement es = e as ExpressionStatement;
1296 if (es == null || e is AnonymousMethodBody)
1297 Error_InvalidExpressionStatement (ec);
1300 // This is quite expensive warning, try to limit the damage
1302 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1303 WarningAsyncWithoutWait (ec, e);
1309 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1311 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1312 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1317 // Need to do full resolve because GetAwaiter can be extension method
1318 // available only in this context
1320 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1324 var arguments = new Arguments (0);
1325 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1330 // Use same check rules as for real await
1332 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1333 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1336 bc.Report.Warning (4014, 1, e.Location,
1337 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1341 var inv = e as Invocation;
1342 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1343 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1344 bc.Report.Warning (4014, 1, e.Location,
1345 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1351 /// Requests the expression to be emitted in a `statement'
1352 /// context. This means that no new value is left on the
1353 /// stack after invoking this method (constrasted with
1354 /// Emit that will always leave a value on the stack).
1356 public abstract void EmitStatement (EmitContext ec);
1358 public override void EmitSideEffect (EmitContext ec)
1365 /// This kind of cast is used to encapsulate the child
1366 /// whose type is child.Type into an expression that is
1367 /// reported to return "return_type". This is used to encapsulate
1368 /// expressions which have compatible types, but need to be dealt
1369 /// at higher levels with.
1371 /// For example, a "byte" expression could be encapsulated in one
1372 /// of these as an "unsigned int". The type for the expression
1373 /// would be "unsigned int".
1376 public abstract class TypeCast : Expression
1378 protected readonly Expression child;
1380 protected TypeCast (Expression child, TypeSpec return_type)
1382 eclass = child.eclass;
1383 loc = child.Location;
1388 public Expression Child {
1394 public override bool ContainsEmitWithAwait ()
1396 return child.ContainsEmitWithAwait ();
1399 public override Expression CreateExpressionTree (ResolveContext ec)
1401 Arguments args = new Arguments (2);
1402 args.Add (new Argument (child.CreateExpressionTree (ec)));
1403 args.Add (new Argument (new TypeOf (type, loc)));
1405 if (type.IsPointer || child.Type.IsPointer)
1406 Error_PointerInsideExpressionTree (ec);
1408 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1411 protected override Expression DoResolve (ResolveContext ec)
1413 // This should never be invoked, we are born in fully
1414 // initialized state.
1419 public override void Emit (EmitContext ec)
1424 public override void FlowAnalysis (FlowAnalysisContext fc)
1426 child.FlowAnalysis (fc);
1429 public override SLE.Expression MakeExpression (BuilderContext ctx)
1432 return base.MakeExpression (ctx);
1434 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1435 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1436 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1440 protected override void CloneTo (CloneContext clonectx, Expression t)
1445 public override bool IsNull {
1446 get { return child.IsNull; }
1450 public class EmptyCast : TypeCast {
1451 EmptyCast (Expression child, TypeSpec target_type)
1452 : base (child, target_type)
1456 public static Expression Create (Expression child, TypeSpec type)
1458 Constant c = child as Constant;
1460 var enum_constant = c as EnumConstant;
1461 if (enum_constant != null)
1462 c = enum_constant.Child;
1464 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1468 var res = c.ConvertImplicitly (type);
1474 EmptyCast e = child as EmptyCast;
1476 return new EmptyCast (e.child, type);
1478 return new EmptyCast (child, type);
1481 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1483 child.EmitBranchable (ec, label, on_true);
1486 public override void EmitSideEffect (EmitContext ec)
1488 child.EmitSideEffect (ec);
1493 // Used for predefined type user operator (no obsolete check, etc.)
1495 public class OperatorCast : TypeCast
1497 readonly MethodSpec conversion_operator;
1499 public OperatorCast (Expression expr, TypeSpec target_type)
1500 : this (expr, target_type, target_type, false)
1504 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1505 : this (expr, target_type, target_type, find_explicit)
1509 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1510 : base (expr, returnType)
1512 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1513 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1516 foreach (MethodSpec oper in mi) {
1517 if (oper.ReturnType != returnType)
1520 if (oper.Parameters.Types[0] == expr.Type) {
1521 conversion_operator = oper;
1527 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1528 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1531 public override void Emit (EmitContext ec)
1534 ec.Emit (OpCodes.Call, conversion_operator);
1539 // Constant specialization of EmptyCast.
1540 // We need to special case this since an empty cast of
1541 // a constant is still a constant.
1543 public class EmptyConstantCast : Constant
1545 public readonly Constant child;
1547 public EmptyConstantCast (Constant child, TypeSpec type)
1548 : base (child.Location)
1551 throw new ArgumentNullException ("child");
1554 this.eclass = child.eclass;
1558 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1560 if (child.Type == target_type)
1563 // FIXME: check that 'type' can be converted to 'target_type' first
1564 return child.ConvertExplicitly (in_checked_context, target_type);
1567 public override Expression CreateExpressionTree (ResolveContext ec)
1569 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1570 child.CreateExpressionTree (ec),
1571 new TypeOf (type, loc));
1574 Error_PointerInsideExpressionTree (ec);
1576 return CreateExpressionFactoryCall (ec, "Convert", args);
1579 public override bool IsDefaultValue {
1580 get { return child.IsDefaultValue; }
1583 public override bool IsNegative {
1584 get { return child.IsNegative; }
1587 public override bool IsNull {
1588 get { return child.IsNull; }
1591 public override bool IsOneInteger {
1592 get { return child.IsOneInteger; }
1595 public override bool IsSideEffectFree {
1597 return child.IsSideEffectFree;
1601 public override bool IsZeroInteger {
1602 get { return child.IsZeroInteger; }
1605 public override void Emit (EmitContext ec)
1610 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1612 child.EmitBranchable (ec, label, on_true);
1614 // Only to make verifier happy
1615 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1616 ec.Emit (OpCodes.Unbox_Any, type);
1619 public override void EmitSideEffect (EmitContext ec)
1621 child.EmitSideEffect (ec);
1624 public override object GetValue ()
1626 return child.GetValue ();
1629 public override string GetValueAsLiteral ()
1631 return child.GetValueAsLiteral ();
1634 public override long GetValueAsLong ()
1636 return child.GetValueAsLong ();
1639 public override Constant ConvertImplicitly (TypeSpec target_type)
1641 if (type == target_type)
1644 // FIXME: Do we need to check user conversions?
1645 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1648 return child.ConvertImplicitly (target_type);
1653 /// This class is used to wrap literals which belong inside Enums
1655 public class EnumConstant : Constant
1657 public Constant Child;
1659 public EnumConstant (Constant child, TypeSpec enum_type)
1660 : base (child.Location)
1664 this.eclass = ExprClass.Value;
1665 this.type = enum_type;
1668 protected EnumConstant (Location loc)
1673 public override void Emit (EmitContext ec)
1678 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1680 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1683 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1685 Child.EmitBranchable (ec, label, on_true);
1688 public override void EmitSideEffect (EmitContext ec)
1690 Child.EmitSideEffect (ec);
1693 public override string GetSignatureForError()
1695 return Type.GetSignatureForError ();
1698 public override object GetValue ()
1700 return Child.GetValue ();
1704 public override object GetTypedValue ()
1707 // The method can be used in dynamic context only (on closed types)
1709 // System.Enum.ToObject cannot be called on dynamic types
1710 // EnumBuilder has to be used, but we cannot use EnumBuilder
1711 // because it does not properly support generics
1713 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1717 public override string GetValueAsLiteral ()
1719 return Child.GetValueAsLiteral ();
1722 public override long GetValueAsLong ()
1724 return Child.GetValueAsLong ();
1727 public EnumConstant Increment()
1729 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1732 public override bool IsDefaultValue {
1734 return Child.IsDefaultValue;
1738 public override bool IsSideEffectFree {
1740 return Child.IsSideEffectFree;
1744 public override bool IsZeroInteger {
1745 get { return Child.IsZeroInteger; }
1748 public override bool IsNegative {
1750 return Child.IsNegative;
1754 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1756 if (Child.Type == target_type)
1759 return Child.ConvertExplicitly (in_checked_context, target_type);
1762 public override Constant ConvertImplicitly (TypeSpec type)
1764 if (this.type == type) {
1768 if (!Convert.ImplicitStandardConversionExists (this, type)){
1772 return Child.ConvertImplicitly (type);
1777 /// This kind of cast is used to encapsulate Value Types in objects.
1779 /// The effect of it is to box the value type emitted by the previous
1782 public class BoxedCast : TypeCast {
1784 public BoxedCast (Expression expr, TypeSpec target_type)
1785 : base (expr, target_type)
1787 eclass = ExprClass.Value;
1790 protected override Expression DoResolve (ResolveContext ec)
1792 // This should never be invoked, we are born in fully
1793 // initialized state.
1798 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1800 // Only boxing to object type is supported
1801 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1802 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1806 enc.Encode (child.Type);
1807 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1810 public override void Emit (EmitContext ec)
1814 ec.Emit (OpCodes.Box, child.Type);
1817 public override void EmitSideEffect (EmitContext ec)
1819 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1820 // so, we need to emit the box+pop instructions in most cases
1821 if (child.Type.IsStruct &&
1822 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1823 child.EmitSideEffect (ec);
1825 base.EmitSideEffect (ec);
1829 public class UnboxCast : TypeCast {
1830 public UnboxCast (Expression expr, TypeSpec return_type)
1831 : base (expr, return_type)
1835 protected override Expression DoResolve (ResolveContext ec)
1837 // This should never be invoked, we are born in fully
1838 // initialized state.
1843 public override void Emit (EmitContext ec)
1847 ec.Emit (OpCodes.Unbox_Any, type);
1852 /// This is used to perform explicit numeric conversions.
1854 /// Explicit numeric conversions might trigger exceptions in a checked
1855 /// context, so they should generate the conv.ovf opcodes instead of
1858 public class ConvCast : TypeCast {
1859 public enum Mode : byte {
1860 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1862 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1863 U2_I1, U2_U1, U2_I2, U2_CH,
1864 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1865 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1866 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1867 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1868 CH_I1, CH_U1, CH_I2,
1869 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1870 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1876 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1877 : base (child, return_type)
1882 protected override Expression DoResolve (ResolveContext ec)
1884 // This should never be invoked, we are born in fully
1885 // initialized state.
1890 public override string ToString ()
1892 return String.Format ("ConvCast ({0}, {1})", mode, child);
1895 public override void Emit (EmitContext ec)
1901 public static void Emit (EmitContext ec, Mode mode)
1903 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1905 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1906 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1907 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1908 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1909 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1911 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1912 case Mode.U1_CH: /* nothing */ break;
1914 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1915 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1916 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1917 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1918 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1919 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1921 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1922 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1923 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1924 case Mode.U2_CH: /* nothing */ break;
1926 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1927 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1928 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1929 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1930 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1931 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1932 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1935 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1936 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1937 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1938 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1939 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1941 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1942 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1943 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1944 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1945 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1946 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1948 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1949 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1951 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1952 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1953 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1954 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1955 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1956 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1957 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1958 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1959 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1961 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1962 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1963 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1965 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1966 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1967 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1968 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1969 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1970 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1971 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1972 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1973 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1975 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1976 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1977 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1978 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1979 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1980 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1981 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1982 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1983 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1984 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1986 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1990 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1991 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1992 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1993 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1994 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1996 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1997 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1999 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
2000 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
2001 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
2002 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
2003 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
2004 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
2006 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
2007 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
2008 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
2009 case Mode.U2_CH: /* nothing */ break;
2011 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
2012 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
2013 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
2014 case Mode.I4_U4: /* nothing */ break;
2015 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
2016 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2023 case Mode.U4_I4: /* nothing */ break;
2024 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2026 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2027 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2028 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2029 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2030 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2031 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2032 case Mode.I8_U8: /* nothing */ break;
2033 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2034 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2036 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2037 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2038 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2039 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2040 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2041 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2042 case Mode.U8_I8: /* nothing */ break;
2043 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2044 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2046 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2047 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2048 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2050 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2051 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2052 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2053 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2054 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2055 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2056 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2057 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2058 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2060 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2061 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2062 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2063 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2064 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2065 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2066 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2067 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2068 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2069 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2071 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2077 class OpcodeCast : TypeCast
2081 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2082 : base (child, return_type)
2087 protected override Expression DoResolve (ResolveContext ec)
2089 // This should never be invoked, we are born in fully
2090 // initialized state.
2095 public override void Emit (EmitContext ec)
2101 public TypeSpec UnderlyingType {
2102 get { return child.Type; }
2107 // Opcode casts expression with 2 opcodes but only
2108 // single expression tree node
2110 class OpcodeCastDuplex : OpcodeCast
2112 readonly OpCode second;
2114 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2115 : base (child, returnType, first)
2117 this.second = second;
2120 public override void Emit (EmitContext ec)
2128 /// This kind of cast is used to encapsulate a child and cast it
2129 /// to the class requested
2131 public sealed class ClassCast : TypeCast {
2132 readonly bool forced;
2134 public ClassCast (Expression child, TypeSpec return_type)
2135 : base (child, return_type)
2139 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2140 : base (child, return_type)
2142 this.forced = forced;
2145 public override void Emit (EmitContext ec)
2149 bool gen = TypeManager.IsGenericParameter (child.Type);
2151 ec.Emit (OpCodes.Box, child.Type);
2153 if (type.IsGenericParameter) {
2154 ec.Emit (OpCodes.Unbox_Any, type);
2161 ec.Emit (OpCodes.Castclass, type);
2166 // Created during resolving pahse when an expression is wrapped or constantified
2167 // and original expression can be used later (e.g. for expression trees)
2169 public class ReducedExpression : Expression
2171 public sealed class ReducedConstantExpression : EmptyConstantCast
2173 readonly Expression orig_expr;
2175 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2176 : base (expr, expr.Type)
2178 this.orig_expr = orig_expr;
2181 public Expression OriginalExpression {
2187 public override Constant ConvertImplicitly (TypeSpec target_type)
2189 Constant c = base.ConvertImplicitly (target_type);
2191 c = new ReducedConstantExpression (c, orig_expr);
2196 public override Expression CreateExpressionTree (ResolveContext ec)
2198 return orig_expr.CreateExpressionTree (ec);
2201 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2203 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2205 c = new ReducedConstantExpression (c, orig_expr);
2209 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2212 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2214 if (orig_expr is Conditional)
2215 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2217 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2221 sealed class ReducedExpressionStatement : ExpressionStatement
2223 readonly Expression orig_expr;
2224 readonly ExpressionStatement stm;
2226 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2228 this.orig_expr = orig;
2230 this.eclass = stm.eclass;
2231 this.type = stm.Type;
2233 this.loc = orig.Location;
2236 public override bool ContainsEmitWithAwait ()
2238 return stm.ContainsEmitWithAwait ();
2241 public override Expression CreateExpressionTree (ResolveContext ec)
2243 return orig_expr.CreateExpressionTree (ec);
2246 protected override Expression DoResolve (ResolveContext ec)
2251 public override void Emit (EmitContext ec)
2256 public override void EmitStatement (EmitContext ec)
2258 stm.EmitStatement (ec);
2261 public override void FlowAnalysis (FlowAnalysisContext fc)
2263 stm.FlowAnalysis (fc);
2267 readonly Expression expr, orig_expr;
2269 private ReducedExpression (Expression expr, Expression orig_expr)
2272 this.eclass = expr.eclass;
2273 this.type = expr.Type;
2274 this.orig_expr = orig_expr;
2275 this.loc = orig_expr.Location;
2280 public override bool IsSideEffectFree {
2282 return expr.IsSideEffectFree;
2286 public Expression OriginalExpression {
2294 public override bool ContainsEmitWithAwait ()
2296 return expr.ContainsEmitWithAwait ();
2300 // Creates fully resolved expression switcher
2302 public static Constant Create (Constant expr, Expression original_expr)
2304 if (expr.eclass == ExprClass.Unresolved)
2305 throw new ArgumentException ("Unresolved expression");
2307 return new ReducedConstantExpression (expr, original_expr);
2310 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2312 return new ReducedExpressionStatement (s, orig);
2315 public static Expression Create (Expression expr, Expression original_expr)
2317 return Create (expr, original_expr, true);
2321 // Creates unresolved reduce expression. The original expression has to be
2322 // already resolved. Created expression is constant based based on `expr'
2323 // value unless canBeConstant is used
2325 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2327 if (canBeConstant) {
2328 Constant c = expr as Constant;
2330 return Create (c, original_expr);
2333 ExpressionStatement s = expr as ExpressionStatement;
2335 return Create (s, original_expr);
2337 if (expr.eclass == ExprClass.Unresolved)
2338 throw new ArgumentException ("Unresolved expression");
2340 return new ReducedExpression (expr, original_expr);
2343 public override Expression CreateExpressionTree (ResolveContext ec)
2345 return orig_expr.CreateExpressionTree (ec);
2348 protected override Expression DoResolve (ResolveContext ec)
2353 public override void Emit (EmitContext ec)
2358 public override Expression EmitToField (EmitContext ec)
2360 return expr.EmitToField(ec);
2363 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2365 expr.EmitBranchable (ec, target, on_true);
2368 public override void FlowAnalysis (FlowAnalysisContext fc)
2370 expr.FlowAnalysis (fc);
2373 public override SLE.Expression MakeExpression (BuilderContext ctx)
2375 return orig_expr.MakeExpression (ctx);
2380 // Standard composite pattern
2382 public abstract class CompositeExpression : Expression
2384 protected Expression expr;
2386 protected CompositeExpression (Expression expr)
2389 this.loc = expr.Location;
2392 public override bool ContainsEmitWithAwait ()
2394 return expr.ContainsEmitWithAwait ();
2397 public override Expression CreateExpressionTree (ResolveContext rc)
2399 return expr.CreateExpressionTree (rc);
2402 public Expression Child {
2403 get { return expr; }
2406 protected override Expression DoResolve (ResolveContext rc)
2408 expr = expr.Resolve (rc);
2413 eclass = expr.eclass;
2417 public override void Emit (EmitContext ec)
2422 public override bool IsNull {
2423 get { return expr.IsNull; }
2428 // Base of expressions used only to narrow resolve flow
2430 public abstract class ShimExpression : Expression
2432 protected Expression expr;
2434 protected ShimExpression (Expression expr)
2439 public Expression Expr {
2445 protected override void CloneTo (CloneContext clonectx, Expression t)
2450 ShimExpression target = (ShimExpression) t;
2451 target.expr = expr.Clone (clonectx);
2454 public override bool ContainsEmitWithAwait ()
2456 return expr.ContainsEmitWithAwait ();
2459 public override Expression CreateExpressionTree (ResolveContext ec)
2461 throw new NotSupportedException ("ET");
2464 public override void Emit (EmitContext ec)
2466 throw new InternalErrorException ("Missing Resolve call");
2470 public class UnreachableExpression : Expression
2472 public UnreachableExpression (Expression expr)
2474 this.loc = expr.Location;
2477 public override Expression CreateExpressionTree (ResolveContext ec)
2480 throw new NotImplementedException ();
2483 protected override Expression DoResolve (ResolveContext rc)
2485 throw new NotSupportedException ();
2488 public override void FlowAnalysis (FlowAnalysisContext fc)
2490 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2493 public override void Emit (EmitContext ec)
2497 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2503 // Unresolved type name expressions
2505 public abstract class ATypeNameExpression : FullNamedExpression
2508 protected TypeArguments targs;
2510 protected ATypeNameExpression (string name, Location l)
2516 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2523 protected ATypeNameExpression (string name, int arity, Location l)
2524 : this (name, new UnboundTypeArguments (arity), l)
2532 return targs == null ? 0 : targs.Count;
2536 public bool HasTypeArguments {
2538 return targs != null && !targs.IsEmpty;
2542 public string Name {
2551 public TypeArguments TypeArguments {
2559 public override bool Equals (object obj)
2561 ATypeNameExpression atne = obj as ATypeNameExpression;
2562 return atne != null && atne.Name == Name &&
2563 (targs == null || targs.Equals (atne.targs));
2566 protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
2568 mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
2571 public override int GetHashCode ()
2573 return Name.GetHashCode ();
2576 // TODO: Move it to MemberCore
2577 public static string GetMemberType (MemberCore mc)
2583 if (mc is FieldBase)
2585 if (mc is MethodCore)
2587 if (mc is EnumMember)
2595 public override string GetSignatureForError ()
2597 if (targs != null) {
2598 return Name + "<" + targs.GetSignatureForError () + ">";
2604 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2608 /// SimpleName expressions are formed of a single word and only happen at the beginning
2609 /// of a dotted-name.
2611 public class SimpleName : ATypeNameExpression
2613 public SimpleName (string name, Location l)
2618 public SimpleName (string name, TypeArguments args, Location l)
2619 : base (name, args, l)
2623 public SimpleName (string name, int arity, Location l)
2624 : base (name, arity, l)
2628 public SimpleName GetMethodGroup ()
2630 return new SimpleName (Name, targs, loc);
2633 protected override Expression DoResolve (ResolveContext rc)
2635 return SimpleNameResolve (rc, null);
2638 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2640 return SimpleNameResolve (ec, right_side);
2643 public void Error_NameDoesNotExist (ResolveContext rc)
2645 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2648 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2650 if (ctx.CurrentType != null) {
2651 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2652 if (member != null) {
2653 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2658 var report = ctx.Module.Compiler.Report;
2660 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2661 if (retval != null) {
2662 report.SymbolRelatedToPreviousError (retval.Type);
2663 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2667 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2668 if (retval != null) {
2669 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2673 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2674 if (ns_candidates != null) {
2675 if (ctx is UsingAliasNamespace.AliasContext) {
2676 report.Error (246, loc,
2677 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2678 ns_candidates[0], Name);
2680 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2681 report.Error (246, loc,
2682 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2686 report.Error (246, loc,
2687 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2692 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2694 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2697 if (fne.Type != null && Arity > 0) {
2698 if (HasTypeArguments) {
2699 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2700 if (ct.ResolveAsType (mc) == null)
2706 if (!allowUnboundTypeArguments)
2707 Error_OpenGenericTypeIsNotAllowed (mc);
2709 return new GenericOpenTypeExpr (fne.Type, loc);
2713 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2715 if (!(fne is NamespaceExpression))
2719 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2720 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2721 mc.Module.Compiler.Report.Error (1980, Location,
2722 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2723 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2726 fne = new DynamicTypeExpr (loc);
2727 fne.ResolveAsType (mc);
2733 Error_TypeOrNamespaceNotFound (mc);
2737 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2739 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2742 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2744 int lookup_arity = Arity;
2745 bool errorMode = false;
2747 Block current_block = rc.CurrentBlock;
2748 INamedBlockVariable variable = null;
2749 bool variable_found = false;
2753 // Stage 1: binding to local variables or parameters
2755 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2757 if (current_block != null && lookup_arity == 0) {
2758 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2759 if (!variable.IsDeclared) {
2760 // We found local name in accessible block but it's not
2761 // initialized yet, maybe the user wanted to bind to something else
2763 variable_found = true;
2765 e = variable.CreateReferenceExpression (rc, loc);
2768 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2777 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2779 TypeSpec member_type = rc.CurrentType;
2780 for (; member_type != null; member_type = member_type.DeclaringType) {
2781 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2785 var me = e as MemberExpr;
2787 // The name matches a type, defer to ResolveAsTypeStep
2795 if (variable != null) {
2796 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2797 rc.Report.Error (844, loc,
2798 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2799 Name, me.GetSignatureForError ());
2803 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2804 // Leave it to overload resolution to report correct error
2806 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2807 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2810 // LAMESPEC: again, ignores InvocableOnly
2811 if (variable != null) {
2812 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2813 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2817 // MemberLookup does not check accessors availability, this is actually needed for properties only
2819 var pe = me as PropertyExpr;
2822 // Break as there is no other overload available anyway
2823 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2824 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2827 pe.Getter = pe.PropertyInfo.Get;
2829 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2832 pe.Setter = pe.PropertyInfo.Set;
2837 // TODO: It's used by EventExpr -> FieldExpr transformation only
2838 // TODO: Should go to MemberAccess
2839 me = me.ResolveMemberAccess (rc, null, null);
2843 me.SetTypeArguments (rc, targs);
2850 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2852 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2853 if (IsPossibleTypeOrNamespace (rc)) {
2854 if (variable != null) {
2855 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2856 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2859 return ResolveAsTypeOrNamespace (rc, false);
2863 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2867 mg.SetTypeArguments (rc, targs);
2872 if (Name == "nameof")
2873 return new NameOf (this);
2876 if (variable_found) {
2877 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2880 var tparams = rc.CurrentTypeParameters;
2881 if (tparams != null) {
2882 if (tparams.Find (Name) != null) {
2883 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2888 var ct = rc.CurrentType;
2890 if (ct.MemberDefinition.TypeParametersCount > 0) {
2891 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2892 if (ctp.Name == Name) {
2893 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2899 ct = ct.DeclaringType;
2900 } while (ct != null);
2903 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2904 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2906 rc.Report.SymbolRelatedToPreviousError (e.Type);
2907 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2911 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2913 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2914 return ErrorExpression.Instance;
2918 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2920 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2921 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2925 if (e is TypeExpr) {
2926 // TypeExpression does not have correct location
2927 if (e is TypeExpression)
2928 e = new TypeExpression (e.Type, loc);
2934 Error_NameDoesNotExist (rc);
2937 return ErrorExpression.Instance;
2940 if (rc.Module.Evaluator != null) {
2941 var fi = rc.Module.Evaluator.LookupField (Name);
2943 return new FieldExpr (fi.Item1, loc);
2951 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2953 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2958 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2959 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2963 if (right_side != null) {
2964 e = e.ResolveLValue (ec, right_side);
2972 public override object Accept (StructuralVisitor visitor)
2974 return visitor.Visit (this);
2979 /// Represents a namespace or a type. The name of the class was inspired by
2980 /// section 10.8.1 (Fully Qualified Names).
2982 public abstract class FullNamedExpression : Expression
2984 protected override void CloneTo (CloneContext clonectx, Expression target)
2986 // Do nothing, most unresolved type expressions cannot be
2987 // resolved to different type
2990 public override bool ContainsEmitWithAwait ()
2995 public override Expression CreateExpressionTree (ResolveContext ec)
2997 throw new NotSupportedException ("ET");
3000 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
3003 // This is used to resolve the expression as a type, a null
3004 // value will be returned if the expression is not a type
3007 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3009 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
3014 TypeExpr te = fne as TypeExpr;
3016 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3024 var dep = type.GetMissingDependencies ();
3026 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3029 if (type.Kind == MemberKind.Void) {
3030 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3034 // Obsolete checks cannot be done when resolving base context as they
3035 // require type dependencies to be set but we are in process of resolving them
3037 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3038 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3039 if (obsolete_attr != null && !mc.IsObsolete) {
3040 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3048 public override void Emit (EmitContext ec)
3050 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3051 GetSignatureForError ());
3056 /// Expression that evaluates to a type
3058 public abstract class TypeExpr : FullNamedExpression
3060 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3066 protected sealed override Expression DoResolve (ResolveContext ec)
3072 public override bool Equals (object obj)
3074 TypeExpr tobj = obj as TypeExpr;
3078 return Type == tobj.Type;
3081 public override int GetHashCode ()
3083 return Type.GetHashCode ();
3088 /// Fully resolved Expression that already evaluated to a type
3090 public class TypeExpression : TypeExpr
3092 public TypeExpression (TypeSpec t, Location l)
3095 eclass = ExprClass.Type;
3099 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3105 public class NamespaceExpression : FullNamedExpression
3107 readonly Namespace ns;
3109 public NamespaceExpression (Namespace ns, Location loc)
3112 this.Type = InternalType.Namespace;
3113 this.eclass = ExprClass.Namespace;
3117 public Namespace Namespace {
3123 protected override Expression DoResolve (ResolveContext rc)
3125 throw new NotImplementedException ();
3128 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3133 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3135 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3136 if (retval != null) {
3137 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3138 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3142 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3143 if (retval != null) {
3144 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3149 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3150 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3154 string assembly = null;
3155 string possible_name = Namespace.GetSignatureForError () + "." + name;
3157 // Only assembly unique name should be added
3158 switch (possible_name) {
3159 case "System.Drawing":
3160 case "System.Web.Services":
3163 case "System.Configuration":
3164 case "System.Data.Services":
3165 case "System.DirectoryServices":
3167 case "System.Net.Http":
3168 case "System.Numerics":
3169 case "System.Runtime.Caching":
3170 case "System.ServiceModel":
3171 case "System.Transactions":
3172 case "System.Web.Routing":
3173 case "System.Xml.Linq":
3175 assembly = possible_name;
3179 case "System.Linq.Expressions":
3180 assembly = "System.Core";
3183 case "System.Windows.Forms":
3184 case "System.Windows.Forms.Layout":
3185 assembly = "System.Windows.Forms";
3189 assembly = assembly == null ? "an" : "`" + assembly + "'";
3191 if (Namespace is GlobalRootNamespace) {
3192 ctx.Module.Compiler.Report.Error (400, loc,
3193 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3196 ctx.Module.Compiler.Report.Error (234, loc,
3197 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3198 name, GetSignatureForError (), assembly);
3202 public override string GetSignatureForError ()
3204 return ns.GetSignatureForError ();
3207 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3209 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3212 public override string ToString ()
3214 return Namespace.Name;
3219 /// This class denotes an expression which evaluates to a member
3220 /// of a struct or a class.
3222 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3224 protected bool conditional_access_receiver;
3227 // An instance expression associated with this member, if it's a
3228 // non-static member
3230 public Expression InstanceExpression;
3233 /// The name of this member.
3235 public abstract string Name {
3240 // When base.member is used
3242 public bool IsBase {
3243 get { return InstanceExpression is BaseThis; }
3247 /// Whether this is an instance member.
3249 public abstract bool IsInstance {
3254 /// Whether this is a static member.
3256 public abstract bool IsStatic {
3260 public abstract string KindName {
3264 public bool ConditionalAccess { get; set; }
3266 protected abstract TypeSpec DeclaringType {
3270 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3272 return InstanceExpression.Type;
3277 // Converts best base candidate for virtual method starting from QueriedBaseType
3279 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3282 // Only when base.member is used and method is virtual
3288 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3289 // means for base.member access we have to find the closest match after we found best candidate
3291 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3293 // The method could already be what we are looking for
3295 TypeSpec[] targs = null;
3296 if (method.DeclaringType != InstanceExpression.Type) {
3298 // Candidate can have inflated MVAR parameters and we need to find
3299 // base match for original definition not inflated parameter types
3301 var parameters = method.Parameters;
3302 if (method.Arity > 0) {
3303 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3304 var inflated = method.DeclaringType as InflatedTypeSpec;
3305 if (inflated != null) {
3306 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3310 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3311 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3312 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3313 if (base_override.IsGeneric)
3314 targs = method.TypeArguments;
3316 method = base_override;
3321 // When base access is used inside anonymous method/iterator/etc we need to
3322 // get back to the context of original type. We do it by emiting proxy
3323 // method in original class and rewriting base call to this compiler
3324 // generated method call which does the actual base invocation. This may
3325 // introduce redundant storey but with `this' only but it's tricky to avoid
3326 // at this stage as we don't know what expressions follow base
3328 if (rc.CurrentAnonymousMethod != null) {
3329 if (targs == null && method.IsGeneric) {
3330 targs = method.TypeArguments;
3331 method = method.GetGenericMethodDefinition ();
3334 if (method.Parameters.HasArglist)
3335 throw new NotImplementedException ("__arglist base call proxy");
3337 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3339 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3340 // get/set member expressions second call would fail to proxy because left expression
3341 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3342 // FIXME: The async check is another hack but will probably fail with mutators
3343 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3344 InstanceExpression = new This (loc).Resolve (rc);
3348 method = method.MakeGenericMethod (rc, targs);
3352 // Only base will allow this invocation to happen.
3354 if (method.IsAbstract) {
3355 rc.Report.SymbolRelatedToPreviousError (method);
3356 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3362 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3364 if (InstanceExpression == null)
3367 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3368 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3369 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3374 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3376 if (InstanceExpression == null)
3379 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3382 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3384 var ct = rc.CurrentType;
3385 if (ct == qualifier)
3388 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3391 qualifier = qualifier.GetDefinition ();
3392 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3399 public override bool ContainsEmitWithAwait ()
3401 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3404 public override bool HasConditionalAccess ()
3406 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3409 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3412 type = type.GetDefinition ();
3414 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3417 type = type.DeclaringType;
3418 } while (type != null);
3423 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3425 if (InstanceExpression != null) {
3426 InstanceExpression = InstanceExpression.Resolve (rc);
3427 CheckProtectedMemberAccess (rc, member);
3430 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3431 UnsafeError (rc, loc);
3434 var dep = member.GetMissingDependencies ();
3436 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3439 if (!rc.IsObsolete) {
3440 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3442 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3445 if (!(member is FieldSpec))
3446 member.MemberDefinition.SetIsUsed ();
3449 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3451 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3454 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3456 rc.Report.SymbolRelatedToPreviousError (member);
3457 rc.Report.Error (1540, loc,
3458 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3459 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3462 public override void FlowAnalysis (FlowAnalysisContext fc)
3464 if (InstanceExpression != null) {
3465 InstanceExpression.FlowAnalysis (fc);
3467 if (ConditionalAccess) {
3468 fc.BranchConditionalAccessDefiniteAssignment ();
3473 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3475 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3476 if (HasConditionalAccess ()) {
3477 conditional_access_receiver = true;
3478 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3483 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3485 if (!ResolveInstanceExpressionCore (rc, rhs))
3489 // Check intermediate value modification which won't have any effect
3491 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3492 var fexpr = InstanceExpression as FieldExpr;
3493 if (fexpr != null) {
3494 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3497 if (fexpr.IsStatic) {
3498 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3499 fexpr.GetSignatureForError ());
3501 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3502 fexpr.GetSignatureForError ());
3508 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3509 if (rc.CurrentInitializerVariable != null) {
3510 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3511 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3513 rc.Report.Error (1612, loc,
3514 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3515 InstanceExpression.GetSignatureForError ());
3521 var lvr = InstanceExpression as LocalVariableReference;
3524 if (!lvr.local_info.IsReadonly)
3527 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3528 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3535 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3538 if (InstanceExpression != null) {
3539 if (InstanceExpression is TypeExpr) {
3540 var t = InstanceExpression.Type;
3542 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3543 if (oa != null && !rc.IsObsolete) {
3544 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3547 t = t.DeclaringType;
3548 } while (t != null);
3550 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3551 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3552 rc.Report.Error (176, loc,
3553 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3554 GetSignatureForError ());
3558 InstanceExpression = null;
3564 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3565 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3566 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3567 rc.Report.Error (236, loc,
3568 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3569 GetSignatureForError ());
3571 var fe = this as FieldExpr;
3572 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3573 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3574 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3576 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3580 rc.Report.Error (120, loc,
3581 "An object reference is required to access non-static member `{0}'",
3582 GetSignatureForError ());
3586 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3590 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3591 rc.Report.Error (38, loc,
3592 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3593 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3596 InstanceExpression = new This (loc).Resolve (rc);
3600 var me = InstanceExpression as MemberExpr;
3602 me.ResolveInstanceExpressionCore (rc, rhs);
3604 var fe = me as FieldExpr;
3605 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3606 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3607 rc.Report.Warning (1690, 1, loc,
3608 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3609 me.GetSignatureForError ());
3616 // Additional checks for l-value member access
3619 if (InstanceExpression is UnboxCast) {
3620 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3627 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3629 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3630 ec.Report.Warning (1720, 1, left.Location,
3631 "Expression will always cause a `{0}'", "System.NullReferenceException");
3634 InstanceExpression = left;
3638 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3640 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3641 inst.Emit (ec, ConditionalAccess);
3643 if (prepare_for_load)
3644 ec.Emit (OpCodes.Dup);
3647 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3650 public class ExtensionMethodCandidates
3652 readonly NamespaceContainer container;
3653 readonly IList<MethodSpec> methods;
3655 readonly IMemberContext context;
3657 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3659 this.context = context;
3660 this.methods = methods;
3661 this.container = nsContainer;
3662 this.index = lookupIndex;
3665 public NamespaceContainer Container {
3671 public IMemberContext Context {
3677 public int LookupIndex {
3683 public IList<MethodSpec> Methods {
3691 // Represents a group of extension method candidates for whole namespace
3693 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3695 ExtensionMethodCandidates candidates;
3696 public Expression ExtensionExpression;
3698 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3699 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3701 this.candidates = candidates;
3702 this.ExtensionExpression = extensionExpr;
3705 public override bool IsStatic {
3706 get { return true; }
3709 public override void FlowAnalysis (FlowAnalysisContext fc)
3711 if (ConditionalAccess) {
3712 fc.BranchConditionalAccessDefiniteAssignment ();
3717 // For extension methodgroup we are not looking for base members but parent
3718 // namespace extension methods
3720 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3722 // TODO: candidates are null only when doing error reporting, that's
3723 // incorrect. We have to discover same extension methods in error mode
3724 if (candidates == null)
3727 int arity = type_arguments == null ? 0 : type_arguments.Count;
3729 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3730 if (candidates == null)
3733 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3736 public static bool IsExtensionTypeCompatible (TypeSpec argType, TypeSpec extensionType)
3739 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3741 // LAMESPEC: or implicit type parameter conversion
3743 return argType == extensionType ||
3744 TypeSpecComparer.IsEqual (argType, extensionType) ||
3745 Convert.ImplicitReferenceConversionExists (argType, extensionType, false) ||
3746 Convert.ImplicitBoxingConversion (null, argType, extensionType) != null;
3749 public bool ResolveNameOf (ResolveContext rc, MemberAccess ma)
3751 ExtensionExpression = ExtensionExpression.Resolve (rc);
3752 if (ExtensionExpression == null)
3755 var argType = ExtensionExpression.Type;
3756 foreach (MethodSpec candidate in Candidates) {
3757 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (argType, candidate.Parameters.ExtensionMethodType))
3761 // TODO: Scan full hierarchy
3763 ma.Error_TypeDoesNotContainDefinition (rc, argType, ma.Name);
3767 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3769 // We are already here
3773 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3775 if (arguments == null)
3776 arguments = new Arguments (1);
3778 ExtensionExpression = ExtensionExpression.Resolve (ec);
3779 if (ExtensionExpression == null)
3782 var cand = candidates;
3783 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3784 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3785 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3787 // Restore candidates in case we are running in probing mode
3790 // Store resolved argument and restore original arguments
3792 // Clean-up modified arguments for error reporting
3793 arguments.RemoveAt (0);
3797 var me = ExtensionExpression as MemberExpr;
3799 me.ResolveInstanceExpression (ec, null);
3800 var fe = me as FieldExpr;
3802 fe.Spec.MemberDefinition.SetIsUsed ();
3805 InstanceExpression = null;
3809 #region IErrorHandler Members
3811 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3816 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3818 rc.Report.SymbolRelatedToPreviousError (best);
3819 rc.Report.Error (1928, loc,
3820 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3821 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3824 rc.Report.Error (1929, loc,
3825 "Extension method instance type `{0}' cannot be converted to `{1}'",
3826 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3832 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3837 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3846 /// MethodGroupExpr represents a group of method candidates which
3847 /// can be resolved to the best method overload
3849 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3851 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3853 protected IList<MemberSpec> Methods;
3854 MethodSpec best_candidate;
3855 TypeSpec best_candidate_return;
3856 protected TypeArguments type_arguments;
3858 SimpleName simple_name;
3859 protected TypeSpec queried_type;
3861 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3865 this.type = InternalType.MethodGroup;
3867 eclass = ExprClass.MethodGroup;
3868 queried_type = type;
3871 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3872 : this (new MemberSpec[] { m }, type, loc)
3878 public MethodSpec BestCandidate {
3880 return best_candidate;
3884 public TypeSpec BestCandidateReturnType {
3886 return best_candidate_return;
3890 public IList<MemberSpec> Candidates {
3896 protected override TypeSpec DeclaringType {
3898 return queried_type;
3902 public bool IsConditionallyExcluded {
3904 return Methods == Excluded;
3908 public override bool IsInstance {
3910 if (best_candidate != null)
3911 return !best_candidate.IsStatic;
3917 public override bool IsSideEffectFree {
3919 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3923 public override bool IsStatic {
3925 if (best_candidate != null)
3926 return best_candidate.IsStatic;
3932 public override string KindName {
3933 get { return "method"; }
3936 public override string Name {
3938 if (best_candidate != null)
3939 return best_candidate.Name;
3942 return Methods.First ().Name;
3949 // When best candidate is already know this factory can be used
3950 // to avoid expensive overload resolution to be called
3952 // NOTE: InstanceExpression has to be set manually
3954 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3956 return new MethodGroupExpr (best, queriedType, loc) {
3957 best_candidate = best,
3958 best_candidate_return = best.ReturnType
3962 public override string GetSignatureForError ()
3964 if (best_candidate != null)
3965 return best_candidate.GetSignatureForError ();
3967 return Methods.First ().GetSignatureForError ();
3970 public override Expression CreateExpressionTree (ResolveContext ec)
3972 if (best_candidate == null) {
3973 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3977 if (IsConditionallyExcluded)
3978 ec.Report.Error (765, loc,
3979 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3981 if (ConditionalAccess)
3982 Error_NullShortCircuitInsideExpressionTree (ec);
3984 return new TypeOfMethod (best_candidate, loc);
3987 protected override Expression DoResolve (ResolveContext ec)
3989 this.eclass = ExprClass.MethodGroup;
3991 if (InstanceExpression != null) {
3992 InstanceExpression = InstanceExpression.Resolve (ec);
3993 if (InstanceExpression == null)
4000 public override void Emit (EmitContext ec)
4002 throw new NotSupportedException ();
4005 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
4007 var call = new CallEmitter ();
4008 call.InstanceExpression = InstanceExpression;
4009 call.ConditionalAccess = ConditionalAccess;
4012 call.EmitStatement (ec, best_candidate, arguments, loc);
4014 call.Emit (ec, best_candidate, arguments, loc);
4017 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
4019 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
4020 Statement = statement
4023 EmitCall (ec, arguments, statement);
4025 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
4028 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
4030 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
4031 Name, target.GetSignatureForError ());
4034 public bool HasAccessibleCandidate (ResolveContext rc)
4036 foreach (var candidate in Candidates) {
4037 if (candidate.IsAccessible (rc))
4044 public static bool IsExtensionMethodArgument (Expression expr)
4047 // LAMESPEC: No details about which expressions are not allowed
4049 return !(expr is TypeExpr) && !(expr is BaseThis);
4053 /// Find the Applicable Function Members (7.4.2.1)
4055 /// me: Method Group expression with the members to select.
4056 /// it might contain constructors or methods (or anything
4057 /// that maps to a method).
4059 /// Arguments: ArrayList containing resolved Argument objects.
4061 /// loc: The location if we want an error to be reported, or a Null
4062 /// location for "probing" purposes.
4064 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4065 /// that is the best match of me on Arguments.
4068 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4070 // TODO: causes issues with probing mode, remove explicit Kind check
4071 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4074 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4075 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4076 r.BaseMembersProvider = this;
4077 r.InstanceQualifier = this;
4080 if (cerrors != null)
4081 r.CustomErrors = cerrors;
4083 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4084 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4085 if (best_candidate == null) {
4086 if (!r.BestCandidateIsDynamic)
4089 if (simple_name != null && ec.IsStatic)
4090 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4095 // Overload resolver had to create a new method group, all checks bellow have already been executed
4096 if (r.BestCandidateNewMethodGroup != null)
4097 return r.BestCandidateNewMethodGroup;
4099 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4100 if (InstanceExpression != null) {
4101 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4102 InstanceExpression = null;
4104 if (simple_name != null && best_candidate.IsStatic) {
4105 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4108 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4112 ResolveInstanceExpression (ec, null);
4115 var base_override = CandidateToBaseOverride (ec, best_candidate);
4116 if (base_override == best_candidate) {
4117 best_candidate_return = r.BestCandidateReturnType;
4119 best_candidate = base_override;
4120 best_candidate_return = best_candidate.ReturnType;
4123 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4124 ConstraintChecker cc = new ConstraintChecker (ec);
4125 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4129 // Additional check for possible imported base override method which
4130 // could not be done during IsOverrideMethodBaseTypeAccessible
4132 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4133 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4134 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4135 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4138 // Speed up the check by not doing it on disallowed targets
4139 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4145 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4147 var fe = left as FieldExpr;
4150 // Using method-group on struct fields makes the struct assigned. I am not sure
4151 // why but that's what .net does
4153 fe.Spec.MemberDefinition.SetIsAssigned ();
4156 simple_name = original;
4157 return base.ResolveMemberAccess (ec, left, original);
4160 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4162 type_arguments = ta;
4165 #region IBaseMembersProvider Members
4167 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4169 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4172 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4174 if (queried_type == member.DeclaringType)
4177 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4178 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4182 // Extension methods lookup after ordinary methods candidates failed to apply
4184 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4186 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4189 if (!IsExtensionMethodArgument (InstanceExpression))
4192 int arity = type_arguments == null ? 0 : type_arguments.Count;
4193 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4194 if (methods == null)
4197 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4198 emg.SetTypeArguments (rc, type_arguments);
4205 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4207 public ConstructorInstanceQualifier (TypeSpec type)
4210 InstanceType = type;
4213 public TypeSpec InstanceType { get; private set; }
4215 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4217 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4221 public struct OverloadResolver
4224 public enum Restrictions
4228 ProbingOnly = 1 << 1,
4229 CovariantDelegate = 1 << 2,
4230 NoBaseMembers = 1 << 3,
4231 BaseMembersIncluded = 1 << 4,
4232 GetEnumeratorLookup = 1 << 5
4235 public interface IBaseMembersProvider
4237 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4238 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4239 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4242 public interface IErrorHandler
4244 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4245 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4246 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4247 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4250 public interface IInstanceQualifier
4252 TypeSpec InstanceType { get; }
4253 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4256 sealed class NoBaseMembers : IBaseMembersProvider
4258 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4260 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4265 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4270 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4276 struct AmbiguousCandidate
4278 public readonly MemberSpec Member;
4279 public readonly bool Expanded;
4280 public readonly AParametersCollection Parameters;
4282 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4285 Parameters = parameters;
4286 Expanded = expanded;
4291 IList<MemberSpec> members;
4292 TypeArguments type_arguments;
4293 IBaseMembersProvider base_provider;
4294 IErrorHandler custom_errors;
4295 IInstanceQualifier instance_qualifier;
4296 Restrictions restrictions;
4297 MethodGroupExpr best_candidate_extension_group;
4298 TypeSpec best_candidate_return_type;
4300 SessionReportPrinter lambda_conv_msgs;
4302 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4303 : this (members, null, restrictions, loc)
4307 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4310 if (members == null || members.Count == 0)
4311 throw new ArgumentException ("empty members set");
4313 this.members = members;
4315 type_arguments = targs;
4316 this.restrictions = restrictions;
4317 if (IsDelegateInvoke)
4318 this.restrictions |= Restrictions.NoBaseMembers;
4320 base_provider = NoBaseMembers.Instance;
4325 public IBaseMembersProvider BaseMembersProvider {
4327 return base_provider;
4330 base_provider = value;
4334 public bool BestCandidateIsDynamic { get; set; }
4337 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4339 public MethodGroupExpr BestCandidateNewMethodGroup {
4341 return best_candidate_extension_group;
4346 // Return type can be different between best candidate and closest override
4348 public TypeSpec BestCandidateReturnType {
4350 return best_candidate_return_type;
4354 public IErrorHandler CustomErrors {
4356 return custom_errors;
4359 custom_errors = value;
4363 TypeSpec DelegateType {
4365 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4366 throw new InternalErrorException ("Not running in delegate mode", loc);
4368 return members [0].DeclaringType;
4372 public IInstanceQualifier InstanceQualifier {
4374 return instance_qualifier;
4377 instance_qualifier = value;
4381 bool IsProbingOnly {
4383 return (restrictions & Restrictions.ProbingOnly) != 0;
4387 bool IsDelegateInvoke {
4389 return (restrictions & Restrictions.DelegateInvoke) != 0;
4396 // 7.4.3.3 Better conversion from expression
4397 // Returns : 1 if a->p is better,
4398 // 2 if a->q is better,
4399 // 0 if neither is better
4401 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4403 TypeSpec argument_type = a.Type;
4406 // If argument is an anonymous function
4408 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4410 // p and q are delegate types or expression tree types
4412 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4413 if (q.MemberDefinition != p.MemberDefinition) {
4418 // Uwrap delegate from Expression<T>
4420 q = TypeManager.GetTypeArguments (q)[0];
4421 p = TypeManager.GetTypeArguments (p)[0];
4424 var p_m = Delegate.GetInvokeMethod (p);
4425 var q_m = Delegate.GetInvokeMethod (q);
4428 // With identical parameter lists
4430 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4438 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4440 if (p.Kind == MemberKind.Void) {
4441 return q.Kind != MemberKind.Void ? 2 : 0;
4445 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4447 if (q.Kind == MemberKind.Void) {
4448 return p.Kind != MemberKind.Void ? 1: 0;
4451 var am = (AnonymousMethodExpression) a.Expr;
4454 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4455 // better conversion is performed between underlying types Y1 and Y2
4457 if (p.IsGenericTask || q.IsGenericTask) {
4458 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4459 q = q.TypeArguments[0];
4460 p = p.TypeArguments[0];
4466 // An inferred return type X exists for E in the context of that parameter list, and
4467 // the conversion from X to Y1 is better than the conversion from X to Y2
4469 argument_type = am.InferReturnType (ec, null, orig_q);
4470 if (argument_type == null) {
4471 // TODO: Can this be hit?
4475 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4476 argument_type = ec.BuiltinTypes.Object;
4480 if (argument_type == p)
4483 if (argument_type == q)
4487 // The parameters are identicial and return type is not void, use better type conversion
4488 // on return type to determine better one
4490 return BetterTypeConversion (ec, p, q);
4494 // 7.4.3.4 Better conversion from type
4496 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4498 if (p == null || q == null)
4499 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4501 switch (p.BuiltinType) {
4502 case BuiltinTypeSpec.Type.Int:
4503 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4506 case BuiltinTypeSpec.Type.Long:
4507 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4510 case BuiltinTypeSpec.Type.SByte:
4511 switch (q.BuiltinType) {
4512 case BuiltinTypeSpec.Type.Byte:
4513 case BuiltinTypeSpec.Type.UShort:
4514 case BuiltinTypeSpec.Type.UInt:
4515 case BuiltinTypeSpec.Type.ULong:
4519 case BuiltinTypeSpec.Type.Short:
4520 switch (q.BuiltinType) {
4521 case BuiltinTypeSpec.Type.UShort:
4522 case BuiltinTypeSpec.Type.UInt:
4523 case BuiltinTypeSpec.Type.ULong:
4527 case BuiltinTypeSpec.Type.Dynamic:
4528 // Dynamic is never better
4532 switch (q.BuiltinType) {
4533 case BuiltinTypeSpec.Type.Int:
4534 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4537 case BuiltinTypeSpec.Type.Long:
4538 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4541 case BuiltinTypeSpec.Type.SByte:
4542 switch (p.BuiltinType) {
4543 case BuiltinTypeSpec.Type.Byte:
4544 case BuiltinTypeSpec.Type.UShort:
4545 case BuiltinTypeSpec.Type.UInt:
4546 case BuiltinTypeSpec.Type.ULong:
4550 case BuiltinTypeSpec.Type.Short:
4551 switch (p.BuiltinType) {
4552 case BuiltinTypeSpec.Type.UShort:
4553 case BuiltinTypeSpec.Type.UInt:
4554 case BuiltinTypeSpec.Type.ULong:
4558 case BuiltinTypeSpec.Type.Dynamic:
4559 // Dynamic is never better
4563 // FIXME: handle lifted operators
4565 // TODO: this is expensive
4566 Expression p_tmp = new EmptyExpression (p);
4567 Expression q_tmp = new EmptyExpression (q);
4569 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4570 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4572 if (p_to_q && !q_to_p)
4575 if (q_to_p && !p_to_q)
4582 /// Determines "Better function" between candidate
4583 /// and the current best match
4586 /// Returns a boolean indicating :
4587 /// false if candidate ain't better
4588 /// true if candidate is better than the current best match
4590 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4591 MemberSpec best, AParametersCollection bparam, bool best_params)
4593 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4594 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4596 bool better_at_least_one = false;
4597 bool are_equivalent = true;
4598 int args_count = args == null ? 0 : args.Count;
4602 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4605 // Default arguments are ignored for better decision
4606 if (a.IsDefaultArgument)
4610 // When comparing named argument the parameter type index has to be looked up
4611 // in original parameter set (override version for virtual members)
4613 NamedArgument na = a as NamedArgument;
4615 int idx = cparam.GetParameterIndexByName (na.Name);
4616 ct = candidate_pd.Types[idx];
4617 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4618 ct = TypeManager.GetElementType (ct);
4620 idx = bparam.GetParameterIndexByName (na.Name);
4621 bt = best_pd.Types[idx];
4622 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4623 bt = TypeManager.GetElementType (bt);
4625 ct = candidate_pd.Types[c_idx];
4626 bt = best_pd.Types[b_idx];
4628 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4629 ct = TypeManager.GetElementType (ct);
4633 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4634 bt = TypeManager.GetElementType (bt);
4639 if (TypeSpecComparer.IsEqual (ct, bt))
4642 are_equivalent = false;
4643 int result = BetterExpressionConversion (ec, a, ct, bt);
4645 // for each argument, the conversion to 'ct' should be no worse than
4646 // the conversion to 'bt'.
4650 // for at least one argument, the conversion to 'ct' should be better than
4651 // the conversion to 'bt'.
4653 better_at_least_one = true;
4656 if (better_at_least_one)
4660 // Tie-breaking rules are applied only for equivalent parameter types
4662 if (!are_equivalent) {
4664 // LAMESPEC: A candidate with less default parameters is still better when there
4665 // is no better expression conversion
4667 if (candidate_pd.Count < best_pd.Count && !candidate_params && best_pd.FixedParameters [j].HasDefaultValue) {
4675 // If candidate is applicable in its normal form and best has a params array and is applicable
4676 // only in its expanded form, then candidate is better
4678 if (candidate_params != best_params)
4679 return !candidate_params;
4682 // We have not reached end of parameters list due to params or used default parameters
4684 while (j < candidate_pd.Count && j < best_pd.Count) {
4685 var cand_param = candidate_pd.FixedParameters [j];
4686 var best_param = best_pd.FixedParameters [j];
4688 if (candidate_pd.Count == best_pd.Count) {
4692 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4693 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4695 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4696 return cand_param.HasDefaultValue;
4698 if (cand_param.HasDefaultValue) {
4704 // Neither is better when not all arguments are provided
4706 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4707 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4708 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4710 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4717 if (candidate_pd.Count != best_pd.Count)
4718 return candidate_pd.Count < best_pd.Count;
4721 // One is a non-generic method and second is a generic method, then non-generic is better
4723 if (best.IsGeneric != candidate.IsGeneric)
4724 return best.IsGeneric;
4727 // Both methods have the same number of parameters, and the parameters have equal types
4728 // Pick the "more specific" signature using rules over original (non-inflated) types
4730 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4731 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4733 bool specific_at_least_once = false;
4734 for (j = 0; j < args_count; ++j) {
4735 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4737 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4738 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4740 ct = candidate_def_pd.Types[j];
4741 bt = best_def_pd.Types[j];
4746 TypeSpec specific = MoreSpecific (ct, bt);
4750 specific_at_least_once = true;
4753 if (specific_at_least_once)
4759 static bool CheckInflatedArguments (MethodSpec ms)
4761 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4764 // Setup constraint checker for probing only
4765 ConstraintChecker cc = new ConstraintChecker (null);
4767 var mp = ms.Parameters.Types;
4768 for (int i = 0; i < mp.Length; ++i) {
4769 var type = mp[i] as InflatedTypeSpec;
4773 var targs = type.TypeArguments;
4774 if (targs.Length == 0)
4777 // TODO: Checking inflated MVAR arguments should be enough
4778 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4785 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4787 rc.Report.Error (1729, loc,
4788 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4789 type.GetSignatureForError (), argCount.ToString ());
4793 // Determines if the candidate method is applicable to the given set of arguments
4794 // There could be two different set of parameters for same candidate where one
4795 // is the closest override for default values and named arguments checks and second
4796 // one being the virtual base for the parameter types and modifiers.
4798 // A return value rates candidate method compatibility,
4800 // 0 = the best, int.MaxValue = the worst
4802 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)
4805 // Each step has allocated 10 values, it can overflow for
4806 // more than 10 arguments but that's ok as it's used for
4807 // better error reporting only
4809 const int ArgumentCountMismatch = 1000000000;
4810 const int NamedArgumentsMismatch = 100000000;
4811 const int DefaultArgumentMismatch = 10000000;
4812 const int UnexpectedTypeArguments = 1000000;
4813 const int TypeArgumentsMismatch = 100000;
4814 const int InflatedTypesMismatch = 10000;
4816 // Parameters of most-derived type used mainly for named and optional parameters
4817 var pd = pm.Parameters;
4819 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4820 // params modifier instead of most-derived type
4821 var cpd = ((IParametersMember) candidate).Parameters;
4822 int param_count = pd.Count;
4823 int optional_count = 0;
4825 Arguments orig_args = arguments;
4827 if (arg_count != param_count) {
4829 // No arguments expansion when doing exact match for delegates
4831 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4832 for (int i = 0; i < pd.Count; ++i) {
4833 if (pd.FixedParameters[i].HasDefaultValue) {
4834 optional_count = pd.Count - i;
4840 if (optional_count != 0) {
4841 // Readjust expected number when params used
4842 if (cpd.HasParams) {
4844 if (arg_count < param_count)
4846 } else if (arg_count > param_count) {
4847 int args_gap = System.Math.Abs (arg_count - param_count);
4848 return ArgumentCountMismatch + args_gap;
4849 } else if (arg_count < param_count - optional_count) {
4850 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4851 return ArgumentCountMismatch + args_gap;
4853 } else if (arg_count != param_count) {
4854 int args_gap = System.Math.Abs (arg_count - param_count);
4856 return ArgumentCountMismatch + args_gap;
4857 if (arg_count < param_count - 1)
4858 return ArgumentCountMismatch + args_gap;
4861 // Resize to fit optional arguments
4862 if (optional_count != 0) {
4863 if (arguments == null) {
4864 arguments = new Arguments (optional_count);
4866 // Have to create a new container, so the next run can do same
4867 var resized = new Arguments (param_count);
4868 resized.AddRange (arguments);
4869 arguments = resized;
4872 for (int i = arg_count; i < param_count; ++i)
4873 arguments.Add (null);
4877 if (arg_count > 0) {
4879 // Shuffle named arguments to the right positions if there are any
4881 if (arguments[arg_count - 1] is NamedArgument) {
4882 arg_count = arguments.Count;
4884 for (int i = 0; i < arg_count; ++i) {
4885 bool arg_moved = false;
4887 NamedArgument na = arguments[i] as NamedArgument;
4891 int index = pd.GetParameterIndexByName (na.Name);
4893 // Named parameter not found
4895 return NamedArgumentsMismatch - i;
4897 // already reordered
4902 if (index >= param_count) {
4903 // When using parameters which should not be available to the user
4904 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4907 arguments.Add (null);
4911 if (index == arg_count)
4912 return NamedArgumentsMismatch - i - 1;
4914 temp = arguments [index];
4916 // The slot has been taken by positional argument
4917 if (temp != null && !(temp is NamedArgument))
4922 arguments = arguments.MarkOrderedArgument (na);
4926 if (arguments == orig_args) {
4927 arguments = new Arguments (orig_args.Count);
4928 arguments.AddRange (orig_args);
4931 arguments[index] = arguments[i];
4932 arguments[i] = temp;
4939 arg_count = arguments.Count;
4941 } else if (arguments != null) {
4942 arg_count = arguments.Count;
4946 // Don't do any expensive checks when the candidate cannot succeed
4948 if (arg_count != param_count && !cpd.HasParams)
4949 return DefaultArgumentMismatch - System.Math.Abs (param_count - arg_count);
4951 var dep = candidate.GetMissingDependencies ();
4953 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4958 // 1. Handle generic method using type arguments when specified or type inference
4961 var ms = candidate as MethodSpec;
4962 if (ms != null && ms.IsGeneric) {
4963 if (type_arguments != null) {
4964 var g_args_count = ms.Arity;
4965 if (g_args_count != type_arguments.Count)
4966 return TypeArgumentsMismatch - System.Math.Abs (type_arguments.Count - g_args_count);
4968 if (type_arguments.Arguments != null)
4969 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4972 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4973 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4974 // candidate was found use the set to report more details about what was wrong with lambda body.
4975 // The general idea is to distinguish between code errors and errors caused by
4976 // trial-and-error type inference
4978 if (lambda_conv_msgs == null) {
4979 for (int i = 0; i < arg_count; i++) {
4980 Argument a = arguments[i];
4984 var am = a.Expr as AnonymousMethodExpression;
4986 if (lambda_conv_msgs == null)
4987 lambda_conv_msgs = new SessionReportPrinter ();
4989 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4994 var ti = new TypeInference (arguments);
4995 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4998 return TypeArgumentsMismatch - ti.InferenceScore;
5001 // Clear any error messages when the result was success
5003 if (lambda_conv_msgs != null)
5004 lambda_conv_msgs.ClearSession ();
5006 if (i_args.Length != 0) {
5008 for (int i = 0; i < i_args.Length; ++i) {
5009 var ta = i_args [i];
5010 if (!ta.IsAccessible (ec))
5011 return TypeArgumentsMismatch - i;
5015 ms = ms.MakeGenericMethod (ec, i_args);
5020 // Type arguments constraints have to match for the method to be applicable
5022 if (!CheckInflatedArguments (ms)) {
5024 return InflatedTypesMismatch;
5028 // We have a generic return type and at same time the method is override which
5029 // means we have to also inflate override return type in case the candidate is
5030 // best candidate and override return type is different to base return type.
5032 // virtual Foo<T, object> with override Foo<T, dynamic>
5034 if (candidate != pm) {
5035 MethodSpec override_ms = (MethodSpec) pm;
5036 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
5037 returnType = inflator.Inflate (returnType);
5039 returnType = ms.ReturnType;
5046 if (type_arguments != null)
5047 return UnexpectedTypeArguments;
5053 // 2. Each argument has to be implicitly convertible to method parameter
5055 Parameter.Modifier p_mod = 0;
5058 for (int i = 0; i < arg_count; i++) {
5059 Argument a = arguments[i];
5061 var fp = pd.FixedParameters[i];
5062 if (!fp.HasDefaultValue) {
5063 arguments = orig_args;
5064 return arg_count * 2 + 2;
5068 // Get the default value expression, we can use the same expression
5069 // if the type matches
5071 Expression e = fp.DefaultValue;
5073 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
5075 // Restore for possible error reporting
5076 for (int ii = i; ii < arg_count; ++ii)
5077 arguments.RemoveAt (i);
5079 return (arg_count - i) * 2 + 1;
5083 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
5085 // LAMESPEC: Attributes can be mixed together with build-in priority
5087 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
5088 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
5089 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5090 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5091 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5092 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5096 arguments[i] = new Argument (e, Argument.AType.Default);
5100 if (p_mod != Parameter.Modifier.PARAMS) {
5101 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5103 } else if (!params_expanded_form) {
5104 params_expanded_form = true;
5105 pt = ((ElementTypeSpec) pt).Element;
5111 if (!params_expanded_form) {
5112 if (a.IsExtensionType) {
5113 if (ExtensionMethodGroupExpr.IsExtensionTypeCompatible (a.Type, pt)) {
5118 score = IsArgumentCompatible (ec, a, p_mod, pt);
5121 dynamicArgument = true;
5126 // It can be applicable in expanded form (when not doing exact match like for delegates)
5128 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5129 if (!params_expanded_form) {
5130 pt = ((ElementTypeSpec) pt).Element;
5134 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5137 params_expanded_form = true;
5138 dynamicArgument = true;
5139 } else if (score == 0 || arg_count > pd.Count) {
5140 params_expanded_form = true;
5145 if (params_expanded_form)
5147 return (arg_count - i) * 2 + score;
5152 // Restore original arguments for dynamic binder to keep the intention of original source code
5154 if (dynamicArgument)
5155 arguments = orig_args;
5160 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5162 if (e is Constant && e.Type == ptype)
5166 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5168 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5169 e = new MemberAccess (new MemberAccess (new MemberAccess (
5170 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5171 } else if (e is Constant) {
5173 // Handles int to int? conversions, DefaultParameterValue check
5175 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5179 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5182 return e.Resolve (ec);
5186 // Tests argument compatibility with the parameter
5187 // The possible return values are
5189 // 1 - modifier mismatch
5190 // 2 - type mismatch
5191 // -1 - dynamic binding required
5193 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5196 // Types have to be identical when ref or out modifer
5197 // is used and argument is not of dynamic type
5199 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5200 var arg_type = argument.Type;
5202 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5204 // Using dynamic for ref/out parameter can still succeed at runtime
5206 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5212 if (arg_type != parameter) {
5213 if (arg_type == InternalType.VarOutType)
5217 // Do full equality check after quick path
5219 if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
5221 // Using dynamic for ref/out parameter can still succeed at runtime
5223 if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5231 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5235 // Use implicit conversion in all modes to return same candidates when the expression
5236 // is used as argument or delegate conversion
5238 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5239 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5246 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5248 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5250 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5253 var ac_p = p as ArrayContainer;
5255 var ac_q = q as ArrayContainer;
5259 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5260 if (specific == ac_p.Element)
5262 if (specific == ac_q.Element)
5264 } else if (p.IsGeneric && q.IsGeneric) {
5265 var pargs = TypeManager.GetTypeArguments (p);
5266 var qargs = TypeManager.GetTypeArguments (q);
5268 bool p_specific_at_least_once = false;
5269 bool q_specific_at_least_once = false;
5271 for (int i = 0; i < pargs.Length; i++) {
5272 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5273 if (specific == pargs[i])
5274 p_specific_at_least_once = true;
5275 if (specific == qargs[i])
5276 q_specific_at_least_once = true;
5279 if (p_specific_at_least_once && !q_specific_at_least_once)
5281 if (!p_specific_at_least_once && q_specific_at_least_once)
5289 // Find the best method from candidate list
5291 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5293 List<AmbiguousCandidate> ambiguous_candidates = null;
5295 MemberSpec best_candidate;
5296 Arguments best_candidate_args = null;
5297 bool best_candidate_params = false;
5298 bool best_candidate_dynamic = false;
5299 int best_candidate_rate;
5300 IParametersMember best_parameter_member = null;
5302 int args_count = args != null ? args.Count : 0;
5304 Arguments candidate_args = args;
5305 bool error_mode = false;
5306 MemberSpec invocable_member = null;
5309 best_candidate = null;
5310 best_candidate_rate = int.MaxValue;
5312 var type_members = members;
5314 for (int i = 0; i < type_members.Count; ++i) {
5315 var member = type_members[i];
5318 // Methods in a base class are not candidates if any method in a derived
5319 // class is applicable
5321 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5325 if (!member.IsAccessible (rc))
5328 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5331 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5332 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5337 IParametersMember pm = member as IParametersMember;
5340 // Will use it later to report ambiguity between best method and invocable member
5342 if (Invocation.IsMemberInvocable (member))
5343 invocable_member = member;
5349 // Overload resolution is looking for base member but using parameter names
5350 // and default values from the closest member. That means to do expensive lookup
5351 // for the closest override for virtual or abstract members
5353 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5354 var override_params = base_provider.GetOverrideMemberParameters (member);
5355 if (override_params != null)
5356 pm = override_params;
5360 // Check if the member candidate is applicable
5362 bool params_expanded_form = false;
5363 bool dynamic_argument = false;
5364 TypeSpec rt = pm.MemberType;
5365 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5367 if (lambda_conv_msgs != null)
5368 lambda_conv_msgs.EndSession ();
5371 // How does it score compare to others
5373 if (candidate_rate < best_candidate_rate) {
5375 // Fatal error (missing dependency), cannot continue
5376 if (candidate_rate < 0)
5379 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5380 // Only parameterless methods are considered
5382 best_candidate_rate = candidate_rate;
5383 best_candidate = member;
5384 best_candidate_args = candidate_args;
5385 best_candidate_params = params_expanded_form;
5386 best_candidate_dynamic = dynamic_argument;
5387 best_parameter_member = pm;
5388 best_candidate_return_type = rt;
5390 } else if (candidate_rate == 0) {
5392 // The member look is done per type for most operations but sometimes
5393 // it's not possible like for binary operators overload because they
5394 // are unioned between 2 sides
5396 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5397 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5402 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5404 // We pack all interface members into top level type which makes the overload resolution
5405 // more complicated for interfaces. We compensate it by removing methods with same
5406 // signature when building the cache hence this path should not really be hit often
5409 // interface IA { void Foo (int arg); }
5410 // interface IB : IA { void Foo (params int[] args); }
5412 // IB::Foo is the best overload when calling IB.Foo (1)
5415 if (ambiguous_candidates != null) {
5416 foreach (var amb_cand in ambiguous_candidates) {
5417 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5426 ambiguous_candidates = null;
5429 // Is the new candidate better
5430 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5434 best_candidate = member;
5435 best_candidate_args = candidate_args;
5436 best_candidate_params = params_expanded_form;
5437 best_candidate_dynamic = dynamic_argument;
5438 best_parameter_member = pm;
5439 best_candidate_return_type = rt;
5441 // It's not better but any other found later could be but we are not sure yet
5442 if (ambiguous_candidates == null)
5443 ambiguous_candidates = new List<AmbiguousCandidate> ();
5445 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5449 // Restore expanded arguments
5450 candidate_args = args;
5452 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5455 // We've found exact match
5457 if (best_candidate_rate == 0)
5461 // Try extension methods lookup when no ordinary method match was found and provider enables it
5464 var emg = base_provider.LookupExtensionMethod (rc);
5466 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5468 best_candidate_extension_group = emg;
5469 return (T) (MemberSpec) emg.BestCandidate;
5474 // Don't run expensive error reporting mode for probing
5481 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5484 lambda_conv_msgs = null;
5489 // No best member match found, report an error
5491 if (best_candidate_rate != 0 || error_mode) {
5492 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5496 if (best_candidate_dynamic) {
5497 if (args[0].IsExtensionType) {
5498 rc.Report.Error (1973, loc,
5499 "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",
5500 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5504 // Check type constraints only when explicit type arguments are used
5506 if (best_candidate.IsGeneric && type_arguments != null) {
5507 MethodSpec bc = best_candidate as MethodSpec;
5508 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5509 ConstraintChecker cc = new ConstraintChecker (rc);
5510 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5514 BestCandidateIsDynamic = true;
5519 // These flags indicates we are running delegate probing conversion. No need to
5520 // do more expensive checks
5522 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5523 return (T) best_candidate;
5525 if (ambiguous_candidates != null) {
5527 // Now check that there are no ambiguities i.e the selected method
5528 // should be better than all the others
5530 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5531 var candidate = ambiguous_candidates [ix];
5533 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5534 var ambiguous = candidate.Member;
5535 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5536 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5537 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5538 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5539 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5542 return (T) best_candidate;
5547 if (invocable_member != null && !IsProbingOnly) {
5548 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5549 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5550 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5551 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5555 // And now check if the arguments are all
5556 // compatible, perform conversions if
5557 // necessary etc. and return if everything is
5560 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5563 if (best_candidate == null)
5567 // Don't run possibly expensive checks in probing mode
5569 if (!IsProbingOnly && !rc.IsInProbingMode) {
5571 // Check ObsoleteAttribute on the best method
5573 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5574 if (oa != null && !rc.IsObsolete)
5575 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5577 best_candidate.MemberDefinition.SetIsUsed ();
5580 args = best_candidate_args;
5581 return (T) best_candidate;
5584 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5586 return ResolveMember<MethodSpec> (rc, ref args);
5589 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5590 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5592 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5595 if (a.Type == InternalType.ErrorType)
5598 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5599 ec.Report.SymbolRelatedToPreviousError (method);
5600 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5601 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5602 TypeManager.CSharpSignature (method));
5605 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5606 TypeManager.CSharpSignature (method));
5607 } else if (IsDelegateInvoke) {
5608 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5609 DelegateType.GetSignatureForError ());
5611 ec.Report.SymbolRelatedToPreviousError (method);
5612 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5613 method.GetSignatureForError ());
5616 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5618 string index = (idx + 1).ToString ();
5619 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5620 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5621 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5622 index, Parameter.GetModifierSignature (a.Modifier));
5624 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5625 index, Parameter.GetModifierSignature (mod));
5627 string p1 = a.GetSignatureForError ();
5628 string p2 = paramType.GetSignatureForError ();
5631 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5632 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5635 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5636 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5637 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5640 ec.Report.Error (1503, a.Expr.Location,
5641 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5646 // We have failed to find exact match so we return error info about the closest match
5648 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5650 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5651 int arg_count = args == null ? 0 : args.Count;
5653 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5654 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5655 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5659 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5664 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5665 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5666 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5670 // For candidates which match on parameters count report more details about incorrect arguments
5673 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5674 // Reject any inaccessible member
5675 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5676 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5677 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5681 var ms = best_candidate as MethodSpec;
5682 if (ms != null && ms.IsGeneric) {
5683 bool constr_ok = true;
5684 if (ms.TypeArguments != null)
5685 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5687 if (ta_count == 0 && ms.TypeArguments == null) {
5688 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5692 rc.Report.Error (411, loc,
5693 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5694 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5701 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5707 // We failed to find any method with correct argument count, report best candidate
5709 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5712 if (best_candidate.Kind == MemberKind.Constructor) {
5713 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5714 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5715 } else if (IsDelegateInvoke) {
5716 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5717 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5718 DelegateType.GetSignatureForError (), arg_count.ToString ());
5720 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5721 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5722 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5723 name, arg_count.ToString ());
5727 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5729 var p = ((IParametersMember)best_candidate).Parameters;
5734 for (int i = p.Count - 1; i != 0; --i) {
5735 var fp = p.FixedParameters [i];
5736 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5746 foreach (var arg in args) {
5747 var na = arg as NamedArgument;
5751 if (na.Name == name) {
5760 return args.Count + 1 == pm.Parameters.Count;
5763 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5765 var pd = pm.Parameters;
5766 var cpd = ((IParametersMember) member).Parameters;
5767 var ptypes = cpd.Types;
5769 Parameter.Modifier p_mod = 0;
5771 int a_idx = 0, a_pos = 0;
5773 ArrayInitializer params_initializers = null;
5774 bool has_unsafe_arg = pm.MemberType.IsPointer;
5775 int arg_count = args == null ? 0 : args.Count;
5777 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5782 if (p_mod != Parameter.Modifier.PARAMS) {
5783 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5785 has_unsafe_arg |= pt.IsPointer;
5787 if (p_mod == Parameter.Modifier.PARAMS) {
5788 if (chose_params_expanded) {
5789 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5790 pt = TypeManager.GetElementType (pt);
5796 // Types have to be identical when ref or out modifer is used
5798 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5799 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5802 var arg_type = a.Type;
5806 if (arg_type == InternalType.VarOutType) {
5808 // Set underlying variable type based on parameter type
5810 ((DeclarationExpression)a.Expr).Variable.Type = pt;
5814 if (!TypeSpecComparer.IsEqual (arg_type, pt))
5818 NamedArgument na = a as NamedArgument;
5820 int name_index = pd.GetParameterIndexByName (na.Name);
5821 if (name_index < 0 || name_index >= pd.Count) {
5822 if (IsDelegateInvoke) {
5823 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5824 ec.Report.Error (1746, na.Location,
5825 "The delegate `{0}' does not contain a parameter named `{1}'",
5826 DelegateType.GetSignatureForError (), na.Name);
5828 ec.Report.SymbolRelatedToPreviousError (member);
5829 ec.Report.Error (1739, na.Location,
5830 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5831 TypeManager.CSharpSignature (member), na.Name);
5833 } else if (args[name_index] != a && args[name_index] != null) {
5834 if (IsDelegateInvoke)
5835 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5837 ec.Report.SymbolRelatedToPreviousError (member);
5839 ec.Report.Error (1744, na.Location,
5840 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5845 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5848 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5849 custom_errors.NoArgumentMatch (ec, member);
5854 if (a.IsExtensionType) {
5855 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5858 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5860 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5863 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5870 // Convert params arguments to an array initializer
5872 if (params_initializers != null) {
5873 // we choose to use 'a.Expr' rather than 'conv' so that
5874 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5875 params_initializers.Add (a.Expr);
5876 args.RemoveAt (a_idx--);
5882 // Update the argument with the implicit conversion
5886 if (a_idx != arg_count) {
5888 // Convert all var out argument to error type for less confusing error reporting
5889 // when no matching overload is found
5891 for (; a_idx < arg_count; a_idx++) {
5892 var arg = args [a_idx];
5896 if (arg.Type == InternalType.VarOutType) {
5897 ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
5901 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5906 // Fill not provided arguments required by params modifier
5908 if (params_initializers == null && arg_count + 1 == pd.Count) {
5910 args = new Arguments (1);
5912 pt = ptypes[pd.Count - 1];
5913 pt = TypeManager.GetElementType (pt);
5914 has_unsafe_arg |= pt.IsPointer;
5915 params_initializers = new ArrayInitializer (0, loc);
5919 // Append an array argument with all params arguments
5921 if (params_initializers != null) {
5922 args.Add (new Argument (
5923 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5927 if (has_unsafe_arg && !ec.IsUnsafe) {
5928 Expression.UnsafeError (ec, loc);
5932 // We could infer inaccesible type arguments
5934 if (type_arguments == null && member.IsGeneric) {
5935 var ms = (MethodSpec) member;
5936 foreach (var ta in ms.TypeArguments) {
5937 if (!ta.IsAccessible (ec)) {
5938 ec.Report.SymbolRelatedToPreviousError (ta);
5939 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5949 public class ConstantExpr : MemberExpr
5951 readonly ConstSpec constant;
5953 public ConstantExpr (ConstSpec constant, Location loc)
5955 this.constant = constant;
5959 public override string Name {
5960 get { throw new NotImplementedException (); }
5963 public override string KindName {
5964 get { return "constant"; }
5967 public override bool IsInstance {
5968 get { return !IsStatic; }
5971 public override bool IsStatic {
5972 get { return true; }
5975 protected override TypeSpec DeclaringType {
5976 get { return constant.DeclaringType; }
5979 public override Expression CreateExpressionTree (ResolveContext ec)
5981 throw new NotSupportedException ("ET");
5984 protected override Expression DoResolve (ResolveContext rc)
5986 ResolveInstanceExpression (rc, null);
5987 DoBestMemberChecks (rc, constant);
5989 var c = constant.GetConstant (rc);
5991 // Creates reference expression to the constant value
5992 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5995 public override void Emit (EmitContext ec)
5997 throw new NotSupportedException ();
6000 public override string GetSignatureForError ()
6002 return constant.GetSignatureForError ();
6005 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6007 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
6012 // Fully resolved expression that references a Field
6014 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
6016 protected FieldSpec spec;
6017 VariableInfo variable_info;
6019 LocalTemporary temp;
6022 protected FieldExpr (Location l)
6027 public FieldExpr (FieldSpec spec, Location loc)
6032 type = spec.MemberType;
6035 public FieldExpr (FieldBase fi, Location l)
6042 public override string Name {
6048 public bool IsHoisted {
6050 IVariableReference hv = InstanceExpression as IVariableReference;
6051 return hv != null && hv.IsHoisted;
6055 public override bool IsInstance {
6057 return !spec.IsStatic;
6061 public override bool IsStatic {
6063 return spec.IsStatic;
6067 public override string KindName {
6068 get { return "field"; }
6071 public FieldSpec Spec {
6077 protected override TypeSpec DeclaringType {
6079 return spec.DeclaringType;
6083 public VariableInfo VariableInfo {
6085 return variable_info;
6091 public override string GetSignatureForError ()
6093 return spec.GetSignatureForError ();
6096 public bool IsMarshalByRefAccess (ResolveContext rc)
6098 // Checks possible ldflda of field access expression
6099 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
6100 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
6101 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
6104 public void SetHasAddressTaken ()
6106 IVariableReference vr = InstanceExpression as IVariableReference;
6108 vr.SetHasAddressTaken ();
6112 protected override void CloneTo (CloneContext clonectx, Expression target)
6114 var t = (FieldExpr) target;
6116 if (InstanceExpression != null)
6117 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6120 public override Expression CreateExpressionTree (ResolveContext ec)
6122 if (ConditionalAccess) {
6123 Error_NullShortCircuitInsideExpressionTree (ec);
6126 return CreateExpressionTree (ec, true);
6129 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6132 Expression instance;
6134 if (InstanceExpression == null) {
6135 instance = new NullLiteral (loc);
6136 } else if (convertInstance) {
6137 instance = InstanceExpression.CreateExpressionTree (ec);
6139 args = new Arguments (1);
6140 args.Add (new Argument (InstanceExpression));
6141 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6144 args = Arguments.CreateForExpressionTree (ec, null,
6146 CreateTypeOfExpression ());
6148 return CreateExpressionFactoryCall (ec, "Field", args);
6151 public Expression CreateTypeOfExpression ()
6153 return new TypeOfField (spec, loc);
6156 protected override Expression DoResolve (ResolveContext ec)
6158 spec.MemberDefinition.SetIsUsed ();
6160 return DoResolve (ec, null);
6163 Expression DoResolve (ResolveContext ec, Expression rhs)
6165 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6168 ResolveConditionalAccessReceiver (ec);
6170 if (ResolveInstanceExpression (ec, rhs)) {
6171 // Resolve the field's instance expression while flow analysis is turned
6172 // off: when accessing a field "a.b", we must check whether the field
6173 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6175 if (lvalue_instance) {
6176 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6178 Expression right_side =
6179 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6181 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6183 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6186 if (InstanceExpression == null)
6190 DoBestMemberChecks (ec, spec);
6192 if (conditional_access_receiver)
6193 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6196 var fb = spec as FixedFieldSpec;
6197 IVariableReference var = InstanceExpression as IVariableReference;
6200 IFixedExpression fe = InstanceExpression as IFixedExpression;
6201 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6202 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6205 if (InstanceExpression.eclass != ExprClass.Variable) {
6206 ec.Report.SymbolRelatedToPreviousError (spec);
6207 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6208 TypeManager.GetFullNameSignature (spec));
6209 } else if (var != null && var.IsHoisted) {
6210 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6213 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6217 // Set flow-analysis variable info for struct member access. It will be check later
6218 // for precise error reporting
6220 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6221 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6224 if (ConditionalAccess) {
6225 if (conditional_access_receiver)
6226 type = LiftMemberType (ec, type);
6228 if (InstanceExpression.IsNull)
6229 return Constant.CreateConstantFromValue (type, null, loc);
6232 eclass = ExprClass.Variable;
6236 public void SetFieldAssigned (FlowAnalysisContext fc)
6241 bool lvalue_instance = spec.DeclaringType.IsStruct;
6242 if (lvalue_instance) {
6243 var var = InstanceExpression as IVariableReference;
6244 if (var != null && var.VariableInfo != null) {
6245 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6249 var fe = InstanceExpression as FieldExpr;
6251 Expression instance;
6254 instance = fe.InstanceExpression;
6255 var fe_instance = instance as FieldExpr;
6256 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6257 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6258 var var = InstanceExpression as IVariableReference;
6259 if (var != null && var.VariableInfo == null) {
6260 var var_inst = instance as IVariableReference;
6261 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6262 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6266 if (fe_instance != null) {
6275 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6276 instance.FlowAnalysis (fc);
6278 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6279 InstanceExpression.FlowAnalysis (fc);
6283 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6285 // The return value is always null. Returning a value simplifies calling code.
6287 if (right_side == EmptyExpression.OutAccess) {
6289 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6290 GetSignatureForError ());
6292 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6293 GetSignatureForError ());
6299 if (right_side == EmptyExpression.LValueMemberAccess) {
6300 // Already reported as CS1648/CS1650
6304 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6306 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6307 GetSignatureForError ());
6309 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6310 GetSignatureForError ());
6316 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6317 GetSignatureForError ());
6319 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6320 GetSignatureForError ());
6326 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6328 if (ConditionalAccess)
6329 throw new NotSupportedException ("null propagating operator assignment");
6331 if (spec is FixedFieldSpec) {
6332 // It could be much better error message but we want to be error compatible
6333 Error_ValueAssignment (ec, right_side);
6336 Expression e = DoResolve (ec, right_side);
6341 spec.MemberDefinition.SetIsAssigned ();
6343 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6344 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6345 ec.Report.Warning (420, 1, loc,
6346 "`{0}': A volatile field references will not be treated as volatile",
6347 spec.GetSignatureForError ());
6350 if (spec.IsReadOnly) {
6351 // InitOnly fields can only be assigned in constructors or initializers
6352 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6353 return Error_AssignToReadonly (ec, right_side);
6355 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6357 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6358 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6359 return Error_AssignToReadonly (ec, right_side);
6360 // static InitOnly fields cannot be assigned-to in an instance constructor
6361 if (IsStatic && !ec.IsStatic)
6362 return Error_AssignToReadonly (ec, right_side);
6363 // instance constructors can't modify InitOnly fields of other instances of the same type
6364 if (!IsStatic && !(InstanceExpression is This))
6365 return Error_AssignToReadonly (ec, right_side);
6369 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6370 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6371 ec.Report.Warning (197, 1, loc,
6372 "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",
6373 GetSignatureForError ());
6376 eclass = ExprClass.Variable;
6380 public override void FlowAnalysis (FlowAnalysisContext fc)
6382 var var = InstanceExpression as IVariableReference;
6384 var vi = var.VariableInfo;
6385 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6386 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6390 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6394 base.FlowAnalysis (fc);
6396 if (conditional_access_receiver)
6397 fc.ConditionalAccessEnd ();
6400 public override int GetHashCode ()
6402 return spec.GetHashCode ();
6405 public bool IsFixed {
6408 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6410 IVariableReference variable = InstanceExpression as IVariableReference;
6411 if (variable != null)
6412 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6414 IFixedExpression fe = InstanceExpression as IFixedExpression;
6415 return fe != null && fe.IsFixed;
6419 public override bool Equals (object obj)
6421 FieldExpr fe = obj as FieldExpr;
6425 if (spec != fe.spec)
6428 if (InstanceExpression == null || fe.InstanceExpression == null)
6431 return InstanceExpression.Equals (fe.InstanceExpression);
6434 public void Emit (EmitContext ec, bool leave_copy)
6436 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6440 ec.Emit (OpCodes.Volatile);
6442 ec.Emit (OpCodes.Ldsfld, spec);
6445 if (conditional_access_receiver)
6446 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6448 EmitInstance (ec, false);
6451 // Optimization for build-in types
6452 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6453 ec.EmitLoadFromPtr (type);
6455 var ff = spec as FixedFieldSpec;
6457 ec.Emit (OpCodes.Ldflda, spec);
6458 ec.Emit (OpCodes.Ldflda, ff.Element);
6461 ec.Emit (OpCodes.Volatile);
6463 ec.Emit (OpCodes.Ldfld, spec);
6467 if (conditional_access_receiver) {
6468 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6473 ec.Emit (OpCodes.Dup);
6475 temp = new LocalTemporary (this.Type);
6481 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6483 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6484 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6489 if (ConditionalAccess)
6490 throw new NotImplementedException ("null operator assignment");
6492 if (has_await_source)
6493 source = source.EmitToField (ec);
6495 EmitInstance (ec, prepared);
6500 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6501 ec.Emit (OpCodes.Dup);
6503 temp = new LocalTemporary (this.Type);
6508 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6509 ec.Emit (OpCodes.Volatile);
6511 spec.MemberDefinition.SetIsAssigned ();
6514 ec.Emit (OpCodes.Stsfld, spec);
6516 ec.Emit (OpCodes.Stfld, spec);
6518 if (ec.NotifyEvaluatorOnStore) {
6520 throw new NotImplementedException ("instance field write");
6523 ec.Emit (OpCodes.Dup);
6525 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6536 // Emits store to field with prepared values on stack
6538 public void EmitAssignFromStack (EmitContext ec)
6541 ec.Emit (OpCodes.Stsfld, spec);
6543 ec.Emit (OpCodes.Stfld, spec);
6547 public override void Emit (EmitContext ec)
6552 public override void EmitSideEffect (EmitContext ec)
6554 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6556 if (is_volatile) // || is_marshal_by_ref ())
6557 base.EmitSideEffect (ec);
6560 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6562 if ((mode & AddressOp.Store) != 0)
6563 spec.MemberDefinition.SetIsAssigned ();
6564 if ((mode & AddressOp.Load) != 0)
6565 spec.MemberDefinition.SetIsUsed ();
6568 // Handle initonly fields specially: make a copy and then
6569 // get the address of the copy.
6572 if (spec.IsReadOnly){
6574 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6586 var temp = ec.GetTemporaryLocal (type);
6587 ec.Emit (OpCodes.Stloc, temp);
6588 ec.Emit (OpCodes.Ldloca, temp);
6594 ec.Emit (OpCodes.Ldsflda, spec);
6597 EmitInstance (ec, false);
6598 ec.Emit (OpCodes.Ldflda, spec);
6602 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6604 return MakeExpression (ctx);
6607 public override SLE.Expression MakeExpression (BuilderContext ctx)
6610 return base.MakeExpression (ctx);
6612 return SLE.Expression.Field (
6613 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6614 spec.GetMetaInfo ());
6618 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6620 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6626 // Expression that evaluates to a Property.
6628 // This is not an LValue because we need to re-write the expression. We
6629 // can not take data from the stack and store it.
6631 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6633 Arguments arguments;
6634 FieldExpr backing_field;
6636 public PropertyExpr (PropertySpec spec, Location l)
6639 best_candidate = spec;
6640 type = spec.MemberType;
6645 protected override Arguments Arguments {
6654 protected override TypeSpec DeclaringType {
6656 return best_candidate.DeclaringType;
6660 public override string Name {
6662 return best_candidate.Name;
6666 public bool IsAutoPropertyAccess {
6668 var prop = best_candidate.MemberDefinition as Property;
6669 return prop != null && prop.BackingField != null;
6673 public override bool IsInstance {
6679 public override bool IsStatic {
6681 return best_candidate.IsStatic;
6685 public override string KindName {
6686 get { return "property"; }
6689 public PropertySpec PropertyInfo {
6691 return best_candidate;
6697 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6699 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6702 var args_count = arguments == null ? 0 : arguments.Count;
6703 if (args_count != body.Parameters.Count && args_count == 0)
6706 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6707 mg.InstanceExpression = InstanceExpression;
6712 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6714 return new PropertyExpr (spec, loc) {
6720 public override Expression CreateExpressionTree (ResolveContext ec)
6722 if (ConditionalAccess) {
6723 Error_NullShortCircuitInsideExpressionTree (ec);
6727 if (IsSingleDimensionalArrayLength ()) {
6728 args = new Arguments (1);
6729 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6730 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6733 args = new Arguments (2);
6734 if (InstanceExpression == null)
6735 args.Add (new Argument (new NullLiteral (loc)));
6737 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6738 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6739 return CreateExpressionFactoryCall (ec, "Property", args);
6742 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6744 DoResolveLValue (rc, null);
6745 return new TypeOfMethod (Setter, loc);
6748 public override string GetSignatureForError ()
6750 return best_candidate.GetSignatureForError ();
6753 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6756 return base.MakeExpression (ctx);
6758 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6762 public override SLE.Expression MakeExpression (BuilderContext ctx)
6765 return base.MakeExpression (ctx);
6767 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6771 void Error_PropertyNotValid (ResolveContext ec)
6773 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6774 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6775 GetSignatureForError ());
6778 bool IsSingleDimensionalArrayLength ()
6780 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6783 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6784 return ac != null && ac.Rank == 1;
6787 public override void Emit (EmitContext ec, bool leave_copy)
6790 // Special case: length of single dimension array property is turned into ldlen
6792 if (IsSingleDimensionalArrayLength ()) {
6793 if (conditional_access_receiver) {
6794 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6797 EmitInstance (ec, false);
6799 ec.Emit (OpCodes.Ldlen);
6800 ec.Emit (OpCodes.Conv_I4);
6802 if (conditional_access_receiver) {
6803 ec.CloseConditionalAccess (type);
6809 base.Emit (ec, leave_copy);
6812 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6814 if (backing_field != null) {
6815 backing_field.EmitAssign (ec, source, false, false);
6820 LocalTemporary await_source_arg = null;
6822 if (isCompound && !(source is DynamicExpressionStatement)) {
6823 emitting_compound_assignment = true;
6826 if (has_await_arguments) {
6827 await_source_arg = new LocalTemporary (Type);
6828 await_source_arg.Store (ec);
6830 args = new Arguments (1);
6831 args.Add (new Argument (await_source_arg));
6834 temp = await_source_arg;
6837 has_await_arguments = false;
6842 ec.Emit (OpCodes.Dup);
6843 temp = new LocalTemporary (this.Type);
6848 args = arguments ?? new Arguments (1);
6852 temp = new LocalTemporary (this.Type);
6854 args.Add (new Argument (temp));
6856 args.Add (new Argument (source));
6860 emitting_compound_assignment = false;
6862 var call = new CallEmitter ();
6863 call.InstanceExpression = InstanceExpression;
6865 call.InstanceExpressionOnStack = true;
6867 if (ConditionalAccess) {
6868 call.ConditionalAccess = true;
6872 call.Emit (ec, Setter, args, loc);
6874 call.EmitStatement (ec, Setter, args, loc);
6881 if (await_source_arg != null) {
6882 await_source_arg.Release (ec);
6886 public override void FlowAnalysis (FlowAnalysisContext fc)
6888 var prop = best_candidate.MemberDefinition as Property;
6889 if (prop != null && prop.BackingField != null) {
6890 var var = InstanceExpression as IVariableReference;
6892 var vi = var.VariableInfo;
6893 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, prop.BackingField.Name)) {
6894 fc.Report.Error (8079, loc, "Use of possibly unassigned auto-implemented property `{0}'", Name);
6898 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6903 base.FlowAnalysis (fc);
6905 if (conditional_access_receiver)
6906 fc.ConditionalAccessEnd ();
6909 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6911 eclass = ExprClass.PropertyAccess;
6913 if (best_candidate.IsNotCSharpCompatible) {
6914 Error_PropertyNotValid (rc);
6917 ResolveInstanceExpression (rc, right_side);
6919 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6920 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6921 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6923 type = p.MemberType;
6927 DoBestMemberChecks (rc, best_candidate);
6929 // Handling of com-imported properties with any number of default property parameters
6930 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6931 var p = best_candidate.Get.Parameters;
6932 arguments = new Arguments (p.Count);
6933 for (int i = 0; i < p.Count; ++i) {
6934 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6936 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6937 var p = best_candidate.Set.Parameters;
6938 arguments = new Arguments (p.Count - 1);
6939 for (int i = 0; i < p.Count - 1; ++i) {
6940 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6947 protected override bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
6949 var prop = best_candidate.MemberDefinition as Property;
6953 if (!rc.HasSet (ResolveContext.Options.ConstructorScope))
6956 var spec = prop.BackingField;
6960 if (rc.IsStatic != spec.IsStatic)
6963 if (!spec.IsStatic && (!(InstanceExpression is This) || InstanceExpression is BaseThis))
6966 backing_field = new FieldExpr (prop.BackingField, loc);
6967 backing_field.ResolveLValue (rc, rhs);
6971 public void SetBackingFieldAssigned (FlowAnalysisContext fc)
6973 if (backing_field != null) {
6974 backing_field.SetFieldAssigned (fc);
6978 if (!IsAutoPropertyAccess)
6981 var prop = best_candidate.MemberDefinition as Property;
6982 if (prop != null && prop.BackingField != null) {
6983 bool lvalue_instance = best_candidate.DeclaringType.IsStruct;
6984 if (lvalue_instance) {
6985 var var = InstanceExpression as IVariableReference;
6986 if (var != null && var.VariableInfo != null) {
6987 fc.SetStructFieldAssigned (var.VariableInfo, prop.BackingField.Name);
6993 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6995 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6999 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
7001 // getter and setter can be different for base calls
7002 MethodSpec getter, setter;
7003 protected T best_candidate;
7005 protected LocalTemporary temp;
7006 protected bool emitting_compound_assignment;
7007 protected bool has_await_arguments;
7009 protected PropertyOrIndexerExpr (Location l)
7016 protected abstract Arguments Arguments { get; set; }
7018 public MethodSpec Getter {
7027 public MethodSpec Setter {
7038 protected override Expression DoResolve (ResolveContext ec)
7040 if (eclass == ExprClass.Unresolved) {
7041 ResolveConditionalAccessReceiver (ec);
7043 var expr = OverloadResolve (ec, null);
7048 return expr.Resolve (ec);
7050 if (conditional_access_receiver) {
7051 type = LiftMemberType (ec, type);
7052 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
7056 if (!ResolveGetter (ec))
7062 public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
7064 if (ConditionalAccess)
7065 throw new NotSupportedException ("null propagating operator assignment");
7067 if (right_side == EmptyExpression.OutAccess) {
7068 // TODO: best_candidate can be null at this point
7069 INamedBlockVariable variable = null;
7070 if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
7071 rc.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
7072 best_candidate.Name);
7074 right_side.DoResolveLValue (rc, this);
7079 if (eclass == ExprClass.Unresolved) {
7080 var expr = OverloadResolve (rc, right_side);
7085 return expr.ResolveLValue (rc, right_side);
7087 ResolveInstanceExpression (rc, right_side);
7090 if (!best_candidate.HasSet) {
7091 if (ResolveAutopropertyAssignment (rc, right_side))
7094 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7095 GetSignatureForError ());
7099 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7100 if (best_candidate.HasDifferentAccessibility) {
7101 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7102 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7103 GetSignatureForError ());
7105 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7106 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7110 if (best_candidate.HasDifferentAccessibility)
7111 CheckProtectedMemberAccess (rc, best_candidate.Set);
7113 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7117 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
7119 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7121 call.Emit (ec, method, arguments, loc);
7123 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
7127 // Implements the IAssignMethod interface for assignments
7129 public virtual void Emit (EmitContext ec, bool leave_copy)
7131 var call = new CallEmitter ();
7132 call.ConditionalAccess = ConditionalAccess;
7133 call.InstanceExpression = InstanceExpression;
7134 if (has_await_arguments)
7135 call.HasAwaitArguments = true;
7137 call.DuplicateArguments = emitting_compound_assignment;
7139 if (conditional_access_receiver)
7140 EmitConditionalAccess (ec, ref call, Getter, Arguments);
7142 call.Emit (ec, Getter, Arguments, loc);
7144 if (call.HasAwaitArguments) {
7145 InstanceExpression = call.InstanceExpression;
7146 Arguments = call.EmittedArguments;
7147 has_await_arguments = true;
7151 ec.Emit (OpCodes.Dup);
7152 temp = new LocalTemporary (Type);
7157 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
7159 public override void Emit (EmitContext ec)
7164 protected override FieldExpr EmitToFieldSource (EmitContext ec)
7166 has_await_arguments = true;
7171 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
7173 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
7175 bool ResolveGetter (ResolveContext rc)
7177 if (!best_candidate.HasGet) {
7178 if (InstanceExpression != EmptyExpression.Null) {
7179 rc.Report.SymbolRelatedToPreviousError (best_candidate);
7180 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7181 best_candidate.GetSignatureForError ());
7184 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
7185 if (best_candidate.HasDifferentAccessibility) {
7186 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7187 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
7188 TypeManager.CSharpSignature (best_candidate));
7190 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
7191 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
7195 if (best_candidate.HasDifferentAccessibility) {
7196 CheckProtectedMemberAccess (rc, best_candidate.Get);
7199 getter = CandidateToBaseOverride (rc, best_candidate.Get);
7203 protected virtual bool ResolveAutopropertyAssignment (ResolveContext rc, Expression rhs)
7210 /// Fully resolved expression that evaluates to an Event
7212 public class EventExpr : MemberExpr, IAssignMethod
7214 readonly EventSpec spec;
7217 public EventExpr (EventSpec spec, Location loc)
7225 protected override TypeSpec DeclaringType {
7227 return spec.DeclaringType;
7231 public override string Name {
7237 public override bool IsInstance {
7239 return !spec.IsStatic;
7243 public override bool IsStatic {
7245 return spec.IsStatic;
7249 public override string KindName {
7250 get { return "event"; }
7253 public MethodSpec Operator {
7261 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7264 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7266 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7267 if (spec.BackingField != null &&
7268 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7270 spec.MemberDefinition.SetIsUsed ();
7272 if (!ec.IsObsolete) {
7273 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7275 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7278 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7279 Error_AssignmentEventOnly (ec);
7281 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7283 InstanceExpression = null;
7285 return ml.ResolveMemberAccess (ec, left, original);
7289 return base.ResolveMemberAccess (ec, left, original);
7292 public override Expression CreateExpressionTree (ResolveContext ec)
7294 throw new NotSupportedException ("ET");
7297 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7299 if (right_side == EmptyExpression.EventAddition) {
7300 op = spec.AccessorAdd;
7301 } else if (right_side == EmptyExpression.EventSubtraction) {
7302 op = spec.AccessorRemove;
7306 Error_AssignmentEventOnly (ec);
7310 op = CandidateToBaseOverride (ec, op);
7314 protected override Expression DoResolve (ResolveContext ec)
7316 eclass = ExprClass.EventAccess;
7317 type = spec.MemberType;
7319 ResolveInstanceExpression (ec, null);
7321 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7322 Error_AssignmentEventOnly (ec);
7325 DoBestMemberChecks (ec, spec);
7329 public override void Emit (EmitContext ec)
7331 throw new NotSupportedException ();
7332 //Error_CannotAssign ();
7335 #region IAssignMethod Members
7337 public void Emit (EmitContext ec, bool leave_copy)
7339 throw new NotImplementedException ();
7342 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7344 if (leave_copy || !isCompound)
7345 throw new NotImplementedException ("EventExpr::EmitAssign");
7347 Arguments args = new Arguments (1);
7348 args.Add (new Argument (source));
7350 // TODO: Wrong, needs receiver
7351 // if (NullShortCircuit) {
7352 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7355 var call = new CallEmitter ();
7356 call.InstanceExpression = InstanceExpression;
7357 call.ConditionalAccess = ConditionalAccess;
7358 call.EmitStatement (ec, op, args, loc);
7360 // if (NullShortCircuit)
7361 // ec.CloseConditionalAccess (null);
7366 void Error_AssignmentEventOnly (ResolveContext ec)
7368 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7369 ec.Report.Error (79, loc,
7370 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7371 GetSignatureForError ());
7373 ec.Report.Error (70, loc,
7374 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7375 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7379 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7381 name = name.Substring (0, name.LastIndexOf ('.'));
7382 base.Error_CannotCallAbstractBase (rc, name);
7385 public override string GetSignatureForError ()
7387 return TypeManager.CSharpSignature (spec);
7390 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7392 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7396 public class TemporaryVariableReference : VariableReference
7398 public class Declarator : Statement
7400 TemporaryVariableReference variable;
7402 public Declarator (TemporaryVariableReference variable)
7404 this.variable = variable;
7408 protected override void DoEmit (EmitContext ec)
7410 variable.li.CreateBuilder (ec);
7413 public override void Emit (EmitContext ec)
7415 // Don't create sequence point
7419 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7424 protected override void CloneTo (CloneContext clonectx, Statement target)
7432 public TemporaryVariableReference (LocalVariable li, Location loc)
7435 this.type = li.Type;
7439 public override bool IsLockedByStatement {
7447 public LocalVariable LocalInfo {
7453 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7455 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7456 return new TemporaryVariableReference (li, loc);
7459 protected override Expression DoResolve (ResolveContext ec)
7461 eclass = ExprClass.Variable;
7464 // Don't capture temporary variables except when using
7465 // state machine redirection and block yields
7467 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7468 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7469 ec.IsVariableCapturingRequired) {
7470 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7471 storey.CaptureLocalVariable (ec, li);
7477 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7479 return Resolve (ec);
7482 public override void Emit (EmitContext ec)
7484 li.CreateBuilder (ec);
7489 public void EmitAssign (EmitContext ec, Expression source)
7491 li.CreateBuilder (ec);
7493 EmitAssign (ec, source, false, false);
7496 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7498 return li.HoistedVariant;
7501 public override bool IsFixed {
7502 get { return true; }
7505 public override bool IsRef {
7506 get { return false; }
7509 public override string Name {
7510 get { throw new NotImplementedException (); }
7513 public override void SetHasAddressTaken ()
7515 throw new NotImplementedException ();
7518 protected override ILocalVariable Variable {
7522 public override VariableInfo VariableInfo {
7523 get { return null; }
7528 /// Handles `var' contextual keyword; var becomes a keyword only
7529 /// if no type called var exists in a variable scope
7531 class VarExpr : SimpleName
7533 public VarExpr (Location loc)
7538 public bool InferType (ResolveContext ec, Expression right_side)
7541 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7543 type = right_side.Type;
7544 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7545 ec.Report.Error (815, loc,
7546 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7547 type.GetSignatureForError ());
7551 eclass = ExprClass.Variable;
7555 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7557 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7558 base.Error_TypeOrNamespaceNotFound (ec);
7560 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");