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)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 protected static bool IsNullPropagatingValid (TypeSpec type)
435 return (TypeSpec.IsReferenceType (type) && type != InternalType.NullLiteral) || type.IsNullableType;
438 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
440 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
441 Nullable.NullableInfo.MakeType (rc.Module, type) :
446 /// Resolves an expression and performs semantic analysis on it.
450 /// Currently Resolve wraps DoResolve to perform sanity
451 /// checking and assertion checking on what we expect from Resolve.
453 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
455 if (eclass != ExprClass.Unresolved) {
456 if ((flags & ExprClassToResolveFlags) == 0) {
457 Error_UnexpectedKind (ec, flags, loc);
471 if ((flags & e.ExprClassToResolveFlags) == 0) {
472 e.Error_UnexpectedKind (ec, flags, loc);
477 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
480 } catch (Exception ex) {
481 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
482 ec.Report.Printer is NullReportPrinter)
485 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
486 return ErrorExpression.Instance; // TODO: Add location
491 /// Resolves an expression and performs semantic analysis on it.
493 public Expression Resolve (ResolveContext rc)
495 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
499 /// Resolves an expression for LValue assignment
503 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
504 /// checking and assertion checking on what we expect from Resolve
506 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
508 int errors = ec.Report.Errors;
509 bool out_access = right_side == EmptyExpression.OutAccess;
511 Expression e = DoResolveLValue (ec, right_side);
513 if (e != null && out_access && !(e is IMemoryLocation)) {
514 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
515 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
517 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
518 // e.GetType () + " " + e.GetSignatureForError ());
523 if (errors == ec.Report.Errors) {
524 Error_ValueAssignment (ec, right_side);
529 if (e.eclass == ExprClass.Unresolved)
530 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
532 if ((e.type == null) && !(e is GenericTypeExpr))
533 throw new Exception ("Expression " + e + " did not set its type after Resolve");
538 public Constant ResolveLabelConstant (ResolveContext rc)
540 var expr = Resolve (rc);
544 Constant c = expr as Constant;
546 if (expr.type != InternalType.ErrorType)
547 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
555 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
557 if (Attribute.IsValidArgumentType (parameterType)) {
558 rc.Module.Compiler.Report.Error (182, loc,
559 "An attribute argument must be a constant expression, typeof expression or array creation expression");
561 rc.Module.Compiler.Report.Error (181, loc,
562 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
563 targetType.GetSignatureForError ());
568 /// Emits the code for the expression
572 /// The Emit method is invoked to generate the code
573 /// for the expression.
575 public abstract void Emit (EmitContext ec);
578 // Emit code to branch to @target if this expression is equivalent to @on_true.
579 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
580 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
581 // including the use of conditional branches. Note also that a branch MUST be emitted
582 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
585 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
588 // Emit this expression for its side effects, not for its value.
589 // The default implementation is to emit the value, and then throw it away.
590 // Subclasses can provide more efficient implementations, but those MUST be equivalent
591 public virtual void EmitSideEffect (EmitContext ec)
594 ec.Emit (OpCodes.Pop);
598 // Emits the expression into temporary field variable. The method
599 // should be used for await expressions only
601 public virtual Expression EmitToField (EmitContext ec)
604 // This is the await prepare Emit method. When emitting code like
605 // a + b we emit code like
611 // For await a + await b we have to interfere the flow to keep the
612 // stack clean because await yields from the expression. The emit
615 // a = a.EmitToField () // a is changed to temporary field access
616 // b = b.EmitToField ()
622 // The idea is to emit expression and leave the stack empty with
623 // result value still available.
625 // Expressions should override this default implementation when
626 // optimized version can be provided (e.g. FieldExpr)
629 // We can optimize for side-effect free expressions, they can be
630 // emitted out of order
632 if (IsSideEffectFree)
635 bool needs_temporary = ContainsEmitWithAwait ();
636 if (!needs_temporary)
639 // Emit original code
640 var field = EmitToFieldSource (ec);
643 // Store the result to temporary field when we
644 // cannot load `this' directly
646 field = ec.GetTemporaryField (type);
647 if (needs_temporary) {
649 // Create temporary local (we cannot load `this' before Emit)
651 var temp = ec.GetTemporaryLocal (type);
652 ec.Emit (OpCodes.Stloc, temp);
655 ec.Emit (OpCodes.Ldloc, temp);
656 field.EmitAssignFromStack (ec);
658 ec.FreeTemporaryLocal (temp, type);
660 field.EmitAssignFromStack (ec);
667 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
670 // Default implementation calls Emit method
676 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
678 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
679 bool contains_await = false;
681 for (int i = 1; i < expressions.Count; ++i) {
682 if (expressions[i].ContainsEmitWithAwait ()) {
683 contains_await = true;
688 if (contains_await) {
689 for (int i = 0; i < expressions.Count; ++i) {
690 expressions[i] = expressions[i].EmitToField (ec);
695 for (int i = 0; i < expressions.Count; ++i) {
696 expressions[i].Emit (ec);
701 /// Protected constructor. Only derivate types should
702 /// be able to be created
705 protected Expression ()
710 /// Returns a fully formed expression after a MemberLookup
713 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
715 if (spec is EventSpec)
716 return new EventExpr ((EventSpec) spec, loc);
717 if (spec is ConstSpec)
718 return new ConstantExpr ((ConstSpec) spec, loc);
719 if (spec is FieldSpec)
720 return new FieldExpr ((FieldSpec) spec, loc);
721 if (spec is PropertySpec)
722 return new PropertyExpr ((PropertySpec) spec, loc);
723 if (spec is TypeSpec)
724 return new TypeExpression (((TypeSpec) spec), loc);
729 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
731 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
734 case MemberKind.Struct:
735 rc.Report.SymbolRelatedToPreviousError (type);
736 // Report meaningful error for struct as they always have default ctor in C# context
737 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
739 case MemberKind.MissingType:
740 case MemberKind.InternalCompilerType:
743 rc.Report.SymbolRelatedToPreviousError (type);
744 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
745 type.GetSignatureForError ());
752 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
753 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
754 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
757 return r.ResolveMember<MethodSpec> (rc, ref args);
761 public enum MemberLookupRestrictions
770 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
771 // `qualifier_type' or null to lookup members in the current class.
773 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
775 var members = MemberCache.FindMembers (queried_type, name, false);
779 MemberSpec non_method = null;
780 MemberSpec ambig_non_method = null;
782 for (int i = 0; i < members.Count; ++i) {
783 var member = members[i];
785 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
786 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
789 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
792 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
796 if (!member.IsAccessible (rc))
800 // With runtime binder we can have a situation where queried type is inaccessible
801 // because it came via dynamic object, the check about inconsisted accessibility
802 // had no effect as the type was unknown during compilation
805 // private class N { }
807 // public dynamic Foo ()
813 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
817 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
818 if (member is MethodSpec) {
820 // Interface members that are hidden by class members are removed from the set. This
821 // step only has an effect if T is a type parameter and T has both an effective base
822 // class other than object and a non-empty effective interface set
824 var tps = queried_type as TypeParameterSpec;
825 if (tps != null && tps.HasTypeConstraint)
826 members = RemoveHiddenTypeParameterMethods (members);
828 return new MethodGroupExpr (members, queried_type, loc);
831 if (!Invocation.IsMemberInvocable (member))
835 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
837 } else if (!errorMode && !member.IsNotCSharpCompatible) {
839 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
840 // T has both an effective base class other than object and a non-empty effective interface set.
842 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
844 var tps = queried_type as TypeParameterSpec;
845 if (tps != null && tps.HasTypeConstraint) {
846 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
849 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
855 ambig_non_method = member;
859 if (non_method != null) {
860 if (ambig_non_method != null && rc != null) {
861 var report = rc.Module.Compiler.Report;
862 report.SymbolRelatedToPreviousError (non_method);
863 report.SymbolRelatedToPreviousError (ambig_non_method);
864 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
865 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
868 if (non_method is MethodSpec)
869 return new MethodGroupExpr (members, queried_type, loc);
871 return ExprClassFromMemberInfo (non_method, loc);
874 if (members[0].DeclaringType.BaseType == null)
877 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
879 } while (members != null);
884 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
886 if (members.Count < 2)
890 // If M is a method, then all non-method members declared in an interface declaration
891 // are removed from the set, and all methods with the same signature as M declared in
892 // an interface declaration are removed from the set
896 for (int i = 0; i < members.Count; ++i) {
897 var method = members[i] as MethodSpec;
898 if (method == null) {
901 members = new List<MemberSpec> (members);
904 members.RemoveAt (i--);
908 if (!method.DeclaringType.IsInterface)
911 for (int ii = 0; ii < members.Count; ++ii) {
912 var candidate = members[ii] as MethodSpec;
913 if (candidate == null || !candidate.DeclaringType.IsClass)
916 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
921 members = new List<MemberSpec> (members);
924 members.RemoveAt (i--);
932 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
934 throw new NotImplementedException ();
937 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
939 if (t == InternalType.ErrorType)
942 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
943 oper, t.GetSignatureForError ());
946 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
948 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
951 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
953 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
956 public virtual void FlowAnalysis (FlowAnalysisContext fc)
961 /// Returns an expression that can be used to invoke operator true
962 /// on the expression if it exists.
964 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
966 return GetOperatorTrueOrFalse (ec, e, true, loc);
970 /// Returns an expression that can be used to invoke operator false
971 /// on the expression if it exists.
973 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
975 return GetOperatorTrueOrFalse (ec, e, false, loc);
978 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
980 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
981 var methods = MemberCache.GetUserOperator (e.type, op, false);
985 Arguments arguments = new Arguments (1);
986 arguments.Add (new Argument (e));
988 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
989 var oper = res.ResolveOperator (ec, ref arguments);
994 return new UserOperatorCall (oper, arguments, null, loc);
997 public virtual string ExprClassName
1001 case ExprClass.Unresolved:
1002 return "Unresolved";
1003 case ExprClass.Value:
1005 case ExprClass.Variable:
1007 case ExprClass.Namespace:
1009 case ExprClass.Type:
1011 case ExprClass.MethodGroup:
1012 return "method group";
1013 case ExprClass.PropertyAccess:
1014 return "property access";
1015 case ExprClass.EventAccess:
1016 return "event access";
1017 case ExprClass.IndexerAccess:
1018 return "indexer access";
1019 case ExprClass.Nothing:
1021 case ExprClass.TypeParameter:
1022 return "type parameter";
1024 throw new Exception ("Should not happen");
1029 /// Reports that we were expecting `expr' to be of class `expected'
1031 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1033 var name = memberExpr.GetSignatureForError ();
1035 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1038 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1040 string [] valid = new string [4];
1043 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1044 valid [count++] = "variable";
1045 valid [count++] = "value";
1048 if ((flags & ResolveFlags.Type) != 0)
1049 valid [count++] = "type";
1051 if ((flags & ResolveFlags.MethodGroup) != 0)
1052 valid [count++] = "method group";
1055 valid [count++] = "unknown";
1057 StringBuilder sb = new StringBuilder (valid [0]);
1058 for (int i = 1; i < count - 1; i++) {
1060 sb.Append (valid [i]);
1063 sb.Append ("' or `");
1064 sb.Append (valid [count - 1]);
1067 ec.Report.Error (119, loc,
1068 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1071 public static void UnsafeError (ResolveContext ec, Location loc)
1073 UnsafeError (ec.Report, loc);
1076 public static void UnsafeError (Report Report, Location loc)
1078 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1082 // Converts `source' to an int, uint, long or ulong.
1084 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1086 var btypes = ec.BuiltinTypes;
1088 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1089 Arguments args = new Arguments (1);
1090 args.Add (new Argument (source));
1091 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1094 Expression converted;
1096 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1097 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1098 if (converted == null)
1099 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1100 if (converted == null)
1101 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1102 if (converted == null)
1103 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1105 if (converted == null) {
1106 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1115 // Only positive constants are allowed at compile time
1117 Constant c = converted as Constant;
1118 if (c != null && c.IsNegative)
1119 Error_NegativeArrayIndex (ec, source.loc);
1121 // No conversion needed to array index
1122 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1125 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1129 // Derived classes implement this method by cloning the fields that
1130 // could become altered during the Resolve stage
1132 // Only expressions that are created for the parser need to implement
1135 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1137 throw new NotImplementedException (
1139 "CloneTo not implemented for expression {0}", this.GetType ()));
1143 // Clones an expression created by the parser.
1145 // We only support expressions created by the parser so far, not
1146 // expressions that have been resolved (many more classes would need
1147 // to implement CloneTo).
1149 // This infrastructure is here merely for Lambda expressions which
1150 // compile the same code using different type values for the same
1151 // arguments to find the correct overload
1153 public virtual Expression Clone (CloneContext clonectx)
1155 Expression cloned = (Expression) MemberwiseClone ();
1156 CloneTo (clonectx, cloned);
1162 // Implementation of expression to expression tree conversion
1164 public abstract Expression CreateExpressionTree (ResolveContext ec);
1166 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1168 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1171 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1173 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1176 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1178 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1181 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1183 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1187 return new TypeExpression (t, loc);
1191 // Implemented by all expressions which support conversion from
1192 // compiler expression to invokable runtime expression. Used by
1193 // dynamic C# binder.
1195 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1197 throw new NotImplementedException ("MakeExpression for " + GetType ());
1200 public virtual object Accept (StructuralVisitor visitor)
1202 return visitor.Visit (this);
1207 /// This is just a base class for expressions that can
1208 /// appear on statements (invocations, object creation,
1209 /// assignments, post/pre increment and decrement). The idea
1210 /// being that they would support an extra Emition interface that
1211 /// does not leave a result on the stack.
1213 public abstract class ExpressionStatement : Expression
1215 public virtual void MarkReachable (Reachability rc)
1219 public ExpressionStatement ResolveStatement (BlockContext ec)
1221 Expression e = Resolve (ec);
1225 ExpressionStatement es = e as ExpressionStatement;
1226 if (es == null || e is AnonymousMethodBody)
1227 Error_InvalidExpressionStatement (ec);
1230 // This is quite expensive warning, try to limit the damage
1232 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1233 WarningAsyncWithoutWait (ec, e);
1239 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1241 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1242 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1247 // Need to do full resolve because GetAwaiter can be extension method
1248 // available only in this context
1250 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1254 var arguments = new Arguments (0);
1255 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1260 // Use same check rules as for real await
1262 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1263 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1266 bc.Report.Warning (4014, 1, e.Location,
1267 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1271 var inv = e as Invocation;
1272 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1273 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1274 bc.Report.Warning (4014, 1, e.Location,
1275 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1281 /// Requests the expression to be emitted in a `statement'
1282 /// context. This means that no new value is left on the
1283 /// stack after invoking this method (constrasted with
1284 /// Emit that will always leave a value on the stack).
1286 public abstract void EmitStatement (EmitContext ec);
1288 public override void EmitSideEffect (EmitContext ec)
1295 /// This kind of cast is used to encapsulate the child
1296 /// whose type is child.Type into an expression that is
1297 /// reported to return "return_type". This is used to encapsulate
1298 /// expressions which have compatible types, but need to be dealt
1299 /// at higher levels with.
1301 /// For example, a "byte" expression could be encapsulated in one
1302 /// of these as an "unsigned int". The type for the expression
1303 /// would be "unsigned int".
1306 public abstract class TypeCast : Expression
1308 protected readonly Expression child;
1310 protected TypeCast (Expression child, TypeSpec return_type)
1312 eclass = child.eclass;
1313 loc = child.Location;
1318 public Expression Child {
1324 public override bool ContainsEmitWithAwait ()
1326 return child.ContainsEmitWithAwait ();
1329 public override Expression CreateExpressionTree (ResolveContext ec)
1331 Arguments args = new Arguments (2);
1332 args.Add (new Argument (child.CreateExpressionTree (ec)));
1333 args.Add (new Argument (new TypeOf (type, loc)));
1335 if (type.IsPointer || child.Type.IsPointer)
1336 Error_PointerInsideExpressionTree (ec);
1338 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1341 protected override Expression DoResolve (ResolveContext ec)
1343 // This should never be invoked, we are born in fully
1344 // initialized state.
1349 public override void Emit (EmitContext ec)
1354 public override void FlowAnalysis (FlowAnalysisContext fc)
1356 child.FlowAnalysis (fc);
1359 public override SLE.Expression MakeExpression (BuilderContext ctx)
1362 return base.MakeExpression (ctx);
1364 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1365 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1366 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1370 protected override void CloneTo (CloneContext clonectx, Expression t)
1375 public override bool IsNull {
1376 get { return child.IsNull; }
1380 public class EmptyCast : TypeCast {
1381 EmptyCast (Expression child, TypeSpec target_type)
1382 : base (child, target_type)
1386 public static Expression Create (Expression child, TypeSpec type)
1388 Constant c = child as Constant;
1390 var enum_constant = c as EnumConstant;
1391 if (enum_constant != null)
1392 c = enum_constant.Child;
1394 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1398 var res = c.ConvertImplicitly (type);
1404 EmptyCast e = child as EmptyCast;
1406 return new EmptyCast (e.child, type);
1408 return new EmptyCast (child, type);
1411 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1413 child.EmitBranchable (ec, label, on_true);
1416 public override void EmitSideEffect (EmitContext ec)
1418 child.EmitSideEffect (ec);
1423 // Used for predefined type user operator (no obsolete check, etc.)
1425 public class OperatorCast : TypeCast
1427 readonly MethodSpec conversion_operator;
1429 public OperatorCast (Expression expr, TypeSpec target_type)
1430 : this (expr, target_type, target_type, false)
1434 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1435 : this (expr, target_type, target_type, find_explicit)
1439 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1440 : base (expr, returnType)
1442 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1443 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1446 foreach (MethodSpec oper in mi) {
1447 if (oper.ReturnType != returnType)
1450 if (oper.Parameters.Types[0] == expr.Type) {
1451 conversion_operator = oper;
1457 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1458 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1461 public override void Emit (EmitContext ec)
1464 ec.Emit (OpCodes.Call, conversion_operator);
1469 // Constant specialization of EmptyCast.
1470 // We need to special case this since an empty cast of
1471 // a constant is still a constant.
1473 public class EmptyConstantCast : Constant
1475 public readonly Constant child;
1477 public EmptyConstantCast (Constant child, TypeSpec type)
1478 : base (child.Location)
1481 throw new ArgumentNullException ("child");
1484 this.eclass = child.eclass;
1488 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1490 if (child.Type == target_type)
1493 // FIXME: check that 'type' can be converted to 'target_type' first
1494 return child.ConvertExplicitly (in_checked_context, target_type);
1497 public override Expression CreateExpressionTree (ResolveContext ec)
1499 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1500 child.CreateExpressionTree (ec),
1501 new TypeOf (type, loc));
1504 Error_PointerInsideExpressionTree (ec);
1506 return CreateExpressionFactoryCall (ec, "Convert", args);
1509 public override bool IsDefaultValue {
1510 get { return child.IsDefaultValue; }
1513 public override bool IsNegative {
1514 get { return child.IsNegative; }
1517 public override bool IsNull {
1518 get { return child.IsNull; }
1521 public override bool IsOneInteger {
1522 get { return child.IsOneInteger; }
1525 public override bool IsSideEffectFree {
1527 return child.IsSideEffectFree;
1531 public override bool IsZeroInteger {
1532 get { return child.IsZeroInteger; }
1535 public override void Emit (EmitContext ec)
1540 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1542 child.EmitBranchable (ec, label, on_true);
1544 // Only to make verifier happy
1545 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1546 ec.Emit (OpCodes.Unbox_Any, type);
1549 public override void EmitSideEffect (EmitContext ec)
1551 child.EmitSideEffect (ec);
1554 public override object GetValue ()
1556 return child.GetValue ();
1559 public override string GetValueAsLiteral ()
1561 return child.GetValueAsLiteral ();
1564 public override long GetValueAsLong ()
1566 return child.GetValueAsLong ();
1569 public override Constant ConvertImplicitly (TypeSpec target_type)
1571 if (type == target_type)
1574 // FIXME: Do we need to check user conversions?
1575 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1578 return child.ConvertImplicitly (target_type);
1583 /// This class is used to wrap literals which belong inside Enums
1585 public class EnumConstant : Constant
1587 public Constant Child;
1589 public EnumConstant (Constant child, TypeSpec enum_type)
1590 : base (child.Location)
1594 this.eclass = ExprClass.Value;
1595 this.type = enum_type;
1598 protected EnumConstant (Location loc)
1603 public override void Emit (EmitContext ec)
1608 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1610 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1613 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1615 Child.EmitBranchable (ec, label, on_true);
1618 public override void EmitSideEffect (EmitContext ec)
1620 Child.EmitSideEffect (ec);
1623 public override string GetSignatureForError()
1625 return Type.GetSignatureForError ();
1628 public override object GetValue ()
1630 return Child.GetValue ();
1634 public override object GetTypedValue ()
1637 // The method can be used in dynamic context only (on closed types)
1639 // System.Enum.ToObject cannot be called on dynamic types
1640 // EnumBuilder has to be used, but we cannot use EnumBuilder
1641 // because it does not properly support generics
1643 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1647 public override string GetValueAsLiteral ()
1649 return Child.GetValueAsLiteral ();
1652 public override long GetValueAsLong ()
1654 return Child.GetValueAsLong ();
1657 public EnumConstant Increment()
1659 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1662 public override bool IsDefaultValue {
1664 return Child.IsDefaultValue;
1668 public override bool IsSideEffectFree {
1670 return Child.IsSideEffectFree;
1674 public override bool IsZeroInteger {
1675 get { return Child.IsZeroInteger; }
1678 public override bool IsNegative {
1680 return Child.IsNegative;
1684 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1686 if (Child.Type == target_type)
1689 return Child.ConvertExplicitly (in_checked_context, target_type);
1692 public override Constant ConvertImplicitly (TypeSpec type)
1694 if (this.type == type) {
1698 if (!Convert.ImplicitStandardConversionExists (this, type)){
1702 return Child.ConvertImplicitly (type);
1707 /// This kind of cast is used to encapsulate Value Types in objects.
1709 /// The effect of it is to box the value type emitted by the previous
1712 public class BoxedCast : TypeCast {
1714 public BoxedCast (Expression expr, TypeSpec target_type)
1715 : base (expr, target_type)
1717 eclass = ExprClass.Value;
1720 protected override Expression DoResolve (ResolveContext ec)
1722 // This should never be invoked, we are born in fully
1723 // initialized state.
1728 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1730 // Only boxing to object type is supported
1731 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1732 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1736 enc.Encode (child.Type);
1737 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1740 public override void Emit (EmitContext ec)
1744 ec.Emit (OpCodes.Box, child.Type);
1747 public override void EmitSideEffect (EmitContext ec)
1749 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1750 // so, we need to emit the box+pop instructions in most cases
1751 if (child.Type.IsStruct &&
1752 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1753 child.EmitSideEffect (ec);
1755 base.EmitSideEffect (ec);
1759 public class UnboxCast : TypeCast {
1760 public UnboxCast (Expression expr, TypeSpec return_type)
1761 : base (expr, return_type)
1765 protected override Expression DoResolve (ResolveContext ec)
1767 // This should never be invoked, we are born in fully
1768 // initialized state.
1773 public override void Emit (EmitContext ec)
1777 ec.Emit (OpCodes.Unbox_Any, type);
1782 /// This is used to perform explicit numeric conversions.
1784 /// Explicit numeric conversions might trigger exceptions in a checked
1785 /// context, so they should generate the conv.ovf opcodes instead of
1788 public class ConvCast : TypeCast {
1789 public enum Mode : byte {
1790 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1792 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1793 U2_I1, U2_U1, U2_I2, U2_CH,
1794 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1795 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1796 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1797 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1798 CH_I1, CH_U1, CH_I2,
1799 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1800 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1806 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1807 : base (child, return_type)
1812 protected override Expression DoResolve (ResolveContext ec)
1814 // This should never be invoked, we are born in fully
1815 // initialized state.
1820 public override string ToString ()
1822 return String.Format ("ConvCast ({0}, {1})", mode, child);
1825 public override void Emit (EmitContext ec)
1831 public static void Emit (EmitContext ec, Mode mode)
1833 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1835 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1836 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1837 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1838 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1839 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1841 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1842 case Mode.U1_CH: /* nothing */ break;
1844 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1845 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1846 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1847 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1848 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1849 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1851 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1852 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1853 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1854 case Mode.U2_CH: /* nothing */ break;
1856 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1857 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1858 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1859 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1860 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1861 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1862 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1864 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1865 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1866 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1867 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1868 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1869 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1871 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1872 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1873 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1874 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1875 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1876 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1877 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1878 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1879 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1881 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1882 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1883 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1884 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1885 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1886 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1887 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1888 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1889 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1891 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1892 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1893 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1895 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1896 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1897 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1898 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1899 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1900 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1901 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1902 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1903 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1905 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1906 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1907 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1908 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1909 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1910 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1911 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1912 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1913 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1914 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1916 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1920 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1921 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1922 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1923 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1924 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1926 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1927 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1929 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1930 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1931 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1932 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1933 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1934 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1936 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1937 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1938 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1939 case Mode.U2_CH: /* nothing */ break;
1941 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1942 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1943 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1944 case Mode.I4_U4: /* nothing */ break;
1945 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1946 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1947 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1949 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1950 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1951 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1952 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1953 case Mode.U4_I4: /* nothing */ break;
1954 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1956 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1957 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1958 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1959 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1960 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1961 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1962 case Mode.I8_U8: /* nothing */ break;
1963 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1964 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1966 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1967 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1968 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1969 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1970 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1971 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1972 case Mode.U8_I8: /* nothing */ break;
1973 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1974 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1976 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1977 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1978 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1980 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1981 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1982 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1983 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1984 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1985 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1986 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1987 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1988 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1990 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1991 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1992 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1993 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1994 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1995 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1996 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1997 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1998 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1999 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2001 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2007 class OpcodeCast : TypeCast
2011 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2012 : base (child, return_type)
2017 protected override Expression DoResolve (ResolveContext ec)
2019 // This should never be invoked, we are born in fully
2020 // initialized state.
2025 public override void Emit (EmitContext ec)
2031 public TypeSpec UnderlyingType {
2032 get { return child.Type; }
2037 // Opcode casts expression with 2 opcodes but only
2038 // single expression tree node
2040 class OpcodeCastDuplex : OpcodeCast
2042 readonly OpCode second;
2044 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2045 : base (child, returnType, first)
2047 this.second = second;
2050 public override void Emit (EmitContext ec)
2058 /// This kind of cast is used to encapsulate a child and cast it
2059 /// to the class requested
2061 public sealed class ClassCast : TypeCast {
2062 readonly bool forced;
2064 public ClassCast (Expression child, TypeSpec return_type)
2065 : base (child, return_type)
2069 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2070 : base (child, return_type)
2072 this.forced = forced;
2075 public override void Emit (EmitContext ec)
2079 bool gen = TypeManager.IsGenericParameter (child.Type);
2081 ec.Emit (OpCodes.Box, child.Type);
2083 if (type.IsGenericParameter) {
2084 ec.Emit (OpCodes.Unbox_Any, type);
2091 ec.Emit (OpCodes.Castclass, type);
2096 // Created during resolving pahse when an expression is wrapped or constantified
2097 // and original expression can be used later (e.g. for expression trees)
2099 public class ReducedExpression : Expression
2101 public sealed class ReducedConstantExpression : EmptyConstantCast
2103 readonly Expression orig_expr;
2105 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2106 : base (expr, expr.Type)
2108 this.orig_expr = orig_expr;
2111 public Expression OriginalExpression {
2117 public override Constant ConvertImplicitly (TypeSpec target_type)
2119 Constant c = base.ConvertImplicitly (target_type);
2121 c = new ReducedConstantExpression (c, orig_expr);
2126 public override Expression CreateExpressionTree (ResolveContext ec)
2128 return orig_expr.CreateExpressionTree (ec);
2131 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2133 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2135 c = new ReducedConstantExpression (c, orig_expr);
2139 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2142 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2144 if (orig_expr is Conditional)
2145 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2147 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2151 sealed class ReducedExpressionStatement : ExpressionStatement
2153 readonly Expression orig_expr;
2154 readonly ExpressionStatement stm;
2156 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2158 this.orig_expr = orig;
2160 this.eclass = stm.eclass;
2161 this.type = stm.Type;
2163 this.loc = orig.Location;
2166 public override bool ContainsEmitWithAwait ()
2168 return stm.ContainsEmitWithAwait ();
2171 public override Expression CreateExpressionTree (ResolveContext ec)
2173 return orig_expr.CreateExpressionTree (ec);
2176 protected override Expression DoResolve (ResolveContext ec)
2181 public override void Emit (EmitContext ec)
2186 public override void EmitStatement (EmitContext ec)
2188 stm.EmitStatement (ec);
2191 public override void FlowAnalysis (FlowAnalysisContext fc)
2193 stm.FlowAnalysis (fc);
2197 readonly Expression expr, orig_expr;
2199 private ReducedExpression (Expression expr, Expression orig_expr)
2202 this.eclass = expr.eclass;
2203 this.type = expr.Type;
2204 this.orig_expr = orig_expr;
2205 this.loc = orig_expr.Location;
2210 public override bool IsSideEffectFree {
2212 return expr.IsSideEffectFree;
2216 public Expression OriginalExpression {
2224 public override bool ContainsEmitWithAwait ()
2226 return expr.ContainsEmitWithAwait ();
2230 // Creates fully resolved expression switcher
2232 public static Constant Create (Constant expr, Expression original_expr)
2234 if (expr.eclass == ExprClass.Unresolved)
2235 throw new ArgumentException ("Unresolved expression");
2237 return new ReducedConstantExpression (expr, original_expr);
2240 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2242 return new ReducedExpressionStatement (s, orig);
2245 public static Expression Create (Expression expr, Expression original_expr)
2247 return Create (expr, original_expr, true);
2251 // Creates unresolved reduce expression. The original expression has to be
2252 // already resolved. Created expression is constant based based on `expr'
2253 // value unless canBeConstant is used
2255 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2257 if (canBeConstant) {
2258 Constant c = expr as Constant;
2260 return Create (c, original_expr);
2263 ExpressionStatement s = expr as ExpressionStatement;
2265 return Create (s, original_expr);
2267 if (expr.eclass == ExprClass.Unresolved)
2268 throw new ArgumentException ("Unresolved expression");
2270 return new ReducedExpression (expr, original_expr);
2273 public override Expression CreateExpressionTree (ResolveContext ec)
2275 return orig_expr.CreateExpressionTree (ec);
2278 protected override Expression DoResolve (ResolveContext ec)
2283 public override void Emit (EmitContext ec)
2288 public override Expression EmitToField (EmitContext ec)
2290 return expr.EmitToField(ec);
2293 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2295 expr.EmitBranchable (ec, target, on_true);
2298 public override void FlowAnalysis (FlowAnalysisContext fc)
2300 expr.FlowAnalysis (fc);
2303 public override SLE.Expression MakeExpression (BuilderContext ctx)
2305 return orig_expr.MakeExpression (ctx);
2310 // Standard composite pattern
2312 public abstract class CompositeExpression : Expression
2314 protected Expression expr;
2316 protected CompositeExpression (Expression expr)
2319 this.loc = expr.Location;
2322 public override bool ContainsEmitWithAwait ()
2324 return expr.ContainsEmitWithAwait ();
2327 public override Expression CreateExpressionTree (ResolveContext rc)
2329 return expr.CreateExpressionTree (rc);
2332 public Expression Child {
2333 get { return expr; }
2336 protected override Expression DoResolve (ResolveContext rc)
2338 expr = expr.Resolve (rc);
2343 eclass = expr.eclass;
2347 public override void Emit (EmitContext ec)
2352 public override bool IsNull {
2353 get { return expr.IsNull; }
2358 // Base of expressions used only to narrow resolve flow
2360 public abstract class ShimExpression : Expression
2362 protected Expression expr;
2364 protected ShimExpression (Expression expr)
2369 public Expression Expr {
2375 protected override void CloneTo (CloneContext clonectx, Expression t)
2380 ShimExpression target = (ShimExpression) t;
2381 target.expr = expr.Clone (clonectx);
2384 public override bool ContainsEmitWithAwait ()
2386 return expr.ContainsEmitWithAwait ();
2389 public override Expression CreateExpressionTree (ResolveContext ec)
2391 throw new NotSupportedException ("ET");
2394 public override void Emit (EmitContext ec)
2396 throw new InternalErrorException ("Missing Resolve call");
2400 public class UnreachableExpression : Expression
2402 public UnreachableExpression (Expression expr)
2404 this.loc = expr.Location;
2407 public override Expression CreateExpressionTree (ResolveContext ec)
2410 throw new NotImplementedException ();
2413 protected override Expression DoResolve (ResolveContext rc)
2415 throw new NotSupportedException ();
2418 public override void FlowAnalysis (FlowAnalysisContext fc)
2420 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2423 public override void Emit (EmitContext ec)
2427 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2433 // Unresolved type name expressions
2435 public abstract class ATypeNameExpression : FullNamedExpression
2438 protected TypeArguments targs;
2440 protected ATypeNameExpression (string name, Location l)
2446 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2453 protected ATypeNameExpression (string name, int arity, Location l)
2454 : this (name, new UnboundTypeArguments (arity), l)
2460 protected int Arity {
2462 return targs == null ? 0 : targs.Count;
2466 public bool HasTypeArguments {
2468 return targs != null && !targs.IsEmpty;
2472 public string Name {
2481 public TypeArguments TypeArguments {
2489 public override bool Equals (object obj)
2491 ATypeNameExpression atne = obj as ATypeNameExpression;
2492 return atne != null && atne.Name == Name &&
2493 (targs == null || targs.Equals (atne.targs));
2496 public override int GetHashCode ()
2498 return Name.GetHashCode ();
2501 // TODO: Move it to MemberCore
2502 public static string GetMemberType (MemberCore mc)
2508 if (mc is FieldBase)
2510 if (mc is MethodCore)
2512 if (mc is EnumMember)
2520 public override string GetSignatureForError ()
2522 if (targs != null) {
2523 return Name + "<" + targs.GetSignatureForError () + ">";
2529 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2533 /// SimpleName expressions are formed of a single word and only happen at the beginning
2534 /// of a dotted-name.
2536 public class SimpleName : ATypeNameExpression
2538 public SimpleName (string name, Location l)
2543 public SimpleName (string name, TypeArguments args, Location l)
2544 : base (name, args, l)
2548 public SimpleName (string name, int arity, Location l)
2549 : base (name, arity, l)
2553 public SimpleName GetMethodGroup ()
2555 return new SimpleName (Name, targs, loc);
2558 protected override Expression DoResolve (ResolveContext rc)
2560 return SimpleNameResolve (rc, null);
2563 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2565 return SimpleNameResolve (ec, right_side);
2568 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2570 if (ctx.CurrentType != null) {
2571 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2572 if (member != null) {
2573 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2578 var report = ctx.Module.Compiler.Report;
2580 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2581 if (retval != null) {
2582 report.SymbolRelatedToPreviousError (retval.Type);
2583 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2587 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2588 if (retval != null) {
2589 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2593 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2594 if (ns_candidates != null) {
2595 if (ctx is UsingAliasNamespace.AliasContext) {
2596 report.Error (246, loc,
2597 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2598 ns_candidates[0], Name);
2600 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2601 report.Error (246, loc,
2602 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2606 report.Error (246, loc,
2607 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2612 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2614 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2617 if (fne.Type != null && Arity > 0) {
2618 if (HasTypeArguments) {
2619 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2620 if (ct.ResolveAsType (mc) == null)
2626 return new GenericOpenTypeExpr (fne.Type, loc);
2630 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2632 if (!(fne is NamespaceExpression))
2636 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2637 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2638 mc.Module.Compiler.Report.Error (1980, Location,
2639 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2640 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2643 fne = new DynamicTypeExpr (loc);
2644 fne.ResolveAsType (mc);
2650 Error_TypeOrNamespaceNotFound (mc);
2654 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2656 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2659 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2661 int lookup_arity = Arity;
2662 bool errorMode = false;
2664 Block current_block = rc.CurrentBlock;
2665 INamedBlockVariable variable = null;
2666 bool variable_found = false;
2670 // Stage 1: binding to local variables or parameters
2672 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2674 if (current_block != null && lookup_arity == 0) {
2675 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2676 if (!variable.IsDeclared) {
2677 // We found local name in accessible block but it's not
2678 // initialized yet, maybe the user wanted to bind to something else
2680 variable_found = true;
2682 e = variable.CreateReferenceExpression (rc, loc);
2685 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2694 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2696 TypeSpec member_type = rc.CurrentType;
2697 for (; member_type != null; member_type = member_type.DeclaringType) {
2698 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2702 var me = e as MemberExpr;
2704 // The name matches a type, defer to ResolveAsTypeStep
2712 if (variable != null) {
2713 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2714 rc.Report.Error (844, loc,
2715 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2716 Name, me.GetSignatureForError ());
2720 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2721 // Leave it to overload resolution to report correct error
2723 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2724 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2727 // LAMESPEC: again, ignores InvocableOnly
2728 if (variable != null) {
2729 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2730 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2734 // MemberLookup does not check accessors availability, this is actually needed for properties only
2736 var pe = me as PropertyExpr;
2739 // Break as there is no other overload available anyway
2740 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2741 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2744 pe.Getter = pe.PropertyInfo.Get;
2746 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2749 pe.Setter = pe.PropertyInfo.Set;
2754 // TODO: It's used by EventExpr -> FieldExpr transformation only
2755 // TODO: Should go to MemberAccess
2756 me = me.ResolveMemberAccess (rc, null, null);
2760 me.SetTypeArguments (rc, targs);
2767 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2769 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2770 if (IsPossibleTypeOrNamespace (rc)) {
2771 if (variable != null) {
2772 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2773 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2776 return ResolveAsTypeOrNamespace (rc);
2780 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2784 mg.SetTypeArguments (rc, targs);
2790 if (variable_found) {
2791 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2794 var tparams = rc.CurrentTypeParameters;
2795 if (tparams != null) {
2796 if (tparams.Find (Name) != null) {
2797 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2802 var ct = rc.CurrentType;
2804 if (ct.MemberDefinition.TypeParametersCount > 0) {
2805 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2806 if (ctp.Name == Name) {
2807 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2813 ct = ct.DeclaringType;
2814 } while (ct != null);
2817 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2818 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2820 rc.Report.SymbolRelatedToPreviousError (e.Type);
2821 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2825 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2827 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2828 return ErrorExpression.Instance;
2832 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2834 if (e.Type.Arity != Arity) {
2835 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2839 if (e is TypeExpr) {
2840 // TypeExpression does not have correct location
2841 if (e is TypeExpression)
2842 e = new TypeExpression (e.Type, loc);
2848 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2851 return ErrorExpression.Instance;
2854 if (rc.Module.Evaluator != null) {
2855 var fi = rc.Module.Evaluator.LookupField (Name);
2857 return new FieldExpr (fi.Item1, loc);
2865 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2867 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2872 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2873 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2877 if (right_side != null) {
2878 e = e.ResolveLValue (ec, right_side);
2886 public override object Accept (StructuralVisitor visitor)
2888 return visitor.Visit (this);
2893 /// Represents a namespace or a type. The name of the class was inspired by
2894 /// section 10.8.1 (Fully Qualified Names).
2896 public abstract class FullNamedExpression : Expression
2898 protected override void CloneTo (CloneContext clonectx, Expression target)
2900 // Do nothing, most unresolved type expressions cannot be
2901 // resolved to different type
2904 public override bool ContainsEmitWithAwait ()
2909 public override Expression CreateExpressionTree (ResolveContext ec)
2911 throw new NotSupportedException ("ET");
2914 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2917 // This is used to resolve the expression as a type, a null
2918 // value will be returned if the expression is not a type
2921 public override TypeSpec ResolveAsType (IMemberContext mc)
2923 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2928 TypeExpr te = fne as TypeExpr;
2930 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2938 var dep = type.GetMissingDependencies ();
2940 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2943 if (type.Kind == MemberKind.Void) {
2944 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2948 // Obsolete checks cannot be done when resolving base context as they
2949 // require type dependencies to be set but we are in process of resolving them
2951 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2952 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2953 if (obsolete_attr != null && !mc.IsObsolete) {
2954 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2962 public override void Emit (EmitContext ec)
2964 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2965 GetSignatureForError ());
2970 /// Expression that evaluates to a type
2972 public abstract class TypeExpr : FullNamedExpression
2974 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2980 protected sealed override Expression DoResolve (ResolveContext ec)
2986 public override bool Equals (object obj)
2988 TypeExpr tobj = obj as TypeExpr;
2992 return Type == tobj.Type;
2995 public override int GetHashCode ()
2997 return Type.GetHashCode ();
3002 /// Fully resolved Expression that already evaluated to a type
3004 public class TypeExpression : TypeExpr
3006 public TypeExpression (TypeSpec t, Location l)
3009 eclass = ExprClass.Type;
3013 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
3019 public class NamespaceExpression : FullNamedExpression
3021 readonly Namespace ns;
3023 public NamespaceExpression (Namespace ns, Location loc)
3026 this.Type = InternalType.Namespace;
3027 this.eclass = ExprClass.Namespace;
3031 public Namespace Namespace {
3037 protected override Expression DoResolve (ResolveContext rc)
3039 throw new NotImplementedException ();
3042 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
3047 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3049 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3050 if (retval != null) {
3051 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3052 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3056 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3057 if (retval != null) {
3058 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3063 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3064 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3068 string assembly = null;
3069 string possible_name = Namespace.GetSignatureForError () + "." + name;
3071 // Only assembly unique name should be added
3072 switch (possible_name) {
3073 case "System.Drawing":
3074 case "System.Web.Services":
3077 case "System.Configuration":
3078 case "System.Data.Services":
3079 case "System.DirectoryServices":
3081 case "System.Net.Http":
3082 case "System.Numerics":
3083 case "System.Runtime.Caching":
3084 case "System.ServiceModel":
3085 case "System.Transactions":
3086 case "System.Web.Routing":
3087 case "System.Xml.Linq":
3089 assembly = possible_name;
3093 case "System.Linq.Expressions":
3094 assembly = "System.Core";
3097 case "System.Windows.Forms":
3098 case "System.Windows.Forms.Layout":
3099 assembly = "System.Windows.Forms";
3103 assembly = assembly == null ? "an" : "`" + assembly + "'";
3105 if (Namespace is GlobalRootNamespace) {
3106 ctx.Module.Compiler.Report.Error (400, loc,
3107 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3110 ctx.Module.Compiler.Report.Error (234, loc,
3111 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3112 name, GetSignatureForError (), assembly);
3116 public override string GetSignatureForError ()
3118 return ns.GetSignatureForError ();
3121 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3123 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3128 /// This class denotes an expression which evaluates to a member
3129 /// of a struct or a class.
3131 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3134 // An instance expression associated with this member, if it's a
3135 // non-static member
3137 public Expression InstanceExpression;
3140 /// The name of this member.
3142 public abstract string Name {
3147 // When base.member is used
3149 public bool IsBase {
3150 get { return InstanceExpression is BaseThis; }
3154 /// Whether this is an instance member.
3156 public abstract bool IsInstance {
3161 /// Whether this is a static member.
3163 public abstract bool IsStatic {
3167 public abstract string KindName {
3171 public bool NullShortCircuit { get; set; }
3173 protected abstract TypeSpec DeclaringType {
3177 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3179 return InstanceExpression.Type;
3184 // Converts best base candidate for virtual method starting from QueriedBaseType
3186 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3189 // Only when base.member is used and method is virtual
3195 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3196 // means for base.member access we have to find the closest match after we found best candidate
3198 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3200 // The method could already be what we are looking for
3202 TypeSpec[] targs = null;
3203 if (method.DeclaringType != InstanceExpression.Type) {
3205 // Candidate can have inflated MVAR parameters and we need to find
3206 // base match for original definition not inflated parameter types
3208 var parameters = method.Parameters;
3209 if (method.Arity > 0) {
3210 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3211 var inflated = method.DeclaringType as InflatedTypeSpec;
3212 if (inflated != null) {
3213 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3217 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3218 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3219 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3220 if (base_override.IsGeneric)
3221 targs = method.TypeArguments;
3223 method = base_override;
3228 // When base access is used inside anonymous method/iterator/etc we need to
3229 // get back to the context of original type. We do it by emiting proxy
3230 // method in original class and rewriting base call to this compiler
3231 // generated method call which does the actual base invocation. This may
3232 // introduce redundant storey but with `this' only but it's tricky to avoid
3233 // at this stage as we don't know what expressions follow base
3235 if (rc.CurrentAnonymousMethod != null) {
3236 if (targs == null && method.IsGeneric) {
3237 targs = method.TypeArguments;
3238 method = method.GetGenericMethodDefinition ();
3241 if (method.Parameters.HasArglist)
3242 throw new NotImplementedException ("__arglist base call proxy");
3244 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3246 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3247 // get/set member expressions second call would fail to proxy because left expression
3248 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3249 // FIXME: The async check is another hack but will probably fail with mutators
3250 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3251 InstanceExpression = new This (loc).Resolve (rc);
3255 method = method.MakeGenericMethod (rc, targs);
3259 // Only base will allow this invocation to happen.
3261 if (method.IsAbstract) {
3262 rc.Report.SymbolRelatedToPreviousError (method);
3263 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3269 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3271 if (InstanceExpression == null)
3274 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3275 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3276 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3281 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3283 if (InstanceExpression == null)
3286 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3289 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3291 var ct = rc.CurrentType;
3292 if (ct == qualifier)
3295 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3298 qualifier = qualifier.GetDefinition ();
3299 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3306 public override bool ContainsEmitWithAwait ()
3308 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3311 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3314 type = type.GetDefinition ();
3316 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3319 type = type.DeclaringType;
3320 } while (type != null);
3325 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3327 if (InstanceExpression != null) {
3328 InstanceExpression = InstanceExpression.Resolve (rc);
3329 CheckProtectedMemberAccess (rc, member);
3332 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3333 UnsafeError (rc, loc);
3336 var dep = member.GetMissingDependencies ();
3338 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3341 if (!rc.IsObsolete) {
3342 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3344 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3347 if (!(member is FieldSpec))
3348 member.MemberDefinition.SetIsUsed ();
3351 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3353 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3356 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3358 rc.Report.SymbolRelatedToPreviousError (member);
3359 rc.Report.Error (1540, loc,
3360 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3361 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3364 public override void FlowAnalysis (FlowAnalysisContext fc)
3366 if (InstanceExpression != null)
3367 InstanceExpression.FlowAnalysis (fc);
3370 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3372 if (!ResolveInstanceExpressionCore (rc, rhs))
3376 // Check intermediate value modification which won't have any effect
3378 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3379 var fexpr = InstanceExpression as FieldExpr;
3380 if (fexpr != null) {
3381 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3384 if (fexpr.IsStatic) {
3385 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3386 fexpr.GetSignatureForError ());
3388 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3389 fexpr.GetSignatureForError ());
3395 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3396 if (rc.CurrentInitializerVariable != null) {
3397 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3398 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3400 rc.Report.Error (1612, loc,
3401 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3402 InstanceExpression.GetSignatureForError ());
3408 var lvr = InstanceExpression as LocalVariableReference;
3411 if (!lvr.local_info.IsReadonly)
3414 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3415 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3422 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3425 if (InstanceExpression != null) {
3426 if (InstanceExpression is TypeExpr) {
3427 var t = InstanceExpression.Type;
3429 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3430 if (oa != null && !rc.IsObsolete) {
3431 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3434 t = t.DeclaringType;
3435 } while (t != null);
3437 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3438 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3439 rc.Report.Error (176, loc,
3440 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3441 GetSignatureForError ());
3445 InstanceExpression = null;
3451 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3452 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3453 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3454 rc.Report.Error (236, loc,
3455 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3456 GetSignatureForError ());
3458 var fe = this as FieldExpr;
3459 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3460 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3461 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3463 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3467 rc.Report.Error (120, loc,
3468 "An object reference is required to access non-static member `{0}'",
3469 GetSignatureForError ());
3473 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3477 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3478 rc.Report.Error (38, loc,
3479 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3480 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3483 InstanceExpression = new This (loc).Resolve (rc);
3487 var me = InstanceExpression as MemberExpr;
3489 me.ResolveInstanceExpressionCore (rc, rhs);
3491 var fe = me as FieldExpr;
3492 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3493 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3494 rc.Report.Warning (1690, 1, loc,
3495 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3496 me.GetSignatureForError ());
3503 // Additional checks for l-value member access
3506 if (InstanceExpression is UnboxCast) {
3507 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3514 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3516 if (left != null && !NullShortCircuit && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3517 ec.Report.Warning (1720, 1, left.Location,
3518 "Expression will always cause a `{0}'", "System.NullReferenceException");
3521 InstanceExpression = left;
3525 protected InstanceEmitter EmitInstance (EmitContext ec, bool prepare_for_load)
3527 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3528 inst.NullShortCircuit = NullShortCircuit;
3531 if (prepare_for_load)
3532 ec.Emit (OpCodes.Dup);
3537 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3540 public class ExtensionMethodCandidates
3542 readonly NamespaceContainer container;
3543 readonly IList<MethodSpec> methods;
3545 readonly IMemberContext context;
3547 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3549 this.context = context;
3550 this.methods = methods;
3551 this.container = nsContainer;
3552 this.index = lookupIndex;
3555 public NamespaceContainer Container {
3561 public IMemberContext Context {
3567 public int LookupIndex {
3573 public IList<MethodSpec> Methods {
3581 // Represents a group of extension method candidates for whole namespace
3583 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3585 ExtensionMethodCandidates candidates;
3586 public Expression ExtensionExpression;
3588 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3589 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3591 this.candidates = candidates;
3592 this.ExtensionExpression = extensionExpr;
3595 public override bool IsStatic {
3596 get { return true; }
3600 // For extension methodgroup we are not looking for base members but parent
3601 // namespace extension methods
3603 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3605 // TODO: candidates are null only when doing error reporting, that's
3606 // incorrect. We have to discover same extension methods in error mode
3607 if (candidates == null)
3610 int arity = type_arguments == null ? 0 : type_arguments.Count;
3612 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3613 if (candidates == null)
3616 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3619 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3621 // We are already here
3625 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3627 if (arguments == null)
3628 arguments = new Arguments (1);
3630 ExtensionExpression = ExtensionExpression.Resolve (ec);
3631 if (ExtensionExpression == null)
3634 var cand = candidates;
3635 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3636 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3638 // Restore candidates in case we are running in probing mode
3641 // Store resolved argument and restore original arguments
3643 // Clean-up modified arguments for error reporting
3644 arguments.RemoveAt (0);
3648 var me = ExtensionExpression as MemberExpr;
3650 me.ResolveInstanceExpression (ec, null);
3651 var fe = me as FieldExpr;
3653 fe.Spec.MemberDefinition.SetIsUsed ();
3656 InstanceExpression = null;
3660 #region IErrorHandler Members
3662 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3667 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3669 rc.Report.SymbolRelatedToPreviousError (best);
3670 rc.Report.Error (1928, loc,
3671 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3672 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3675 rc.Report.Error (1929, loc,
3676 "Extension method instance type `{0}' cannot be converted to `{1}'",
3677 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3683 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3688 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3697 /// MethodGroupExpr represents a group of method candidates which
3698 /// can be resolved to the best method overload
3700 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3702 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3704 protected IList<MemberSpec> Methods;
3705 MethodSpec best_candidate;
3706 TypeSpec best_candidate_return;
3707 protected TypeArguments type_arguments;
3709 SimpleName simple_name;
3710 protected TypeSpec queried_type;
3712 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3716 this.type = InternalType.MethodGroup;
3718 eclass = ExprClass.MethodGroup;
3719 queried_type = type;
3722 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3723 : this (new MemberSpec[] { m }, type, loc)
3729 public MethodSpec BestCandidate {
3731 return best_candidate;
3735 public TypeSpec BestCandidateReturnType {
3737 return best_candidate_return;
3741 public IList<MemberSpec> Candidates {
3747 protected override TypeSpec DeclaringType {
3749 return queried_type;
3753 public bool IsConditionallyExcluded {
3755 return Methods == Excluded;
3759 public override bool IsInstance {
3761 if (best_candidate != null)
3762 return !best_candidate.IsStatic;
3768 public override bool IsSideEffectFree {
3770 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3774 public override bool IsStatic {
3776 if (best_candidate != null)
3777 return best_candidate.IsStatic;
3783 public override string KindName {
3784 get { return "method"; }
3787 public override string Name {
3789 if (best_candidate != null)
3790 return best_candidate.Name;
3793 return Methods.First ().Name;
3800 // When best candidate is already know this factory can be used
3801 // to avoid expensive overload resolution to be called
3803 // NOTE: InstanceExpression has to be set manually
3805 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3807 return new MethodGroupExpr (best, queriedType, loc) {
3808 best_candidate = best,
3809 best_candidate_return = best.ReturnType
3813 public override string GetSignatureForError ()
3815 if (best_candidate != null)
3816 return best_candidate.GetSignatureForError ();
3818 return Methods.First ().GetSignatureForError ();
3821 public override Expression CreateExpressionTree (ResolveContext ec)
3823 if (best_candidate == null) {
3824 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3828 if (IsConditionallyExcluded)
3829 ec.Report.Error (765, loc,
3830 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3832 if (NullShortCircuit)
3833 Error_NullShortCircuitInsideExpressionTree (ec);
3835 return new TypeOfMethod (best_candidate, loc);
3838 protected override Expression DoResolve (ResolveContext ec)
3840 this.eclass = ExprClass.MethodGroup;
3842 if (InstanceExpression != null) {
3843 InstanceExpression = InstanceExpression.Resolve (ec);
3844 if (InstanceExpression == null)
3851 public override void Emit (EmitContext ec)
3853 throw new NotSupportedException ();
3856 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3858 var call = new CallEmitter ();
3859 call.InstanceExpression = InstanceExpression;
3860 call.NullShortCircuit = NullShortCircuit;
3862 call.EmitStatement (ec, best_candidate, arguments, loc);
3864 call.Emit (ec, best_candidate, arguments, loc);
3867 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3869 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3870 Name, target.GetSignatureForError ());
3873 public static bool IsExtensionMethodArgument (Expression expr)
3876 // LAMESPEC: No details about which expressions are not allowed
3878 return !(expr is TypeExpr) && !(expr is BaseThis);
3882 /// Find the Applicable Function Members (7.4.2.1)
3884 /// me: Method Group expression with the members to select.
3885 /// it might contain constructors or methods (or anything
3886 /// that maps to a method).
3888 /// Arguments: ArrayList containing resolved Argument objects.
3890 /// loc: The location if we want an error to be reported, or a Null
3891 /// location for "probing" purposes.
3893 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3894 /// that is the best match of me on Arguments.
3897 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3899 // TODO: causes issues with probing mode, remove explicit Kind check
3900 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3903 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3904 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3905 r.BaseMembersProvider = this;
3906 r.InstanceQualifier = this;
3909 if (cerrors != null)
3910 r.CustomErrors = cerrors;
3912 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3913 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3914 if (best_candidate == null) {
3915 if (!r.BestCandidateIsDynamic)
3918 if (simple_name != null && ec.IsStatic)
3919 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3924 // Overload resolver had to create a new method group, all checks bellow have already been executed
3925 if (r.BestCandidateNewMethodGroup != null)
3926 return r.BestCandidateNewMethodGroup;
3928 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3929 if (InstanceExpression != null) {
3930 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3931 InstanceExpression = null;
3933 if (simple_name != null && best_candidate.IsStatic) {
3934 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3937 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3941 ResolveInstanceExpression (ec, null);
3944 var base_override = CandidateToBaseOverride (ec, best_candidate);
3945 if (base_override == best_candidate) {
3946 best_candidate_return = r.BestCandidateReturnType;
3948 best_candidate = base_override;
3949 best_candidate_return = best_candidate.ReturnType;
3952 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3953 ConstraintChecker cc = new ConstraintChecker (ec);
3954 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3958 // Additional check for possible imported base override method which
3959 // could not be done during IsOverrideMethodBaseTypeAccessible
3961 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3962 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3963 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3964 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3967 // Speed up the check by not doing it on disallowed targets
3968 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3971 if (NullShortCircuit)
3972 best_candidate_return = LiftMemberType (ec, best_candidate_return);
3977 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3979 var fe = left as FieldExpr;
3982 // Using method-group on struct fields makes the struct assigned. I am not sure
3983 // why but that's what .net does
3985 fe.Spec.MemberDefinition.SetIsAssigned ();
3988 simple_name = original;
3989 return base.ResolveMemberAccess (ec, left, original);
3992 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3994 type_arguments = ta;
3997 #region IBaseMembersProvider Members
3999 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4001 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4004 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4006 if (queried_type == member.DeclaringType)
4009 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4010 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4014 // Extension methods lookup after ordinary methods candidates failed to apply
4016 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4018 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4021 if (!IsExtensionMethodArgument (InstanceExpression))
4024 int arity = type_arguments == null ? 0 : type_arguments.Count;
4025 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4026 if (methods == null)
4029 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4030 emg.SetTypeArguments (rc, type_arguments);
4037 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4039 public ConstructorInstanceQualifier (TypeSpec type)
4042 InstanceType = type;
4045 public TypeSpec InstanceType { get; private set; }
4047 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4049 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4053 public struct OverloadResolver
4056 public enum Restrictions
4060 ProbingOnly = 1 << 1,
4061 CovariantDelegate = 1 << 2,
4062 NoBaseMembers = 1 << 3,
4063 BaseMembersIncluded = 1 << 4,
4064 GetEnumeratorLookup = 1 << 5
4067 public interface IBaseMembersProvider
4069 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4070 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4071 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4074 public interface IErrorHandler
4076 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4077 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4078 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4079 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4082 public interface IInstanceQualifier
4084 TypeSpec InstanceType { get; }
4085 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4088 sealed class NoBaseMembers : IBaseMembersProvider
4090 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4092 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4097 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4102 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4108 struct AmbiguousCandidate
4110 public readonly MemberSpec Member;
4111 public readonly bool Expanded;
4112 public readonly AParametersCollection Parameters;
4114 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4117 Parameters = parameters;
4118 Expanded = expanded;
4123 IList<MemberSpec> members;
4124 TypeArguments type_arguments;
4125 IBaseMembersProvider base_provider;
4126 IErrorHandler custom_errors;
4127 IInstanceQualifier instance_qualifier;
4128 Restrictions restrictions;
4129 MethodGroupExpr best_candidate_extension_group;
4130 TypeSpec best_candidate_return_type;
4132 SessionReportPrinter lambda_conv_msgs;
4134 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4135 : this (members, null, restrictions, loc)
4139 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4142 if (members == null || members.Count == 0)
4143 throw new ArgumentException ("empty members set");
4145 this.members = members;
4147 type_arguments = targs;
4148 this.restrictions = restrictions;
4149 if (IsDelegateInvoke)
4150 this.restrictions |= Restrictions.NoBaseMembers;
4152 base_provider = NoBaseMembers.Instance;
4157 public IBaseMembersProvider BaseMembersProvider {
4159 return base_provider;
4162 base_provider = value;
4166 public bool BestCandidateIsDynamic { get; set; }
4169 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4171 public MethodGroupExpr BestCandidateNewMethodGroup {
4173 return best_candidate_extension_group;
4178 // Return type can be different between best candidate and closest override
4180 public TypeSpec BestCandidateReturnType {
4182 return best_candidate_return_type;
4186 public IErrorHandler CustomErrors {
4188 return custom_errors;
4191 custom_errors = value;
4195 TypeSpec DelegateType {
4197 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4198 throw new InternalErrorException ("Not running in delegate mode", loc);
4200 return members [0].DeclaringType;
4204 public IInstanceQualifier InstanceQualifier {
4206 return instance_qualifier;
4209 instance_qualifier = value;
4213 bool IsProbingOnly {
4215 return (restrictions & Restrictions.ProbingOnly) != 0;
4219 bool IsDelegateInvoke {
4221 return (restrictions & Restrictions.DelegateInvoke) != 0;
4228 // 7.4.3.3 Better conversion from expression
4229 // Returns : 1 if a->p is better,
4230 // 2 if a->q is better,
4231 // 0 if neither is better
4233 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4235 TypeSpec argument_type = a.Type;
4238 // If argument is an anonymous function
4240 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4242 // p and q are delegate types or expression tree types
4244 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4245 if (q.MemberDefinition != p.MemberDefinition) {
4250 // Uwrap delegate from Expression<T>
4252 q = TypeManager.GetTypeArguments (q)[0];
4253 p = TypeManager.GetTypeArguments (p)[0];
4256 var p_m = Delegate.GetInvokeMethod (p);
4257 var q_m = Delegate.GetInvokeMethod (q);
4260 // With identical parameter lists
4262 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4270 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4272 if (p.Kind == MemberKind.Void) {
4273 return q.Kind != MemberKind.Void ? 2 : 0;
4277 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4279 if (q.Kind == MemberKind.Void) {
4280 return p.Kind != MemberKind.Void ? 1: 0;
4283 var am = (AnonymousMethodExpression) a.Expr;
4286 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4287 // better conversion is performed between underlying types Y1 and Y2
4289 if (p.IsGenericTask || q.IsGenericTask) {
4290 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4291 q = q.TypeArguments[0];
4292 p = p.TypeArguments[0];
4298 // An inferred return type X exists for E in the context of that parameter list, and
4299 // the conversion from X to Y1 is better than the conversion from X to Y2
4301 argument_type = am.InferReturnType (ec, null, orig_q);
4302 if (argument_type == null) {
4303 // TODO: Can this be hit?
4307 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4308 argument_type = ec.BuiltinTypes.Object;
4312 if (argument_type == p)
4315 if (argument_type == q)
4319 // The parameters are identicial and return type is not void, use better type conversion
4320 // on return type to determine better one
4322 return BetterTypeConversion (ec, p, q);
4326 // 7.4.3.4 Better conversion from type
4328 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4330 if (p == null || q == null)
4331 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4333 switch (p.BuiltinType) {
4334 case BuiltinTypeSpec.Type.Int:
4335 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4338 case BuiltinTypeSpec.Type.Long:
4339 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4342 case BuiltinTypeSpec.Type.SByte:
4343 switch (q.BuiltinType) {
4344 case BuiltinTypeSpec.Type.Byte:
4345 case BuiltinTypeSpec.Type.UShort:
4346 case BuiltinTypeSpec.Type.UInt:
4347 case BuiltinTypeSpec.Type.ULong:
4351 case BuiltinTypeSpec.Type.Short:
4352 switch (q.BuiltinType) {
4353 case BuiltinTypeSpec.Type.UShort:
4354 case BuiltinTypeSpec.Type.UInt:
4355 case BuiltinTypeSpec.Type.ULong:
4359 case BuiltinTypeSpec.Type.Dynamic:
4360 // Dynamic is never better
4364 switch (q.BuiltinType) {
4365 case BuiltinTypeSpec.Type.Int:
4366 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4369 case BuiltinTypeSpec.Type.Long:
4370 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4373 case BuiltinTypeSpec.Type.SByte:
4374 switch (p.BuiltinType) {
4375 case BuiltinTypeSpec.Type.Byte:
4376 case BuiltinTypeSpec.Type.UShort:
4377 case BuiltinTypeSpec.Type.UInt:
4378 case BuiltinTypeSpec.Type.ULong:
4382 case BuiltinTypeSpec.Type.Short:
4383 switch (p.BuiltinType) {
4384 case BuiltinTypeSpec.Type.UShort:
4385 case BuiltinTypeSpec.Type.UInt:
4386 case BuiltinTypeSpec.Type.ULong:
4390 case BuiltinTypeSpec.Type.Dynamic:
4391 // Dynamic is never better
4395 // FIXME: handle lifted operators
4397 // TODO: this is expensive
4398 Expression p_tmp = new EmptyExpression (p);
4399 Expression q_tmp = new EmptyExpression (q);
4401 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4402 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4404 if (p_to_q && !q_to_p)
4407 if (q_to_p && !p_to_q)
4414 /// Determines "Better function" between candidate
4415 /// and the current best match
4418 /// Returns a boolean indicating :
4419 /// false if candidate ain't better
4420 /// true if candidate is better than the current best match
4422 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4423 MemberSpec best, AParametersCollection bparam, bool best_params)
4425 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4426 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4428 bool better_at_least_one = false;
4429 bool are_equivalent = true;
4430 int args_count = args == null ? 0 : args.Count;
4434 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4437 // Default arguments are ignored for better decision
4438 if (a.IsDefaultArgument)
4442 // When comparing named argument the parameter type index has to be looked up
4443 // in original parameter set (override version for virtual members)
4445 NamedArgument na = a as NamedArgument;
4447 int idx = cparam.GetParameterIndexByName (na.Name);
4448 ct = candidate_pd.Types[idx];
4449 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4450 ct = TypeManager.GetElementType (ct);
4452 idx = bparam.GetParameterIndexByName (na.Name);
4453 bt = best_pd.Types[idx];
4454 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4455 bt = TypeManager.GetElementType (bt);
4457 ct = candidate_pd.Types[c_idx];
4458 bt = best_pd.Types[b_idx];
4460 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4461 ct = TypeManager.GetElementType (ct);
4465 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4466 bt = TypeManager.GetElementType (bt);
4471 if (TypeSpecComparer.IsEqual (ct, bt))
4474 are_equivalent = false;
4475 int result = BetterExpressionConversion (ec, a, ct, bt);
4477 // for each argument, the conversion to 'ct' should be no worse than
4478 // the conversion to 'bt'.
4482 // for at least one argument, the conversion to 'ct' should be better than
4483 // the conversion to 'bt'.
4485 better_at_least_one = true;
4488 if (better_at_least_one)
4492 // Tie-breaking rules are applied only for equivalent parameter types
4494 if (!are_equivalent)
4498 // If candidate is applicable in its normal form and best has a params array and is applicable
4499 // only in its expanded form, then candidate is better
4501 if (candidate_params != best_params)
4502 return !candidate_params;
4505 // We have not reached end of parameters list due to params or used default parameters
4507 while (j < candidate_pd.Count && j < best_pd.Count) {
4508 var cand_param = candidate_pd.FixedParameters [j];
4509 var best_param = best_pd.FixedParameters [j];
4511 if (candidate_pd.Count == best_pd.Count) {
4515 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4516 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4518 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4519 return cand_param.HasDefaultValue;
4521 if (cand_param.HasDefaultValue) {
4527 // Neither is better when not all arguments are provided
4529 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4530 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4531 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4533 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4540 if (candidate_pd.Count != best_pd.Count)
4541 return candidate_pd.Count < best_pd.Count;
4544 // One is a non-generic method and second is a generic method, then non-generic is better
4546 if (best.IsGeneric != candidate.IsGeneric)
4547 return best.IsGeneric;
4550 // Both methods have the same number of parameters, and the parameters have equal types
4551 // Pick the "more specific" signature using rules over original (non-inflated) types
4553 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4554 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4556 bool specific_at_least_once = false;
4557 for (j = 0; j < args_count; ++j) {
4558 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4560 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4561 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4563 ct = candidate_def_pd.Types[j];
4564 bt = best_def_pd.Types[j];
4569 TypeSpec specific = MoreSpecific (ct, bt);
4573 specific_at_least_once = true;
4576 if (specific_at_least_once)
4582 static bool CheckInflatedArguments (MethodSpec ms)
4584 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4587 // Setup constraint checker for probing only
4588 ConstraintChecker cc = new ConstraintChecker (null);
4590 var mp = ms.Parameters.Types;
4591 for (int i = 0; i < mp.Length; ++i) {
4592 var type = mp[i] as InflatedTypeSpec;
4596 var targs = type.TypeArguments;
4597 if (targs.Length == 0)
4600 // TODO: Checking inflated MVAR arguments should be enough
4601 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4608 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4610 rc.Report.Error (1729, loc,
4611 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4612 type.GetSignatureForError (), argCount.ToString ());
4616 // Determines if the candidate method is applicable to the given set of arguments
4617 // There could be two different set of parameters for same candidate where one
4618 // is the closest override for default values and named arguments checks and second
4619 // one being the virtual base for the parameter types and modifiers.
4621 // A return value rates candidate method compatibility,
4622 // 0 = the best, int.MaxValue = the worst
4625 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)
4627 // Parameters of most-derived type used mainly for named and optional parameters
4628 var pd = pm.Parameters;
4630 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4631 // params modifier instead of most-derived type
4632 var cpd = ((IParametersMember) candidate).Parameters;
4633 int param_count = pd.Count;
4634 int optional_count = 0;
4636 Arguments orig_args = arguments;
4638 if (arg_count != param_count) {
4640 // No arguments expansion when doing exact match for delegates
4642 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4643 for (int i = 0; i < pd.Count; ++i) {
4644 if (pd.FixedParameters[i].HasDefaultValue) {
4645 optional_count = pd.Count - i;
4651 if (optional_count != 0) {
4652 // Readjust expected number when params used
4653 if (cpd.HasParams) {
4655 if (arg_count < param_count)
4657 } else if (arg_count > param_count) {
4658 int args_gap = System.Math.Abs (arg_count - param_count);
4659 return int.MaxValue - 10000 + args_gap;
4660 } else if (arg_count < param_count - optional_count) {
4661 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4662 return int.MaxValue - 10000 + args_gap;
4664 } else if (arg_count != param_count) {
4665 int args_gap = System.Math.Abs (arg_count - param_count);
4667 return int.MaxValue - 10000 + args_gap;
4668 if (arg_count < param_count - 1)
4669 return int.MaxValue - 10000 + args_gap;
4672 // Resize to fit optional arguments
4673 if (optional_count != 0) {
4674 if (arguments == null) {
4675 arguments = new Arguments (optional_count);
4677 // Have to create a new container, so the next run can do same
4678 var resized = new Arguments (param_count);
4679 resized.AddRange (arguments);
4680 arguments = resized;
4683 for (int i = arg_count; i < param_count; ++i)
4684 arguments.Add (null);
4688 if (arg_count > 0) {
4690 // Shuffle named arguments to the right positions if there are any
4692 if (arguments[arg_count - 1] is NamedArgument) {
4693 arg_count = arguments.Count;
4695 for (int i = 0; i < arg_count; ++i) {
4696 bool arg_moved = false;
4698 NamedArgument na = arguments[i] as NamedArgument;
4702 int index = pd.GetParameterIndexByName (na.Name);
4704 // Named parameter not found
4708 // already reordered
4713 if (index >= param_count) {
4714 // When using parameters which should not be available to the user
4715 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4718 arguments.Add (null);
4722 if (index == arg_count)
4725 temp = arguments [index];
4727 // The slot has been taken by positional argument
4728 if (temp != null && !(temp is NamedArgument))
4733 arguments = arguments.MarkOrderedArgument (na);
4737 if (arguments == orig_args) {
4738 arguments = new Arguments (orig_args.Count);
4739 arguments.AddRange (orig_args);
4742 arguments[index] = arguments[i];
4743 arguments[i] = temp;
4750 arg_count = arguments.Count;
4752 } else if (arguments != null) {
4753 arg_count = arguments.Count;
4757 // Don't do any expensive checks when the candidate cannot succeed
4759 if (arg_count != param_count && !cpd.HasParams)
4760 return (param_count - arg_count) * 2 + 1;
4762 var dep = candidate.GetMissingDependencies ();
4764 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4769 // 1. Handle generic method using type arguments when specified or type inference
4772 var ms = candidate as MethodSpec;
4773 if (ms != null && ms.IsGeneric) {
4774 if (type_arguments != null) {
4775 var g_args_count = ms.Arity;
4776 if (g_args_count != type_arguments.Count)
4777 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4779 if (type_arguments.Arguments != null)
4780 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4783 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4784 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4785 // candidate was found use the set to report more details about what was wrong with lambda body.
4786 // The general idea is to distinguish between code errors and errors caused by
4787 // trial-and-error type inference
4789 if (lambda_conv_msgs == null) {
4790 for (int i = 0; i < arg_count; i++) {
4791 Argument a = arguments[i];
4795 var am = a.Expr as AnonymousMethodExpression;
4797 if (lambda_conv_msgs == null)
4798 lambda_conv_msgs = new SessionReportPrinter ();
4800 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4805 var ti = new TypeInference (arguments);
4806 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4809 return ti.InferenceScore - 20000;
4812 // Clear any error messages when the result was success
4814 if (lambda_conv_msgs != null)
4815 lambda_conv_msgs.ClearSession ();
4817 if (i_args.Length != 0) {
4819 foreach (var ta in i_args) {
4820 if (!ta.IsAccessible (ec))
4821 return ti.InferenceScore - 10000;
4825 ms = ms.MakeGenericMethod (ec, i_args);
4830 // Type arguments constraints have to match for the method to be applicable
4832 if (!CheckInflatedArguments (ms)) {
4834 return int.MaxValue - 25000;
4838 // We have a generic return type and at same time the method is override which
4839 // means we have to also inflate override return type in case the candidate is
4840 // best candidate and override return type is different to base return type.
4842 // virtual Foo<T, object> with override Foo<T, dynamic>
4844 if (candidate != pm) {
4845 MethodSpec override_ms = (MethodSpec) pm;
4846 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4847 returnType = inflator.Inflate (returnType);
4849 returnType = ms.ReturnType;
4856 if (type_arguments != null)
4857 return int.MaxValue - 15000;
4863 // 2. Each argument has to be implicitly convertible to method parameter
4865 Parameter.Modifier p_mod = 0;
4868 for (int i = 0; i < arg_count; i++) {
4869 Argument a = arguments[i];
4871 var fp = pd.FixedParameters[i];
4872 if (!fp.HasDefaultValue) {
4873 arguments = orig_args;
4874 return arg_count * 2 + 2;
4878 // Get the default value expression, we can use the same expression
4879 // if the type matches
4881 Expression e = fp.DefaultValue;
4883 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4885 // Restore for possible error reporting
4886 for (int ii = i; ii < arg_count; ++ii)
4887 arguments.RemoveAt (i);
4889 return (arg_count - i) * 2 + 1;
4893 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4895 // LAMESPEC: Attributes can be mixed together with build-in priority
4897 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4898 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4899 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4900 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4901 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4902 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4906 arguments[i] = new Argument (e, Argument.AType.Default);
4910 if (p_mod != Parameter.Modifier.PARAMS) {
4911 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4913 } else if (!params_expanded_form) {
4914 params_expanded_form = true;
4915 pt = ((ElementTypeSpec) pt).Element;
4921 if (!params_expanded_form) {
4922 if (a.ArgType == Argument.AType.ExtensionType) {
4924 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4926 // LAMESPEC: or implicit type parameter conversion
4929 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4930 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4931 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4936 score = IsArgumentCompatible (ec, a, p_mod, pt);
4939 dynamicArgument = true;
4944 // It can be applicable in expanded form (when not doing exact match like for delegates)
4946 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4947 if (!params_expanded_form) {
4948 pt = ((ElementTypeSpec) pt).Element;
4952 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4955 params_expanded_form = true;
4956 dynamicArgument = true;
4957 } else if (score == 0 || arg_count > pd.Count) {
4958 params_expanded_form = true;
4963 if (params_expanded_form)
4965 return (arg_count - i) * 2 + score;
4970 // Restore original arguments for dynamic binder to keep the intention of original source code
4972 if (dynamicArgument)
4973 arguments = orig_args;
4978 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4980 if (e is Constant && e.Type == ptype)
4984 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4986 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4987 e = new MemberAccess (new MemberAccess (new MemberAccess (
4988 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4989 } else if (e is Constant) {
4991 // Handles int to int? conversions, DefaultParameterValue check
4993 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4997 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5000 return e.Resolve (ec);
5004 // Tests argument compatibility with the parameter
5005 // The possible return values are
5007 // 1 - modifier mismatch
5008 // 2 - type mismatch
5009 // -1 - dynamic binding required
5011 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5014 // Types have to be identical when ref or out modifer
5015 // is used and argument is not of dynamic type
5017 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5018 if (argument.Type != parameter) {
5020 // Do full equality check after quick path
5022 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
5024 // Using dynamic for ref/out parameter can still succeed at runtime
5026 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5033 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5035 // Using dynamic for ref/out parameter can still succeed at runtime
5037 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5044 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5048 // Use implicit conversion in all modes to return same candidates when the expression
5049 // is used as argument or delegate conversion
5051 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5052 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5059 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5061 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5063 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5066 var ac_p = p as ArrayContainer;
5068 var ac_q = q as ArrayContainer;
5072 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5073 if (specific == ac_p.Element)
5075 if (specific == ac_q.Element)
5077 } else if (p.IsGeneric && q.IsGeneric) {
5078 var pargs = TypeManager.GetTypeArguments (p);
5079 var qargs = TypeManager.GetTypeArguments (q);
5081 bool p_specific_at_least_once = false;
5082 bool q_specific_at_least_once = false;
5084 for (int i = 0; i < pargs.Length; i++) {
5085 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5086 if (specific == pargs[i])
5087 p_specific_at_least_once = true;
5088 if (specific == qargs[i])
5089 q_specific_at_least_once = true;
5092 if (p_specific_at_least_once && !q_specific_at_least_once)
5094 if (!p_specific_at_least_once && q_specific_at_least_once)
5102 // Find the best method from candidate list
5104 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5106 List<AmbiguousCandidate> ambiguous_candidates = null;
5108 MemberSpec best_candidate;
5109 Arguments best_candidate_args = null;
5110 bool best_candidate_params = false;
5111 bool best_candidate_dynamic = false;
5112 int best_candidate_rate;
5113 IParametersMember best_parameter_member = null;
5115 int args_count = args != null ? args.Count : 0;
5117 Arguments candidate_args = args;
5118 bool error_mode = false;
5119 MemberSpec invocable_member = null;
5122 best_candidate = null;
5123 best_candidate_rate = int.MaxValue;
5125 var type_members = members;
5127 for (int i = 0; i < type_members.Count; ++i) {
5128 var member = type_members[i];
5131 // Methods in a base class are not candidates if any method in a derived
5132 // class is applicable
5134 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5138 if (!member.IsAccessible (rc))
5141 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5144 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5145 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5150 IParametersMember pm = member as IParametersMember;
5153 // Will use it later to report ambiguity between best method and invocable member
5155 if (Invocation.IsMemberInvocable (member))
5156 invocable_member = member;
5162 // Overload resolution is looking for base member but using parameter names
5163 // and default values from the closest member. That means to do expensive lookup
5164 // for the closest override for virtual or abstract members
5166 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5167 var override_params = base_provider.GetOverrideMemberParameters (member);
5168 if (override_params != null)
5169 pm = override_params;
5173 // Check if the member candidate is applicable
5175 bool params_expanded_form = false;
5176 bool dynamic_argument = false;
5177 TypeSpec rt = pm.MemberType;
5178 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5180 if (lambda_conv_msgs != null)
5181 lambda_conv_msgs.EndSession ();
5184 // How does it score compare to others
5186 if (candidate_rate < best_candidate_rate) {
5188 // Fatal error (missing dependency), cannot continue
5189 if (candidate_rate < 0)
5192 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5193 // Only parameterless methods are considered
5195 best_candidate_rate = candidate_rate;
5196 best_candidate = member;
5197 best_candidate_args = candidate_args;
5198 best_candidate_params = params_expanded_form;
5199 best_candidate_dynamic = dynamic_argument;
5200 best_parameter_member = pm;
5201 best_candidate_return_type = rt;
5203 } else if (candidate_rate == 0) {
5205 // The member look is done per type for most operations but sometimes
5206 // it's not possible like for binary operators overload because they
5207 // are unioned between 2 sides
5209 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5210 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5215 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5217 // We pack all interface members into top level type which makes the overload resolution
5218 // more complicated for interfaces. We compensate it by removing methods with same
5219 // signature when building the cache hence this path should not really be hit often
5222 // interface IA { void Foo (int arg); }
5223 // interface IB : IA { void Foo (params int[] args); }
5225 // IB::Foo is the best overload when calling IB.Foo (1)
5228 if (ambiguous_candidates != null) {
5229 foreach (var amb_cand in ambiguous_candidates) {
5230 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5239 ambiguous_candidates = null;
5242 // Is the new candidate better
5243 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5247 best_candidate = member;
5248 best_candidate_args = candidate_args;
5249 best_candidate_params = params_expanded_form;
5250 best_candidate_dynamic = dynamic_argument;
5251 best_parameter_member = pm;
5252 best_candidate_return_type = rt;
5254 // It's not better but any other found later could be but we are not sure yet
5255 if (ambiguous_candidates == null)
5256 ambiguous_candidates = new List<AmbiguousCandidate> ();
5258 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5262 // Restore expanded arguments
5263 candidate_args = args;
5265 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5268 // We've found exact match
5270 if (best_candidate_rate == 0)
5274 // Try extension methods lookup when no ordinary method match was found and provider enables it
5277 var emg = base_provider.LookupExtensionMethod (rc);
5279 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5281 best_candidate_extension_group = emg;
5282 return (T) (MemberSpec) emg.BestCandidate;
5287 // Don't run expensive error reporting mode for probing
5294 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5297 lambda_conv_msgs = null;
5302 // No best member match found, report an error
5304 if (best_candidate_rate != 0 || error_mode) {
5305 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5309 if (best_candidate_dynamic) {
5310 if (args[0].ArgType == Argument.AType.ExtensionType) {
5311 rc.Report.Error (1973, loc,
5312 "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",
5313 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5317 // Check type constraints only when explicit type arguments are used
5319 if (best_candidate.IsGeneric && type_arguments != null) {
5320 MethodSpec bc = best_candidate as MethodSpec;
5321 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5322 ConstraintChecker cc = new ConstraintChecker (rc);
5323 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5327 BestCandidateIsDynamic = true;
5332 // These flags indicates we are running delegate probing conversion. No need to
5333 // do more expensive checks
5335 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5336 return (T) best_candidate;
5338 if (ambiguous_candidates != null) {
5340 // Now check that there are no ambiguities i.e the selected method
5341 // should be better than all the others
5343 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5344 var candidate = ambiguous_candidates [ix];
5346 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5347 var ambiguous = candidate.Member;
5348 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5349 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5350 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5351 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5352 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5355 return (T) best_candidate;
5360 if (invocable_member != null && !IsProbingOnly) {
5361 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5362 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5363 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5364 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5368 // And now check if the arguments are all
5369 // compatible, perform conversions if
5370 // necessary etc. and return if everything is
5373 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5376 if (best_candidate == null)
5380 // Don't run possibly expensive checks in probing mode
5382 if (!IsProbingOnly && !rc.IsInProbingMode) {
5384 // Check ObsoleteAttribute on the best method
5386 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5387 if (oa != null && !rc.IsObsolete)
5388 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5390 best_candidate.MemberDefinition.SetIsUsed ();
5393 args = best_candidate_args;
5394 return (T) best_candidate;
5397 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5399 return ResolveMember<MethodSpec> (rc, ref args);
5402 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5403 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5405 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5408 if (a.Type == InternalType.ErrorType)
5411 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5412 ec.Report.SymbolRelatedToPreviousError (method);
5413 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5414 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5415 TypeManager.CSharpSignature (method));
5418 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5419 TypeManager.CSharpSignature (method));
5420 } else if (IsDelegateInvoke) {
5421 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5422 DelegateType.GetSignatureForError ());
5424 ec.Report.SymbolRelatedToPreviousError (method);
5425 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5426 method.GetSignatureForError ());
5429 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5431 string index = (idx + 1).ToString ();
5432 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5433 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5434 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5435 index, Parameter.GetModifierSignature (a.Modifier));
5437 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5438 index, Parameter.GetModifierSignature (mod));
5440 string p1 = a.GetSignatureForError ();
5441 string p2 = paramType.GetSignatureForError ();
5444 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5445 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5448 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5449 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5450 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5453 ec.Report.Error (1503, a.Expr.Location,
5454 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5459 // We have failed to find exact match so we return error info about the closest match
5461 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5463 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5464 int arg_count = args == null ? 0 : args.Count;
5466 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5467 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5468 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5472 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5477 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5478 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5479 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5483 // For candidates which match on parameters count report more details about incorrect arguments
5486 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5487 // Reject any inaccessible member
5488 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5489 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5490 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5494 var ms = best_candidate as MethodSpec;
5495 if (ms != null && ms.IsGeneric) {
5496 bool constr_ok = true;
5497 if (ms.TypeArguments != null)
5498 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5500 if (ta_count == 0 && ms.TypeArguments == null) {
5501 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5505 rc.Report.Error (411, loc,
5506 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5507 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5514 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5520 // We failed to find any method with correct argument count, report best candidate
5522 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5525 if (best_candidate.Kind == MemberKind.Constructor) {
5526 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5527 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5528 } else if (IsDelegateInvoke) {
5529 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5530 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5531 DelegateType.GetSignatureForError (), arg_count.ToString ());
5533 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5534 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5535 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5536 name, arg_count.ToString ());
5540 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5542 var p = ((IParametersMember)best_candidate).Parameters;
5547 for (int i = p.Count - 1; i != 0; --i) {
5548 var fp = p.FixedParameters [i];
5549 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5559 foreach (var arg in args) {
5560 var na = arg as NamedArgument;
5564 if (na.Name == name) {
5573 return args.Count + 1 == pm.Parameters.Count;
5576 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5578 var pd = pm.Parameters;
5579 var cpd = ((IParametersMember) member).Parameters;
5580 var ptypes = cpd.Types;
5582 Parameter.Modifier p_mod = 0;
5584 int a_idx = 0, a_pos = 0;
5586 ArrayInitializer params_initializers = null;
5587 bool has_unsafe_arg = pm.MemberType.IsPointer;
5588 int arg_count = args == null ? 0 : args.Count;
5590 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5595 if (p_mod != Parameter.Modifier.PARAMS) {
5596 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5598 has_unsafe_arg |= pt.IsPointer;
5600 if (p_mod == Parameter.Modifier.PARAMS) {
5601 if (chose_params_expanded) {
5602 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5603 pt = TypeManager.GetElementType (pt);
5609 // Types have to be identical when ref or out modifer is used
5611 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5612 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5615 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5621 NamedArgument na = a as NamedArgument;
5623 int name_index = pd.GetParameterIndexByName (na.Name);
5624 if (name_index < 0 || name_index >= pd.Count) {
5625 if (IsDelegateInvoke) {
5626 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5627 ec.Report.Error (1746, na.Location,
5628 "The delegate `{0}' does not contain a parameter named `{1}'",
5629 DelegateType.GetSignatureForError (), na.Name);
5631 ec.Report.SymbolRelatedToPreviousError (member);
5632 ec.Report.Error (1739, na.Location,
5633 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5634 TypeManager.CSharpSignature (member), na.Name);
5636 } else if (args[name_index] != a && args[name_index] != null) {
5637 if (IsDelegateInvoke)
5638 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5640 ec.Report.SymbolRelatedToPreviousError (member);
5642 ec.Report.Error (1744, na.Location,
5643 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5648 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5651 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5652 custom_errors.NoArgumentMatch (ec, member);
5657 if (a.ArgType == Argument.AType.ExtensionType) {
5658 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5661 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5663 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5666 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5673 // Convert params arguments to an array initializer
5675 if (params_initializers != null) {
5676 // we choose to use 'a.Expr' rather than 'conv' so that
5677 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5678 params_initializers.Add (a.Expr);
5679 args.RemoveAt (a_idx--);
5685 // Update the argument with the implicit conversion
5689 if (a_idx != arg_count) {
5690 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5695 // Fill not provided arguments required by params modifier
5697 if (params_initializers == null && arg_count + 1 == pd.Count) {
5699 args = new Arguments (1);
5701 pt = ptypes[pd.Count - 1];
5702 pt = TypeManager.GetElementType (pt);
5703 has_unsafe_arg |= pt.IsPointer;
5704 params_initializers = new ArrayInitializer (0, loc);
5708 // Append an array argument with all params arguments
5710 if (params_initializers != null) {
5711 args.Add (new Argument (
5712 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5716 if (has_unsafe_arg && !ec.IsUnsafe) {
5717 Expression.UnsafeError (ec, loc);
5721 // We could infer inaccesible type arguments
5723 if (type_arguments == null && member.IsGeneric) {
5724 var ms = (MethodSpec) member;
5725 foreach (var ta in ms.TypeArguments) {
5726 if (!ta.IsAccessible (ec)) {
5727 ec.Report.SymbolRelatedToPreviousError (ta);
5728 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5738 public class ConstantExpr : MemberExpr
5740 readonly ConstSpec constant;
5742 public ConstantExpr (ConstSpec constant, Location loc)
5744 this.constant = constant;
5748 public override string Name {
5749 get { throw new NotImplementedException (); }
5752 public override string KindName {
5753 get { return "constant"; }
5756 public override bool IsInstance {
5757 get { return !IsStatic; }
5760 public override bool IsStatic {
5761 get { return true; }
5764 protected override TypeSpec DeclaringType {
5765 get { return constant.DeclaringType; }
5768 public override Expression CreateExpressionTree (ResolveContext ec)
5770 throw new NotSupportedException ("ET");
5773 protected override Expression DoResolve (ResolveContext rc)
5775 ResolveInstanceExpression (rc, null);
5776 DoBestMemberChecks (rc, constant);
5778 var c = constant.GetConstant (rc);
5780 // Creates reference expression to the constant value
5781 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5784 public override void Emit (EmitContext ec)
5786 throw new NotSupportedException ();
5789 public override string GetSignatureForError ()
5791 return constant.GetSignatureForError ();
5794 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5796 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5801 // Fully resolved expression that references a Field
5803 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5805 protected FieldSpec spec;
5806 VariableInfo variable_info;
5808 LocalTemporary temp;
5811 protected FieldExpr (Location l)
5816 public FieldExpr (FieldSpec spec, Location loc)
5821 type = spec.MemberType;
5824 public FieldExpr (FieldBase fi, Location l)
5831 public override string Name {
5837 public bool IsHoisted {
5839 IVariableReference hv = InstanceExpression as IVariableReference;
5840 return hv != null && hv.IsHoisted;
5844 public override bool IsInstance {
5846 return !spec.IsStatic;
5850 public override bool IsStatic {
5852 return spec.IsStatic;
5856 public override string KindName {
5857 get { return "field"; }
5860 public FieldSpec Spec {
5866 protected override TypeSpec DeclaringType {
5868 return spec.DeclaringType;
5872 public VariableInfo VariableInfo {
5874 return variable_info;
5880 public override string GetSignatureForError ()
5882 return spec.GetSignatureForError ();
5885 public bool IsMarshalByRefAccess (ResolveContext rc)
5887 // Checks possible ldflda of field access expression
5888 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5889 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5890 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5893 public void SetHasAddressTaken ()
5895 IVariableReference vr = InstanceExpression as IVariableReference;
5897 vr.SetHasAddressTaken ();
5901 protected override void CloneTo (CloneContext clonectx, Expression target)
5903 var t = (FieldExpr) target;
5905 if (InstanceExpression != null)
5906 t.InstanceExpression = InstanceExpression.Clone (clonectx);
5909 public override Expression CreateExpressionTree (ResolveContext ec)
5911 if (NullShortCircuit) {
5912 Error_NullShortCircuitInsideExpressionTree (ec);
5915 return CreateExpressionTree (ec, true);
5918 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5921 Expression instance;
5923 if (InstanceExpression == null) {
5924 instance = new NullLiteral (loc);
5925 } else if (convertInstance) {
5926 instance = InstanceExpression.CreateExpressionTree (ec);
5928 args = new Arguments (1);
5929 args.Add (new Argument (InstanceExpression));
5930 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5933 args = Arguments.CreateForExpressionTree (ec, null,
5935 CreateTypeOfExpression ());
5937 return CreateExpressionFactoryCall (ec, "Field", args);
5940 public Expression CreateTypeOfExpression ()
5942 return new TypeOfField (spec, loc);
5945 protected override Expression DoResolve (ResolveContext ec)
5947 spec.MemberDefinition.SetIsUsed ();
5949 return DoResolve (ec, null);
5952 Expression DoResolve (ResolveContext ec, Expression rhs)
5954 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5957 if (ResolveInstanceExpression (ec, rhs)) {
5958 // Resolve the field's instance expression while flow analysis is turned
5959 // off: when accessing a field "a.b", we must check whether the field
5960 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5962 if (lvalue_instance) {
5963 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5965 Expression right_side =
5966 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5968 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5970 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5973 if (InstanceExpression == null)
5977 DoBestMemberChecks (ec, spec);
5980 var fb = spec as FixedFieldSpec;
5981 IVariableReference var = InstanceExpression as IVariableReference;
5984 IFixedExpression fe = InstanceExpression as IFixedExpression;
5985 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5986 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5989 if (InstanceExpression.eclass != ExprClass.Variable) {
5990 ec.Report.SymbolRelatedToPreviousError (spec);
5991 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5992 TypeManager.GetFullNameSignature (spec));
5993 } else if (var != null && var.IsHoisted) {
5994 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5997 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6001 // Set flow-analysis variable info for struct member access. It will be check later
6002 // for precise error reporting
6004 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6005 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6008 if (NullShortCircuit) {
6009 type = LiftMemberType (ec, type);
6011 if (InstanceExpression.IsNull)
6012 return Constant.CreateConstantFromValue (type, null, loc);
6015 eclass = ExprClass.Variable;
6019 public void SetFieldAssigned (FlowAnalysisContext fc)
6024 bool lvalue_instance = spec.DeclaringType.IsStruct;
6025 if (lvalue_instance) {
6026 var var = InstanceExpression as IVariableReference;
6027 if (var != null && var.VariableInfo != null) {
6028 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6032 var fe = InstanceExpression as FieldExpr;
6034 Expression instance;
6037 instance = fe.InstanceExpression;
6038 var fe_instance = instance as FieldExpr;
6039 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6040 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6041 var var = InstanceExpression as IVariableReference;
6042 if (var != null && var.VariableInfo == null) {
6043 var var_inst = instance as IVariableReference;
6044 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6045 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6049 if (fe_instance != null) {
6058 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6059 instance.FlowAnalysis (fc);
6061 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6062 InstanceExpression.FlowAnalysis (fc);
6066 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6068 // The return value is always null. Returning a value simplifies calling code.
6070 if (right_side == EmptyExpression.OutAccess) {
6072 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6073 GetSignatureForError ());
6075 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6076 GetSignatureForError ());
6082 if (right_side == EmptyExpression.LValueMemberAccess) {
6083 // Already reported as CS1648/CS1650
6087 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6089 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6090 GetSignatureForError ());
6092 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6093 GetSignatureForError ());
6099 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6100 GetSignatureForError ());
6102 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6103 GetSignatureForError ());
6109 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6111 if (NullShortCircuit)
6112 throw new NotSupportedException ("null propagating operator assignment");
6114 if (spec is FixedFieldSpec) {
6115 // It could be much better error message but we want to be error compatible
6116 Error_ValueAssignment (ec, right_side);
6119 Expression e = DoResolve (ec, right_side);
6124 spec.MemberDefinition.SetIsAssigned ();
6126 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6127 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6128 ec.Report.Warning (420, 1, loc,
6129 "`{0}': A volatile field references will not be treated as volatile",
6130 spec.GetSignatureForError ());
6133 if (spec.IsReadOnly) {
6134 // InitOnly fields can only be assigned in constructors or initializers
6135 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6136 return Error_AssignToReadonly (ec, right_side);
6138 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6140 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6141 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6142 return Error_AssignToReadonly (ec, right_side);
6143 // static InitOnly fields cannot be assigned-to in an instance constructor
6144 if (IsStatic && !ec.IsStatic)
6145 return Error_AssignToReadonly (ec, right_side);
6146 // instance constructors can't modify InitOnly fields of other instances of the same type
6147 if (!IsStatic && !(InstanceExpression is This))
6148 return Error_AssignToReadonly (ec, right_side);
6152 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6153 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6154 ec.Report.Warning (197, 1, loc,
6155 "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",
6156 GetSignatureForError ());
6159 eclass = ExprClass.Variable;
6163 public override void FlowAnalysis (FlowAnalysisContext fc)
6165 var var = InstanceExpression as IVariableReference;
6167 var vi = var.VariableInfo;
6168 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6169 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6173 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6177 base.FlowAnalysis (fc);
6180 public override int GetHashCode ()
6182 return spec.GetHashCode ();
6185 public bool IsFixed {
6188 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6190 IVariableReference variable = InstanceExpression as IVariableReference;
6191 if (variable != null)
6192 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6194 IFixedExpression fe = InstanceExpression as IFixedExpression;
6195 return fe != null && fe.IsFixed;
6199 public override bool Equals (object obj)
6201 FieldExpr fe = obj as FieldExpr;
6205 if (spec != fe.spec)
6208 if (InstanceExpression == null || fe.InstanceExpression == null)
6211 return InstanceExpression.Equals (fe.InstanceExpression);
6214 public void Emit (EmitContext ec, bool leave_copy)
6216 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6220 ec.Emit (OpCodes.Volatile);
6222 ec.Emit (OpCodes.Ldsfld, spec);
6226 ie = EmitInstance (ec, false);
6228 ie = new InstanceEmitter ();
6230 // Optimization for build-in types
6231 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6232 ec.EmitLoadFromPtr (type);
6234 var ff = spec as FixedFieldSpec;
6236 ec.Emit (OpCodes.Ldflda, spec);
6237 ec.Emit (OpCodes.Ldflda, ff.Element);
6240 ec.Emit (OpCodes.Volatile);
6242 ec.Emit (OpCodes.Ldfld, spec);
6244 if (NullShortCircuit) {
6245 ie.EmitResultLift (ec, spec.MemberType, false);
6252 ec.Emit (OpCodes.Dup);
6254 temp = new LocalTemporary (this.Type);
6260 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6262 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6263 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6268 if (NullShortCircuit)
6269 throw new NotImplementedException ("null operator assignment");
6271 if (has_await_source)
6272 source = source.EmitToField (ec);
6274 EmitInstance (ec, prepared);
6279 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6280 ec.Emit (OpCodes.Dup);
6282 temp = new LocalTemporary (this.Type);
6287 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6288 ec.Emit (OpCodes.Volatile);
6290 spec.MemberDefinition.SetIsAssigned ();
6293 ec.Emit (OpCodes.Stsfld, spec);
6295 ec.Emit (OpCodes.Stfld, spec);
6297 if (ec.NotifyEvaluatorOnStore) {
6299 throw new NotImplementedException ("instance field write");
6302 ec.Emit (OpCodes.Dup);
6304 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6315 // Emits store to field with prepared values on stack
6317 public void EmitAssignFromStack (EmitContext ec)
6320 ec.Emit (OpCodes.Stsfld, spec);
6322 ec.Emit (OpCodes.Stfld, spec);
6326 public override void Emit (EmitContext ec)
6331 public override void EmitSideEffect (EmitContext ec)
6333 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6335 if (is_volatile) // || is_marshal_by_ref ())
6336 base.EmitSideEffect (ec);
6339 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6341 if ((mode & AddressOp.Store) != 0)
6342 spec.MemberDefinition.SetIsAssigned ();
6343 if ((mode & AddressOp.Load) != 0)
6344 spec.MemberDefinition.SetIsUsed ();
6347 // Handle initonly fields specially: make a copy and then
6348 // get the address of the copy.
6351 if (spec.IsReadOnly){
6353 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6365 var temp = ec.GetTemporaryLocal (type);
6366 ec.Emit (OpCodes.Stloc, temp);
6367 ec.Emit (OpCodes.Ldloca, temp);
6373 ec.Emit (OpCodes.Ldsflda, spec);
6376 EmitInstance (ec, false);
6377 ec.Emit (OpCodes.Ldflda, spec);
6381 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6383 return MakeExpression (ctx);
6386 public override SLE.Expression MakeExpression (BuilderContext ctx)
6389 return base.MakeExpression (ctx);
6391 return SLE.Expression.Field (
6392 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6393 spec.GetMetaInfo ());
6397 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6399 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6405 // Expression that evaluates to a Property.
6407 // This is not an LValue because we need to re-write the expression. We
6408 // can not take data from the stack and store it.
6410 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6412 Arguments arguments;
6414 public PropertyExpr (PropertySpec spec, Location l)
6417 best_candidate = spec;
6418 type = spec.MemberType;
6423 protected override Arguments Arguments {
6432 protected override TypeSpec DeclaringType {
6434 return best_candidate.DeclaringType;
6438 public override string Name {
6440 return best_candidate.Name;
6444 public override bool IsInstance {
6450 public override bool IsStatic {
6452 return best_candidate.IsStatic;
6456 public override string KindName {
6457 get { return "property"; }
6460 public PropertySpec PropertyInfo {
6462 return best_candidate;
6468 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6470 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6473 var args_count = arguments == null ? 0 : arguments.Count;
6474 if (args_count != body.Parameters.Count && args_count == 0)
6477 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6478 mg.InstanceExpression = InstanceExpression;
6483 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6485 return new PropertyExpr (spec, loc) {
6491 public override Expression CreateExpressionTree (ResolveContext ec)
6493 if (NullShortCircuit) {
6494 Error_NullShortCircuitInsideExpressionTree (ec);
6498 if (IsSingleDimensionalArrayLength ()) {
6499 args = new Arguments (1);
6500 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6501 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6504 args = new Arguments (2);
6505 if (InstanceExpression == null)
6506 args.Add (new Argument (new NullLiteral (loc)));
6508 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6509 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6510 return CreateExpressionFactoryCall (ec, "Property", args);
6513 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6515 DoResolveLValue (rc, null);
6516 return new TypeOfMethod (Setter, loc);
6519 public override string GetSignatureForError ()
6521 return best_candidate.GetSignatureForError ();
6524 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6527 return base.MakeExpression (ctx);
6529 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6533 public override SLE.Expression MakeExpression (BuilderContext ctx)
6536 return base.MakeExpression (ctx);
6538 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6542 void Error_PropertyNotValid (ResolveContext ec)
6544 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6545 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6546 GetSignatureForError ());
6549 bool IsSingleDimensionalArrayLength ()
6551 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6554 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6555 return ac != null && ac.Rank == 1;
6558 public override void Emit (EmitContext ec, bool leave_copy)
6561 // Special case: length of single dimension array property is turned into ldlen
6563 if (IsSingleDimensionalArrayLength ()) {
6564 var inst = EmitInstance (ec, false);
6566 ec.Emit (OpCodes.Ldlen);
6567 ec.Emit (OpCodes.Conv_I4);
6569 if (NullShortCircuit)
6570 inst.EmitResultLift (ec, ec.BuiltinTypes.Int, false);
6575 base.Emit (ec, leave_copy);
6578 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6581 LocalTemporary await_source_arg = null;
6583 if (isCompound && !(source is DynamicExpressionStatement)) {
6584 emitting_compound_assignment = true;
6587 if (has_await_arguments) {
6588 await_source_arg = new LocalTemporary (Type);
6589 await_source_arg.Store (ec);
6591 args = new Arguments (1);
6592 args.Add (new Argument (await_source_arg));
6595 temp = await_source_arg;
6598 has_await_arguments = false;
6603 ec.Emit (OpCodes.Dup);
6604 temp = new LocalTemporary (this.Type);
6609 args = arguments ?? new Arguments (1);
6613 temp = new LocalTemporary (this.Type);
6615 args.Add (new Argument (temp));
6617 args.Add (new Argument (source));
6621 emitting_compound_assignment = false;
6623 var call = new CallEmitter ();
6624 call.InstanceExpression = InstanceExpression;
6626 call.InstanceExpressionOnStack = true;
6627 if (NullShortCircuit) {
6628 call.NullShortCircuit = true;
6629 call.NullOperatorLabel = null_operator_label;
6633 call.Emit (ec, Setter, args, loc);
6635 call.EmitStatement (ec, Setter, args, loc);
6642 if (await_source_arg != null) {
6643 await_source_arg.Release (ec);
6647 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6649 eclass = ExprClass.PropertyAccess;
6651 if (best_candidate.IsNotCSharpCompatible) {
6652 Error_PropertyNotValid (rc);
6655 ResolveInstanceExpression (rc, right_side);
6657 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6658 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6659 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6661 type = p.MemberType;
6665 DoBestMemberChecks (rc, best_candidate);
6667 // Handling of com-imported properties with any number of default property parameters
6668 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6669 var p = best_candidate.Get.Parameters;
6670 arguments = new Arguments (p.Count);
6671 for (int i = 0; i < p.Count; ++i) {
6672 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6674 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6675 var p = best_candidate.Set.Parameters;
6676 arguments = new Arguments (p.Count - 1);
6677 for (int i = 0; i < p.Count - 1; ++i) {
6678 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6685 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6687 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6691 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6693 // getter and setter can be different for base calls
6694 MethodSpec getter, setter;
6695 protected T best_candidate;
6697 protected LocalTemporary temp;
6698 protected bool emitting_compound_assignment;
6699 protected bool has_await_arguments;
6700 protected Label null_operator_label;
6702 protected PropertyOrIndexerExpr (Location l)
6709 protected abstract Arguments Arguments { get; set; }
6711 public MethodSpec Getter {
6720 public MethodSpec Setter {
6731 protected override Expression DoResolve (ResolveContext ec)
6733 if (eclass == ExprClass.Unresolved) {
6734 var expr = OverloadResolve (ec, null);
6738 if (NullShortCircuit && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6739 type = LiftMemberType (ec, type);
6743 return expr.Resolve (ec);
6746 if (!ResolveGetter (ec))
6752 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6754 if (NullShortCircuit)
6755 throw new NotSupportedException ("null propagating operator assignment");
6757 if (right_side == EmptyExpression.OutAccess) {
6758 // TODO: best_candidate can be null at this point
6759 INamedBlockVariable variable = null;
6760 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6761 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6762 best_candidate.Name);
6764 right_side.DoResolveLValue (ec, this);
6769 if (eclass == ExprClass.Unresolved) {
6770 var expr = OverloadResolve (ec, right_side);
6775 return expr.ResolveLValue (ec, right_side);
6777 ResolveInstanceExpression (ec, right_side);
6780 if (!ResolveSetter (ec))
6783 if (NullShortCircuit && ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6784 var lifted_type = LiftMemberType (ec, type);
6785 if (type != lifted_type) {
6786 // TODO: Workaround to disable codegen for now
6787 return Nullable.Wrap.Create (this, lifted_type);
6795 // Implements the IAssignMethod interface for assignments
6797 public virtual void Emit (EmitContext ec, bool leave_copy)
6799 var call = new CallEmitter ();
6800 call.NullShortCircuit = NullShortCircuit;
6801 call.InstanceExpression = InstanceExpression;
6802 if (has_await_arguments)
6803 call.HasAwaitArguments = true;
6805 call.DuplicateArguments = emitting_compound_assignment;
6807 call.Emit (ec, Getter, Arguments, loc);
6809 if (call.HasAwaitArguments) {
6810 InstanceExpression = call.InstanceExpression;
6811 Arguments = call.EmittedArguments;
6812 has_await_arguments = true;
6815 if (NullShortCircuit && emitting_compound_assignment)
6816 null_operator_label = call.NullOperatorLabel;
6819 ec.Emit (OpCodes.Dup);
6820 temp = new LocalTemporary (Type);
6825 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6827 public override void Emit (EmitContext ec)
6832 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6834 has_await_arguments = true;
6839 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6841 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6843 bool ResolveGetter (ResolveContext rc)
6845 if (!best_candidate.HasGet) {
6846 if (InstanceExpression != EmptyExpression.Null) {
6847 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6848 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6849 best_candidate.GetSignatureForError ());
6852 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6853 if (best_candidate.HasDifferentAccessibility) {
6854 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6855 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6856 TypeManager.CSharpSignature (best_candidate));
6858 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6859 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6863 if (best_candidate.HasDifferentAccessibility) {
6864 CheckProtectedMemberAccess (rc, best_candidate.Get);
6867 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6871 bool ResolveSetter (ResolveContext rc)
6873 if (!best_candidate.HasSet) {
6874 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6875 GetSignatureForError ());
6879 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6880 if (best_candidate.HasDifferentAccessibility) {
6881 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6882 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6883 GetSignatureForError ());
6885 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6886 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6890 if (best_candidate.HasDifferentAccessibility)
6891 CheckProtectedMemberAccess (rc, best_candidate.Set);
6893 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6899 /// Fully resolved expression that evaluates to an Event
6901 public class EventExpr : MemberExpr, IAssignMethod
6903 readonly EventSpec spec;
6906 public EventExpr (EventSpec spec, Location loc)
6914 protected override TypeSpec DeclaringType {
6916 return spec.DeclaringType;
6920 public override string Name {
6926 public override bool IsInstance {
6928 return !spec.IsStatic;
6932 public override bool IsStatic {
6934 return spec.IsStatic;
6938 public override string KindName {
6939 get { return "event"; }
6942 public MethodSpec Operator {
6950 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6953 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6955 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6956 if (spec.BackingField != null &&
6957 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6959 spec.MemberDefinition.SetIsUsed ();
6961 if (!ec.IsObsolete) {
6962 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6964 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6967 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6968 Error_AssignmentEventOnly (ec);
6970 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6972 InstanceExpression = null;
6974 return ml.ResolveMemberAccess (ec, left, original);
6978 return base.ResolveMemberAccess (ec, left, original);
6981 public override Expression CreateExpressionTree (ResolveContext ec)
6983 throw new NotSupportedException ("ET");
6986 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6988 if (right_side == EmptyExpression.EventAddition) {
6989 op = spec.AccessorAdd;
6990 } else if (right_side == EmptyExpression.EventSubtraction) {
6991 op = spec.AccessorRemove;
6995 Error_AssignmentEventOnly (ec);
6999 op = CandidateToBaseOverride (ec, op);
7003 protected override Expression DoResolve (ResolveContext ec)
7005 eclass = ExprClass.EventAccess;
7006 type = spec.MemberType;
7008 ResolveInstanceExpression (ec, null);
7010 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7011 Error_AssignmentEventOnly (ec);
7014 DoBestMemberChecks (ec, spec);
7018 public override void Emit (EmitContext ec)
7020 throw new NotSupportedException ();
7021 //Error_CannotAssign ();
7024 #region IAssignMethod Members
7026 public void Emit (EmitContext ec, bool leave_copy)
7028 throw new NotImplementedException ();
7031 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7033 if (leave_copy || !isCompound)
7034 throw new NotImplementedException ("EventExpr::EmitAssign");
7036 Arguments args = new Arguments (1);
7037 args.Add (new Argument (source));
7039 var call = new CallEmitter ();
7040 call.InstanceExpression = InstanceExpression;
7041 call.NullShortCircuit = NullShortCircuit;
7042 call.EmitStatement (ec, op, args, loc);
7047 void Error_AssignmentEventOnly (ResolveContext ec)
7049 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7050 ec.Report.Error (79, loc,
7051 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7052 GetSignatureForError ());
7054 ec.Report.Error (70, loc,
7055 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7056 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7060 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7062 name = name.Substring (0, name.LastIndexOf ('.'));
7063 base.Error_CannotCallAbstractBase (rc, name);
7066 public override string GetSignatureForError ()
7068 return TypeManager.CSharpSignature (spec);
7071 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7073 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7077 public class TemporaryVariableReference : VariableReference
7079 public class Declarator : Statement
7081 TemporaryVariableReference variable;
7083 public Declarator (TemporaryVariableReference variable)
7085 this.variable = variable;
7089 protected override void DoEmit (EmitContext ec)
7091 variable.li.CreateBuilder (ec);
7094 public override void Emit (EmitContext ec)
7096 // Don't create sequence point
7100 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7105 protected override void CloneTo (CloneContext clonectx, Statement target)
7113 public TemporaryVariableReference (LocalVariable li, Location loc)
7116 this.type = li.Type;
7120 public override bool IsLockedByStatement {
7128 public LocalVariable LocalInfo {
7134 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7136 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7137 return new TemporaryVariableReference (li, loc);
7140 protected override Expression DoResolve (ResolveContext ec)
7142 eclass = ExprClass.Variable;
7145 // Don't capture temporary variables except when using
7146 // state machine redirection and block yields
7148 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7149 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7150 ec.IsVariableCapturingRequired) {
7151 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7152 storey.CaptureLocalVariable (ec, li);
7158 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7160 return Resolve (ec);
7163 public override void Emit (EmitContext ec)
7165 li.CreateBuilder (ec);
7170 public void EmitAssign (EmitContext ec, Expression source)
7172 li.CreateBuilder (ec);
7174 EmitAssign (ec, source, false, false);
7177 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7179 return li.HoistedVariant;
7182 public override bool IsFixed {
7183 get { return true; }
7186 public override bool IsRef {
7187 get { return false; }
7190 public override string Name {
7191 get { throw new NotImplementedException (); }
7194 public override void SetHasAddressTaken ()
7196 throw new NotImplementedException ();
7199 protected override ILocalVariable Variable {
7203 public override VariableInfo VariableInfo {
7204 get { return null; }
7209 /// Handles `var' contextual keyword; var becomes a keyword only
7210 /// if no type called var exists in a variable scope
7212 class VarExpr : SimpleName
7214 public VarExpr (Location loc)
7219 public bool InferType (ResolveContext ec, Expression right_side)
7222 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7224 type = right_side.Type;
7225 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7226 ec.Report.Error (815, loc,
7227 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7228 type.GetSignatureForError ());
7232 eclass = ExprClass.Variable;
7236 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7238 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7239 base.Error_TypeOrNamespaceNotFound (ec);
7241 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");