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 ();
434 /// Resolves an expression and performs semantic analysis on it.
438 /// Currently Resolve wraps DoResolve to perform sanity
439 /// checking and assertion checking on what we expect from Resolve.
441 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
443 if (eclass != ExprClass.Unresolved) {
444 if ((flags & ExprClassToResolveFlags) == 0) {
445 Error_UnexpectedKind (ec, flags, loc);
459 if ((flags & e.ExprClassToResolveFlags) == 0) {
460 e.Error_UnexpectedKind (ec, flags, loc);
465 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
468 } catch (Exception ex) {
469 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
470 ec.Report.Printer is NullReportPrinter)
473 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
474 return ErrorExpression.Instance; // TODO: Add location
479 /// Resolves an expression and performs semantic analysis on it.
481 public Expression Resolve (ResolveContext rc)
483 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
487 /// Resolves an expression for LValue assignment
491 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
492 /// checking and assertion checking on what we expect from Resolve
494 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
496 int errors = ec.Report.Errors;
497 bool out_access = right_side == EmptyExpression.OutAccess;
499 Expression e = DoResolveLValue (ec, right_side);
501 if (e != null && out_access && !(e is IMemoryLocation)) {
502 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
503 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
505 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
506 // e.GetType () + " " + e.GetSignatureForError ());
511 if (errors == ec.Report.Errors) {
512 Error_ValueAssignment (ec, right_side);
517 if (e.eclass == ExprClass.Unresolved)
518 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
520 if ((e.type == null) && !(e is GenericTypeExpr))
521 throw new Exception ("Expression " + e + " did not set its type after Resolve");
526 public Constant ResolveLabelConstant (ResolveContext rc)
528 var expr = Resolve (rc);
532 Constant c = expr as Constant;
534 if (expr.type != InternalType.ErrorType)
535 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
543 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
545 rc.Module.Compiler.Report.Error (182, loc,
546 "An attribute argument must be a constant expression, typeof expression or array creation expression");
550 /// Emits the code for the expression
554 /// The Emit method is invoked to generate the code
555 /// for the expression.
557 public abstract void Emit (EmitContext ec);
560 // Emit code to branch to @target if this expression is equivalent to @on_true.
561 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
562 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
563 // including the use of conditional branches. Note also that a branch MUST be emitted
564 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
567 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
570 // Emit this expression for its side effects, not for its value.
571 // The default implementation is to emit the value, and then throw it away.
572 // Subclasses can provide more efficient implementations, but those MUST be equivalent
573 public virtual void EmitSideEffect (EmitContext ec)
576 ec.Emit (OpCodes.Pop);
580 // Emits the expression into temporary field variable. The method
581 // should be used for await expressions only
583 public virtual Expression EmitToField (EmitContext ec)
586 // This is the await prepare Emit method. When emitting code like
587 // a + b we emit code like
593 // For await a + await b we have to interfere the flow to keep the
594 // stack clean because await yields from the expression. The emit
597 // a = a.EmitToField () // a is changed to temporary field access
598 // b = b.EmitToField ()
604 // The idea is to emit expression and leave the stack empty with
605 // result value still available.
607 // Expressions should override this default implementation when
608 // optimized version can be provided (e.g. FieldExpr)
611 // We can optimize for side-effect free expressions, they can be
612 // emitted out of order
614 if (IsSideEffectFree)
617 bool needs_temporary = ContainsEmitWithAwait ();
618 if (!needs_temporary)
621 // Emit original code
622 var field = EmitToFieldSource (ec);
625 // Store the result to temporary field when we
626 // cannot load `this' directly
628 field = ec.GetTemporaryField (type);
629 if (needs_temporary) {
631 // Create temporary local (we cannot load `this' before Emit)
633 var temp = ec.GetTemporaryLocal (type);
634 ec.Emit (OpCodes.Stloc, temp);
637 ec.Emit (OpCodes.Ldloc, temp);
638 field.EmitAssignFromStack (ec);
640 ec.FreeTemporaryLocal (temp, type);
642 field.EmitAssignFromStack (ec);
649 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
652 // Default implementation calls Emit method
658 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
660 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
661 bool contains_await = false;
663 for (int i = 1; i < expressions.Count; ++i) {
664 if (expressions[i].ContainsEmitWithAwait ()) {
665 contains_await = true;
670 if (contains_await) {
671 for (int i = 0; i < expressions.Count; ++i) {
672 expressions[i] = expressions[i].EmitToField (ec);
677 for (int i = 0; i < expressions.Count; ++i) {
678 expressions[i].Emit (ec);
683 /// Protected constructor. Only derivate types should
684 /// be able to be created
687 protected Expression ()
692 /// Returns a fully formed expression after a MemberLookup
695 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
697 if (spec is EventSpec)
698 return new EventExpr ((EventSpec) spec, loc);
699 if (spec is ConstSpec)
700 return new ConstantExpr ((ConstSpec) spec, loc);
701 if (spec is FieldSpec)
702 return new FieldExpr ((FieldSpec) spec, loc);
703 if (spec is PropertySpec)
704 return new PropertyExpr ((PropertySpec) spec, loc);
705 if (spec is TypeSpec)
706 return new TypeExpression (((TypeSpec) spec), loc);
711 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
713 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
716 case MemberKind.Struct:
717 rc.Report.SymbolRelatedToPreviousError (type);
718 // Report meaningful error for struct as they always have default ctor in C# context
719 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
721 case MemberKind.MissingType:
722 case MemberKind.InternalCompilerType:
725 rc.Report.SymbolRelatedToPreviousError (type);
726 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
727 type.GetSignatureForError ());
734 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
735 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
736 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
739 return r.ResolveMember<MethodSpec> (rc, ref args);
743 public enum MemberLookupRestrictions
752 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
753 // `qualifier_type' or null to lookup members in the current class.
755 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
757 var members = MemberCache.FindMembers (queried_type, name, false);
761 MemberSpec non_method = null;
762 MemberSpec ambig_non_method = null;
764 for (int i = 0; i < members.Count; ++i) {
765 var member = members[i];
767 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
768 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
771 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
774 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
778 if (!member.IsAccessible (rc))
782 // With runtime binder we can have a situation where queried type is inaccessible
783 // because it came via dynamic object, the check about inconsisted accessibility
784 // had no effect as the type was unknown during compilation
787 // private class N { }
789 // public dynamic Foo ()
795 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
799 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
800 if (member is MethodSpec) {
802 // Interface members that are hidden by class members are removed from the set. This
803 // step only has an effect if T is a type parameter and T has both an effective base
804 // class other than object and a non-empty effective interface set
806 var tps = queried_type as TypeParameterSpec;
807 if (tps != null && tps.HasTypeConstraint)
808 members = RemoveHiddenTypeParameterMethods (members);
810 return new MethodGroupExpr (members, queried_type, loc);
813 if (!Invocation.IsMemberInvocable (member))
817 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
819 } else if (!errorMode && !member.IsNotCSharpCompatible) {
821 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
822 // T has both an effective base class other than object and a non-empty effective interface set.
824 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
826 var tps = queried_type as TypeParameterSpec;
827 if (tps != null && tps.HasTypeConstraint) {
828 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
831 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
837 ambig_non_method = member;
841 if (non_method != null) {
842 if (ambig_non_method != null && rc != null) {
843 var report = rc.Module.Compiler.Report;
844 report.SymbolRelatedToPreviousError (non_method);
845 report.SymbolRelatedToPreviousError (ambig_non_method);
846 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
847 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
850 if (non_method is MethodSpec)
851 return new MethodGroupExpr (members, queried_type, loc);
853 return ExprClassFromMemberInfo (non_method, loc);
856 if (members[0].DeclaringType.BaseType == null)
859 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
861 } while (members != null);
866 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
868 if (members.Count < 2)
872 // If M is a method, then all non-method members declared in an interface declaration
873 // are removed from the set, and all methods with the same signature as M declared in
874 // an interface declaration are removed from the set
878 for (int i = 0; i < members.Count; ++i) {
879 var method = members[i] as MethodSpec;
880 if (method == null) {
883 members = new List<MemberSpec> (members);
886 members.RemoveAt (i--);
890 if (!method.DeclaringType.IsInterface)
893 for (int ii = 0; ii < members.Count; ++ii) {
894 var candidate = members[ii] as MethodSpec;
895 if (candidate == null || !candidate.DeclaringType.IsClass)
898 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
903 members = new List<MemberSpec> (members);
906 members.RemoveAt (i--);
914 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
916 throw new NotImplementedException ();
919 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
921 if (t == InternalType.ErrorType)
924 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
925 oper, t.GetSignatureForError ());
928 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
930 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
933 public virtual void FlowAnalysis (FlowAnalysisContext fc)
938 /// Returns an expression that can be used to invoke operator true
939 /// on the expression if it exists.
941 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
943 return GetOperatorTrueOrFalse (ec, e, true, loc);
947 /// Returns an expression that can be used to invoke operator false
948 /// on the expression if it exists.
950 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
952 return GetOperatorTrueOrFalse (ec, e, false, loc);
955 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
957 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
958 var methods = MemberCache.GetUserOperator (e.type, op, false);
962 Arguments arguments = new Arguments (1);
963 arguments.Add (new Argument (e));
965 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
966 var oper = res.ResolveOperator (ec, ref arguments);
971 return new UserOperatorCall (oper, arguments, null, loc);
974 public virtual string ExprClassName
978 case ExprClass.Unresolved:
980 case ExprClass.Value:
982 case ExprClass.Variable:
984 case ExprClass.Namespace:
988 case ExprClass.MethodGroup:
989 return "method group";
990 case ExprClass.PropertyAccess:
991 return "property access";
992 case ExprClass.EventAccess:
993 return "event access";
994 case ExprClass.IndexerAccess:
995 return "indexer access";
996 case ExprClass.Nothing:
998 case ExprClass.TypeParameter:
999 return "type parameter";
1001 throw new Exception ("Should not happen");
1006 /// Reports that we were expecting `expr' to be of class `expected'
1008 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1010 var name = memberExpr.GetSignatureForError ();
1012 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1015 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1017 string [] valid = new string [4];
1020 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1021 valid [count++] = "variable";
1022 valid [count++] = "value";
1025 if ((flags & ResolveFlags.Type) != 0)
1026 valid [count++] = "type";
1028 if ((flags & ResolveFlags.MethodGroup) != 0)
1029 valid [count++] = "method group";
1032 valid [count++] = "unknown";
1034 StringBuilder sb = new StringBuilder (valid [0]);
1035 for (int i = 1; i < count - 1; i++) {
1037 sb.Append (valid [i]);
1040 sb.Append ("' or `");
1041 sb.Append (valid [count - 1]);
1044 ec.Report.Error (119, loc,
1045 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1048 public static void UnsafeError (ResolveContext ec, Location loc)
1050 UnsafeError (ec.Report, loc);
1053 public static void UnsafeError (Report Report, Location loc)
1055 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1059 // Converts `source' to an int, uint, long or ulong.
1061 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1063 var btypes = ec.BuiltinTypes;
1065 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1066 Arguments args = new Arguments (1);
1067 args.Add (new Argument (source));
1068 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1071 Expression converted;
1073 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1074 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1075 if (converted == null)
1076 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1077 if (converted == null)
1078 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1079 if (converted == null)
1080 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1082 if (converted == null) {
1083 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1092 // Only positive constants are allowed at compile time
1094 Constant c = converted as Constant;
1095 if (c != null && c.IsNegative)
1096 Error_NegativeArrayIndex (ec, source.loc);
1098 // No conversion needed to array index
1099 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1102 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1106 // Derived classes implement this method by cloning the fields that
1107 // could become altered during the Resolve stage
1109 // Only expressions that are created for the parser need to implement
1112 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1114 throw new NotImplementedException (
1116 "CloneTo not implemented for expression {0}", this.GetType ()));
1120 // Clones an expression created by the parser.
1122 // We only support expressions created by the parser so far, not
1123 // expressions that have been resolved (many more classes would need
1124 // to implement CloneTo).
1126 // This infrastructure is here merely for Lambda expressions which
1127 // compile the same code using different type values for the same
1128 // arguments to find the correct overload
1130 public virtual Expression Clone (CloneContext clonectx)
1132 Expression cloned = (Expression) MemberwiseClone ();
1133 CloneTo (clonectx, cloned);
1139 // Implementation of expression to expression tree conversion
1141 public abstract Expression CreateExpressionTree (ResolveContext ec);
1143 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1145 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1148 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1150 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1153 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1155 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1158 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1160 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1164 return new TypeExpression (t, loc);
1168 // Implemented by all expressions which support conversion from
1169 // compiler expression to invokable runtime expression. Used by
1170 // dynamic C# binder.
1172 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1174 throw new NotImplementedException ("MakeExpression for " + GetType ());
1177 public virtual object Accept (StructuralVisitor visitor)
1179 return visitor.Visit (this);
1184 /// This is just a base class for expressions that can
1185 /// appear on statements (invocations, object creation,
1186 /// assignments, post/pre increment and decrement). The idea
1187 /// being that they would support an extra Emition interface that
1188 /// does not leave a result on the stack.
1190 public abstract class ExpressionStatement : Expression
1192 public virtual void MarkReachable (Reachability rc)
1196 public ExpressionStatement ResolveStatement (BlockContext ec)
1198 Expression e = Resolve (ec);
1202 ExpressionStatement es = e as ExpressionStatement;
1203 if (es == null || e is AnonymousMethodBody)
1204 Error_InvalidExpressionStatement (ec);
1207 // This is quite expensive warning, try to limit the damage
1209 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1210 WarningAsyncWithoutWait (ec, e);
1216 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1218 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1219 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1224 // Need to do full resolve because GetAwaiter can be extension method
1225 // available only in this context
1227 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1231 var arguments = new Arguments (0);
1232 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1237 // Use same check rules as for real await
1239 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1240 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1243 bc.Report.Warning (4014, 1, e.Location,
1244 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1248 var inv = e as Invocation;
1249 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1250 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1251 bc.Report.Warning (4014, 1, e.Location,
1252 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1258 /// Requests the expression to be emitted in a `statement'
1259 /// context. This means that no new value is left on the
1260 /// stack after invoking this method (constrasted with
1261 /// Emit that will always leave a value on the stack).
1263 public abstract void EmitStatement (EmitContext ec);
1265 public override void EmitSideEffect (EmitContext ec)
1272 /// This kind of cast is used to encapsulate the child
1273 /// whose type is child.Type into an expression that is
1274 /// reported to return "return_type". This is used to encapsulate
1275 /// expressions which have compatible types, but need to be dealt
1276 /// at higher levels with.
1278 /// For example, a "byte" expression could be encapsulated in one
1279 /// of these as an "unsigned int". The type for the expression
1280 /// would be "unsigned int".
1283 public abstract class TypeCast : Expression
1285 protected readonly Expression child;
1287 protected TypeCast (Expression child, TypeSpec return_type)
1289 eclass = child.eclass;
1290 loc = child.Location;
1295 public Expression Child {
1301 public override bool ContainsEmitWithAwait ()
1303 return child.ContainsEmitWithAwait ();
1306 public override Expression CreateExpressionTree (ResolveContext ec)
1308 Arguments args = new Arguments (2);
1309 args.Add (new Argument (child.CreateExpressionTree (ec)));
1310 args.Add (new Argument (new TypeOf (type, loc)));
1312 if (type.IsPointer || child.Type.IsPointer)
1313 Error_PointerInsideExpressionTree (ec);
1315 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1318 protected override Expression DoResolve (ResolveContext ec)
1320 // This should never be invoked, we are born in fully
1321 // initialized state.
1326 public override void Emit (EmitContext ec)
1331 public override void FlowAnalysis (FlowAnalysisContext fc)
1333 child.FlowAnalysis (fc);
1336 public override SLE.Expression MakeExpression (BuilderContext ctx)
1339 return base.MakeExpression (ctx);
1341 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1342 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1343 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1347 protected override void CloneTo (CloneContext clonectx, Expression t)
1352 public override bool IsNull {
1353 get { return child.IsNull; }
1357 public class EmptyCast : TypeCast {
1358 EmptyCast (Expression child, TypeSpec target_type)
1359 : base (child, target_type)
1363 public static Expression Create (Expression child, TypeSpec type)
1365 Constant c = child as Constant;
1367 var enum_constant = c as EnumConstant;
1368 if (enum_constant != null)
1369 c = enum_constant.Child;
1371 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1375 var res = c.ConvertImplicitly (type);
1381 EmptyCast e = child as EmptyCast;
1383 return new EmptyCast (e.child, type);
1385 return new EmptyCast (child, type);
1388 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1390 child.EmitBranchable (ec, label, on_true);
1393 public override void EmitSideEffect (EmitContext ec)
1395 child.EmitSideEffect (ec);
1400 // Used for predefined type user operator (no obsolete check, etc.)
1402 public class OperatorCast : TypeCast
1404 readonly MethodSpec conversion_operator;
1406 public OperatorCast (Expression expr, TypeSpec target_type)
1407 : this (expr, target_type, target_type, false)
1411 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1412 : this (expr, target_type, target_type, find_explicit)
1416 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1417 : base (expr, returnType)
1419 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1420 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1423 foreach (MethodSpec oper in mi) {
1424 if (oper.ReturnType != returnType)
1427 if (oper.Parameters.Types[0] == expr.Type) {
1428 conversion_operator = oper;
1434 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1435 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1438 public override void Emit (EmitContext ec)
1441 ec.Emit (OpCodes.Call, conversion_operator);
1446 // Constant specialization of EmptyCast.
1447 // We need to special case this since an empty cast of
1448 // a constant is still a constant.
1450 public class EmptyConstantCast : Constant
1452 public readonly Constant child;
1454 public EmptyConstantCast (Constant child, TypeSpec type)
1455 : base (child.Location)
1458 throw new ArgumentNullException ("child");
1461 this.eclass = child.eclass;
1465 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1467 if (child.Type == target_type)
1470 // FIXME: check that 'type' can be converted to 'target_type' first
1471 return child.ConvertExplicitly (in_checked_context, target_type);
1474 public override Expression CreateExpressionTree (ResolveContext ec)
1476 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1477 child.CreateExpressionTree (ec),
1478 new TypeOf (type, loc));
1481 Error_PointerInsideExpressionTree (ec);
1483 return CreateExpressionFactoryCall (ec, "Convert", args);
1486 public override bool IsDefaultValue {
1487 get { return child.IsDefaultValue; }
1490 public override bool IsNegative {
1491 get { return child.IsNegative; }
1494 public override bool IsNull {
1495 get { return child.IsNull; }
1498 public override bool IsOneInteger {
1499 get { return child.IsOneInteger; }
1502 public override bool IsSideEffectFree {
1504 return child.IsSideEffectFree;
1508 public override bool IsZeroInteger {
1509 get { return child.IsZeroInteger; }
1512 public override void Emit (EmitContext ec)
1517 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1519 child.EmitBranchable (ec, label, on_true);
1521 // Only to make verifier happy
1522 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1523 ec.Emit (OpCodes.Unbox_Any, type);
1526 public override void EmitSideEffect (EmitContext ec)
1528 child.EmitSideEffect (ec);
1531 public override object GetValue ()
1533 return child.GetValue ();
1536 public override string GetValueAsLiteral ()
1538 return child.GetValueAsLiteral ();
1541 public override long GetValueAsLong ()
1543 return child.GetValueAsLong ();
1546 public override Constant ConvertImplicitly (TypeSpec target_type)
1548 if (type == target_type)
1551 // FIXME: Do we need to check user conversions?
1552 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1555 return child.ConvertImplicitly (target_type);
1560 /// This class is used to wrap literals which belong inside Enums
1562 public class EnumConstant : Constant
1564 public Constant Child;
1566 public EnumConstant (Constant child, TypeSpec enum_type)
1567 : base (child.Location)
1571 this.eclass = ExprClass.Value;
1572 this.type = enum_type;
1575 protected EnumConstant (Location loc)
1580 public override void Emit (EmitContext ec)
1585 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1587 Child.EncodeAttributeValue (rc, enc, Child.Type);
1590 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1592 Child.EmitBranchable (ec, label, on_true);
1595 public override void EmitSideEffect (EmitContext ec)
1597 Child.EmitSideEffect (ec);
1600 public override string GetSignatureForError()
1602 return Type.GetSignatureForError ();
1605 public override object GetValue ()
1607 return Child.GetValue ();
1611 public override object GetTypedValue ()
1614 // The method can be used in dynamic context only (on closed types)
1616 // System.Enum.ToObject cannot be called on dynamic types
1617 // EnumBuilder has to be used, but we cannot use EnumBuilder
1618 // because it does not properly support generics
1620 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1624 public override string GetValueAsLiteral ()
1626 return Child.GetValueAsLiteral ();
1629 public override long GetValueAsLong ()
1631 return Child.GetValueAsLong ();
1634 public EnumConstant Increment()
1636 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1639 public override bool IsDefaultValue {
1641 return Child.IsDefaultValue;
1645 public override bool IsSideEffectFree {
1647 return Child.IsSideEffectFree;
1651 public override bool IsZeroInteger {
1652 get { return Child.IsZeroInteger; }
1655 public override bool IsNegative {
1657 return Child.IsNegative;
1661 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1663 if (Child.Type == target_type)
1666 return Child.ConvertExplicitly (in_checked_context, target_type);
1669 public override Constant ConvertImplicitly (TypeSpec type)
1671 if (this.type == type) {
1675 if (!Convert.ImplicitStandardConversionExists (this, type)){
1679 return Child.ConvertImplicitly (type);
1684 /// This kind of cast is used to encapsulate Value Types in objects.
1686 /// The effect of it is to box the value type emitted by the previous
1689 public class BoxedCast : TypeCast {
1691 public BoxedCast (Expression expr, TypeSpec target_type)
1692 : base (expr, target_type)
1694 eclass = ExprClass.Value;
1697 protected override Expression DoResolve (ResolveContext ec)
1699 // This should never be invoked, we are born in fully
1700 // initialized state.
1705 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1707 // Only boxing to object type is supported
1708 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1709 base.EncodeAttributeValue (rc, enc, targetType);
1713 enc.Encode (child.Type);
1714 child.EncodeAttributeValue (rc, enc, child.Type);
1717 public override void Emit (EmitContext ec)
1721 ec.Emit (OpCodes.Box, child.Type);
1724 public override void EmitSideEffect (EmitContext ec)
1726 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1727 // so, we need to emit the box+pop instructions in most cases
1728 if (child.Type.IsStruct &&
1729 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1730 child.EmitSideEffect (ec);
1732 base.EmitSideEffect (ec);
1736 public class UnboxCast : TypeCast {
1737 public UnboxCast (Expression expr, TypeSpec return_type)
1738 : base (expr, return_type)
1742 protected override Expression DoResolve (ResolveContext ec)
1744 // This should never be invoked, we are born in fully
1745 // initialized state.
1750 public override void Emit (EmitContext ec)
1754 ec.Emit (OpCodes.Unbox_Any, type);
1759 /// This is used to perform explicit numeric conversions.
1761 /// Explicit numeric conversions might trigger exceptions in a checked
1762 /// context, so they should generate the conv.ovf opcodes instead of
1765 public class ConvCast : TypeCast {
1766 public enum Mode : byte {
1767 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1769 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1770 U2_I1, U2_U1, U2_I2, U2_CH,
1771 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1772 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1773 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1774 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1775 CH_I1, CH_U1, CH_I2,
1776 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1777 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1783 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1784 : base (child, return_type)
1789 protected override Expression DoResolve (ResolveContext ec)
1791 // This should never be invoked, we are born in fully
1792 // initialized state.
1797 public override string ToString ()
1799 return String.Format ("ConvCast ({0}, {1})", mode, child);
1802 public override void Emit (EmitContext ec)
1808 public static void Emit (EmitContext ec, Mode mode)
1810 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1812 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1813 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1814 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1815 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U1_CH: /* nothing */ break;
1821 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1822 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1823 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1825 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1826 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1829 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1830 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1831 case Mode.U2_CH: /* nothing */ break;
1833 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1834 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1835 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1836 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1837 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1838 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1839 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1841 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1842 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1843 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1844 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1845 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1846 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1848 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1849 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1850 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1851 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1852 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1853 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1854 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1855 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1856 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1858 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1859 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1860 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1861 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1862 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1863 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1864 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1865 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1866 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1868 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1869 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1870 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1872 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1873 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1874 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1875 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1876 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1877 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1878 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1879 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1880 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1882 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1883 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1884 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1885 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1886 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1887 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1888 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1889 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1890 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1891 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1893 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1897 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1898 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1899 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1900 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1901 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1906 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1907 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1908 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1909 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1910 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1911 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1913 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1914 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1915 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1916 case Mode.U2_CH: /* nothing */ break;
1918 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1919 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1920 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1921 case Mode.I4_U4: /* nothing */ break;
1922 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1924 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1926 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1927 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1928 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1929 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1930 case Mode.U4_I4: /* nothing */ break;
1931 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1933 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1934 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1935 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1936 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1937 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1938 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1939 case Mode.I8_U8: /* nothing */ break;
1940 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1941 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1943 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1944 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1945 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1946 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1947 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1948 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1949 case Mode.U8_I8: /* nothing */ break;
1950 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1951 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1953 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1954 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1955 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1957 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1958 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1959 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1960 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1961 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1962 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1963 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1964 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1965 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1967 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1968 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1969 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1970 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1971 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1972 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1973 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1974 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1975 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1976 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1978 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1984 class OpcodeCast : TypeCast
1988 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1989 : base (child, return_type)
1994 protected override Expression DoResolve (ResolveContext ec)
1996 // This should never be invoked, we are born in fully
1997 // initialized state.
2002 public override void Emit (EmitContext ec)
2008 public TypeSpec UnderlyingType {
2009 get { return child.Type; }
2014 // Opcode casts expression with 2 opcodes but only
2015 // single expression tree node
2017 class OpcodeCastDuplex : OpcodeCast
2019 readonly OpCode second;
2021 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2022 : base (child, returnType, first)
2024 this.second = second;
2027 public override void Emit (EmitContext ec)
2035 /// This kind of cast is used to encapsulate a child and cast it
2036 /// to the class requested
2038 public sealed class ClassCast : TypeCast {
2039 readonly bool forced;
2041 public ClassCast (Expression child, TypeSpec return_type)
2042 : base (child, return_type)
2046 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2047 : base (child, return_type)
2049 this.forced = forced;
2052 public override void Emit (EmitContext ec)
2056 bool gen = TypeManager.IsGenericParameter (child.Type);
2058 ec.Emit (OpCodes.Box, child.Type);
2060 if (type.IsGenericParameter) {
2061 ec.Emit (OpCodes.Unbox_Any, type);
2068 ec.Emit (OpCodes.Castclass, type);
2073 // Created during resolving pahse when an expression is wrapped or constantified
2074 // and original expression can be used later (e.g. for expression trees)
2076 public class ReducedExpression : Expression
2078 public sealed class ReducedConstantExpression : EmptyConstantCast
2080 readonly Expression orig_expr;
2082 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2083 : base (expr, expr.Type)
2085 this.orig_expr = orig_expr;
2088 public Expression OriginalExpression {
2094 public override Constant ConvertImplicitly (TypeSpec target_type)
2096 Constant c = base.ConvertImplicitly (target_type);
2098 c = new ReducedConstantExpression (c, orig_expr);
2103 public override Expression CreateExpressionTree (ResolveContext ec)
2105 return orig_expr.CreateExpressionTree (ec);
2108 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2110 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2112 c = new ReducedConstantExpression (c, orig_expr);
2116 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2119 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2121 if (orig_expr is Conditional)
2122 child.EncodeAttributeValue (rc, enc, targetType);
2124 base.EncodeAttributeValue (rc, enc, targetType);
2128 sealed class ReducedExpressionStatement : ExpressionStatement
2130 readonly Expression orig_expr;
2131 readonly ExpressionStatement stm;
2133 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2135 this.orig_expr = orig;
2137 this.eclass = stm.eclass;
2138 this.type = stm.Type;
2140 this.loc = orig.Location;
2143 public override bool ContainsEmitWithAwait ()
2145 return stm.ContainsEmitWithAwait ();
2148 public override Expression CreateExpressionTree (ResolveContext ec)
2150 return orig_expr.CreateExpressionTree (ec);
2153 protected override Expression DoResolve (ResolveContext ec)
2158 public override void Emit (EmitContext ec)
2163 public override void EmitStatement (EmitContext ec)
2165 stm.EmitStatement (ec);
2168 public override void FlowAnalysis (FlowAnalysisContext fc)
2170 stm.FlowAnalysis (fc);
2174 readonly Expression expr, orig_expr;
2176 private ReducedExpression (Expression expr, Expression orig_expr)
2179 this.eclass = expr.eclass;
2180 this.type = expr.Type;
2181 this.orig_expr = orig_expr;
2182 this.loc = orig_expr.Location;
2187 public override bool IsSideEffectFree {
2189 return expr.IsSideEffectFree;
2193 public Expression OriginalExpression {
2201 public override bool ContainsEmitWithAwait ()
2203 return expr.ContainsEmitWithAwait ();
2207 // Creates fully resolved expression switcher
2209 public static Constant Create (Constant expr, Expression original_expr)
2211 if (expr.eclass == ExprClass.Unresolved)
2212 throw new ArgumentException ("Unresolved expression");
2214 return new ReducedConstantExpression (expr, original_expr);
2217 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2219 return new ReducedExpressionStatement (s, orig);
2222 public static Expression Create (Expression expr, Expression original_expr)
2224 return Create (expr, original_expr, true);
2228 // Creates unresolved reduce expression. The original expression has to be
2229 // already resolved. Created expression is constant based based on `expr'
2230 // value unless canBeConstant is used
2232 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2234 if (canBeConstant) {
2235 Constant c = expr as Constant;
2237 return Create (c, original_expr);
2240 ExpressionStatement s = expr as ExpressionStatement;
2242 return Create (s, original_expr);
2244 if (expr.eclass == ExprClass.Unresolved)
2245 throw new ArgumentException ("Unresolved expression");
2247 return new ReducedExpression (expr, original_expr);
2250 public override Expression CreateExpressionTree (ResolveContext ec)
2252 return orig_expr.CreateExpressionTree (ec);
2255 protected override Expression DoResolve (ResolveContext ec)
2260 public override void Emit (EmitContext ec)
2265 public override Expression EmitToField (EmitContext ec)
2267 return expr.EmitToField(ec);
2270 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2272 expr.EmitBranchable (ec, target, on_true);
2275 public override void FlowAnalysis (FlowAnalysisContext fc)
2277 expr.FlowAnalysis (fc);
2280 public override SLE.Expression MakeExpression (BuilderContext ctx)
2282 return orig_expr.MakeExpression (ctx);
2287 // Standard composite pattern
2289 public abstract class CompositeExpression : Expression
2291 protected Expression expr;
2293 protected CompositeExpression (Expression expr)
2296 this.loc = expr.Location;
2299 public override bool ContainsEmitWithAwait ()
2301 return expr.ContainsEmitWithAwait ();
2304 public override Expression CreateExpressionTree (ResolveContext rc)
2306 return expr.CreateExpressionTree (rc);
2309 public Expression Child {
2310 get { return expr; }
2313 protected override Expression DoResolve (ResolveContext rc)
2315 expr = expr.Resolve (rc);
2320 eclass = expr.eclass;
2324 public override void Emit (EmitContext ec)
2329 public override bool IsNull {
2330 get { return expr.IsNull; }
2335 // Base of expressions used only to narrow resolve flow
2337 public abstract class ShimExpression : Expression
2339 protected Expression expr;
2341 protected ShimExpression (Expression expr)
2346 public Expression Expr {
2352 protected override void CloneTo (CloneContext clonectx, Expression t)
2357 ShimExpression target = (ShimExpression) t;
2358 target.expr = expr.Clone (clonectx);
2361 public override bool ContainsEmitWithAwait ()
2363 return expr.ContainsEmitWithAwait ();
2366 public override Expression CreateExpressionTree (ResolveContext ec)
2368 throw new NotSupportedException ("ET");
2371 public override void Emit (EmitContext ec)
2373 throw new InternalErrorException ("Missing Resolve call");
2377 public class UnreachableExpression : Expression
2379 public UnreachableExpression (Expression expr)
2381 this.loc = expr.Location;
2384 public override Expression CreateExpressionTree (ResolveContext ec)
2387 throw new NotImplementedException ();
2390 protected override Expression DoResolve (ResolveContext rc)
2392 throw new NotSupportedException ();
2395 public override void FlowAnalysis (FlowAnalysisContext fc)
2397 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2400 public override void Emit (EmitContext ec)
2404 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2410 // Unresolved type name expressions
2412 public abstract class ATypeNameExpression : FullNamedExpression
2415 protected TypeArguments targs;
2417 protected ATypeNameExpression (string name, Location l)
2423 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2430 protected ATypeNameExpression (string name, int arity, Location l)
2431 : this (name, new UnboundTypeArguments (arity), l)
2437 protected int Arity {
2439 return targs == null ? 0 : targs.Count;
2443 public bool HasTypeArguments {
2445 return targs != null && !targs.IsEmpty;
2449 public string Name {
2458 public TypeArguments TypeArguments {
2466 public override bool Equals (object obj)
2468 ATypeNameExpression atne = obj as ATypeNameExpression;
2469 return atne != null && atne.Name == Name &&
2470 (targs == null || targs.Equals (atne.targs));
2473 public override int GetHashCode ()
2475 return Name.GetHashCode ();
2478 // TODO: Move it to MemberCore
2479 public static string GetMemberType (MemberCore mc)
2485 if (mc is FieldBase)
2487 if (mc is MethodCore)
2489 if (mc is EnumMember)
2497 public override string GetSignatureForError ()
2499 if (targs != null) {
2500 return Name + "<" + targs.GetSignatureForError () + ">";
2506 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2510 /// SimpleName expressions are formed of a single word and only happen at the beginning
2511 /// of a dotted-name.
2513 public class SimpleName : ATypeNameExpression
2515 public SimpleName (string name, Location l)
2520 public SimpleName (string name, TypeArguments args, Location l)
2521 : base (name, args, l)
2525 public SimpleName (string name, int arity, Location l)
2526 : base (name, arity, l)
2530 public SimpleName GetMethodGroup ()
2532 return new SimpleName (Name, targs, loc);
2535 protected override Expression DoResolve (ResolveContext rc)
2537 return SimpleNameResolve (rc, null);
2540 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2542 return SimpleNameResolve (ec, right_side);
2545 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2547 if (ctx.CurrentType != null) {
2548 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2549 if (member != null) {
2550 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2555 var report = ctx.Module.Compiler.Report;
2557 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2558 if (retval != null) {
2559 report.SymbolRelatedToPreviousError (retval.Type);
2560 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2564 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2565 if (retval != null) {
2566 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2570 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2571 if (ns_candidates != null) {
2572 if (ctx is UsingAliasNamespace.AliasContext) {
2573 report.Error (246, loc,
2574 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2575 ns_candidates[0], Name);
2577 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2578 report.Error (246, loc,
2579 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2583 report.Error (246, loc,
2584 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2589 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2591 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2594 if (fne.Type != null && Arity > 0) {
2595 if (HasTypeArguments) {
2596 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2597 if (ct.ResolveAsType (mc) == null)
2603 return new GenericOpenTypeExpr (fne.Type, loc);
2607 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2609 if (!(fne is NamespaceExpression))
2613 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2614 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2615 mc.Module.Compiler.Report.Error (1980, Location,
2616 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2617 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2620 fne = new DynamicTypeExpr (loc);
2621 fne.ResolveAsType (mc);
2627 Error_TypeOrNamespaceNotFound (mc);
2631 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2633 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2636 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2638 int lookup_arity = Arity;
2639 bool errorMode = false;
2641 Block current_block = rc.CurrentBlock;
2642 INamedBlockVariable variable = null;
2643 bool variable_found = false;
2647 // Stage 1: binding to local variables or parameters
2649 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2651 if (current_block != null && lookup_arity == 0) {
2652 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2653 if (!variable.IsDeclared) {
2654 // We found local name in accessible block but it's not
2655 // initialized yet, maybe the user wanted to bind to something else
2657 variable_found = true;
2659 e = variable.CreateReferenceExpression (rc, loc);
2662 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2671 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2673 TypeSpec member_type = rc.CurrentType;
2674 for (; member_type != null; member_type = member_type.DeclaringType) {
2675 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2679 var me = e as MemberExpr;
2681 // The name matches a type, defer to ResolveAsTypeStep
2689 if (variable != null) {
2690 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2691 rc.Report.Error (844, loc,
2692 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2693 Name, me.GetSignatureForError ());
2697 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2698 // Leave it to overload resolution to report correct error
2700 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2701 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2704 // LAMESPEC: again, ignores InvocableOnly
2705 if (variable != null) {
2706 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2707 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2711 // MemberLookup does not check accessors availability, this is actually needed for properties only
2713 var pe = me as PropertyExpr;
2716 // Break as there is no other overload available anyway
2717 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2718 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2721 pe.Getter = pe.PropertyInfo.Get;
2723 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2726 pe.Setter = pe.PropertyInfo.Set;
2731 // TODO: It's used by EventExpr -> FieldExpr transformation only
2732 // TODO: Should go to MemberAccess
2733 me = me.ResolveMemberAccess (rc, null, null);
2737 me.SetTypeArguments (rc, targs);
2744 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2746 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2747 if (IsPossibleTypeOrNamespace (rc)) {
2748 if (variable != null) {
2749 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2750 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2753 return ResolveAsTypeOrNamespace (rc);
2758 if (variable_found) {
2759 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2762 var tparams = rc.CurrentTypeParameters;
2763 if (tparams != null) {
2764 if (tparams.Find (Name) != null) {
2765 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2770 var ct = rc.CurrentType;
2772 if (ct.MemberDefinition.TypeParametersCount > 0) {
2773 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2774 if (ctp.Name == Name) {
2775 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2781 ct = ct.DeclaringType;
2782 } while (ct != null);
2784 var cos = rc.CurrentMemberDefinition.Parent as ClassOrStruct;
2785 if (cos != null && cos.PrimaryConstructorParameters != null) {
2786 foreach (var p in cos.PrimaryConstructorParameters.FixedParameters) {
2787 if (p.Name == Name) {
2788 rc.Report.Error (9007, loc, "Primary constructor parameter `{0}' is not available in this context when using ref or out modifier",
2796 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2797 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2799 rc.Report.SymbolRelatedToPreviousError (e.Type);
2800 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2804 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2806 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2807 return ErrorExpression.Instance;
2811 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2813 if (e.Type.Arity != Arity) {
2814 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2818 if (e is TypeExpr) {
2819 // TypeExpression does not have correct location
2820 if (e is TypeExpression)
2821 e = new TypeExpression (e.Type, loc);
2827 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2830 return ErrorExpression.Instance;
2833 if (rc.Module.Evaluator != null) {
2834 var fi = rc.Module.Evaluator.LookupField (Name);
2836 return new FieldExpr (fi.Item1, loc);
2844 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2846 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2851 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2852 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2856 if (right_side != null) {
2857 e = e.ResolveLValue (ec, right_side);
2865 public override object Accept (StructuralVisitor visitor)
2867 return visitor.Visit (this);
2872 /// Represents a namespace or a type. The name of the class was inspired by
2873 /// section 10.8.1 (Fully Qualified Names).
2875 public abstract class FullNamedExpression : Expression
2877 protected override void CloneTo (CloneContext clonectx, Expression target)
2879 // Do nothing, most unresolved type expressions cannot be
2880 // resolved to different type
2883 public override bool ContainsEmitWithAwait ()
2888 public override Expression CreateExpressionTree (ResolveContext ec)
2890 throw new NotSupportedException ("ET");
2893 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2896 // This is used to resolve the expression as a type, a null
2897 // value will be returned if the expression is not a type
2900 public override TypeSpec ResolveAsType (IMemberContext mc)
2902 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2907 TypeExpr te = fne as TypeExpr;
2909 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2917 var dep = type.GetMissingDependencies ();
2919 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2922 if (type.Kind == MemberKind.Void) {
2923 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2927 // Obsolete checks cannot be done when resolving base context as they
2928 // require type dependencies to be set but we are in process of resolving them
2930 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2931 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2932 if (obsolete_attr != null && !mc.IsObsolete) {
2933 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2941 public override void Emit (EmitContext ec)
2943 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2944 GetSignatureForError ());
2949 /// Expression that evaluates to a type
2951 public abstract class TypeExpr : FullNamedExpression
2953 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2959 protected sealed override Expression DoResolve (ResolveContext ec)
2965 public override bool Equals (object obj)
2967 TypeExpr tobj = obj as TypeExpr;
2971 return Type == tobj.Type;
2974 public override int GetHashCode ()
2976 return Type.GetHashCode ();
2981 /// Fully resolved Expression that already evaluated to a type
2983 public class TypeExpression : TypeExpr
2985 public TypeExpression (TypeSpec t, Location l)
2988 eclass = ExprClass.Type;
2992 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2998 public class NamespaceExpression : FullNamedExpression
3000 readonly Namespace ns;
3002 public NamespaceExpression (Namespace ns, Location loc)
3005 this.Type = InternalType.Namespace;
3006 this.eclass = ExprClass.Namespace;
3010 public Namespace Namespace {
3016 protected override Expression DoResolve (ResolveContext rc)
3018 throw new NotImplementedException ();
3021 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
3026 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3028 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3029 if (retval != null) {
3030 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3031 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3035 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3036 if (retval != null) {
3037 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3042 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3043 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3047 string assembly = null;
3048 string possible_name = Namespace.GetSignatureForError () + "." + name;
3050 // Only assembly unique name should be added
3051 switch (possible_name) {
3052 case "System.Drawing":
3053 case "System.Web.Services":
3056 case "System.Configuration":
3057 case "System.Data.Services":
3058 case "System.DirectoryServices":
3060 case "System.Net.Http":
3061 case "System.Numerics":
3062 case "System.Runtime.Caching":
3063 case "System.ServiceModel":
3064 case "System.Transactions":
3065 case "System.Web.Routing":
3066 case "System.Xml.Linq":
3068 assembly = possible_name;
3072 case "System.Linq.Expressions":
3073 assembly = "System.Core";
3076 case "System.Windows.Forms":
3077 case "System.Windows.Forms.Layout":
3078 assembly = "System.Windows.Forms";
3082 assembly = assembly == null ? "an" : "`" + assembly + "'";
3084 if (Namespace is GlobalRootNamespace) {
3085 ctx.Module.Compiler.Report.Error (400, loc,
3086 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3089 ctx.Module.Compiler.Report.Error (234, loc,
3090 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3091 name, GetSignatureForError (), assembly);
3095 public override string GetSignatureForError ()
3097 return ns.GetSignatureForError ();
3100 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3102 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3107 /// This class denotes an expression which evaluates to a member
3108 /// of a struct or a class.
3110 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3113 // An instance expression associated with this member, if it's a
3114 // non-static member
3116 public Expression InstanceExpression;
3119 /// The name of this member.
3121 public abstract string Name {
3126 // When base.member is used
3128 public bool IsBase {
3129 get { return InstanceExpression is BaseThis; }
3133 /// Whether this is an instance member.
3135 public abstract bool IsInstance {
3140 /// Whether this is a static member.
3142 public abstract bool IsStatic {
3146 public abstract string KindName {
3150 protected abstract TypeSpec DeclaringType {
3154 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3156 return InstanceExpression.Type;
3161 // Converts best base candidate for virtual method starting from QueriedBaseType
3163 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3166 // Only when base.member is used and method is virtual
3172 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3173 // means for base.member access we have to find the closest match after we found best candidate
3175 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3177 // The method could already be what we are looking for
3179 TypeSpec[] targs = null;
3180 if (method.DeclaringType != InstanceExpression.Type) {
3182 // Candidate can have inflated MVAR parameters and we need to find
3183 // base match for original definition not inflated parameter types
3185 var parameters = method.Parameters;
3186 if (method.Arity > 0) {
3187 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3188 var inflated = method.DeclaringType as InflatedTypeSpec;
3189 if (inflated != null) {
3190 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3194 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3195 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3196 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3197 if (base_override.IsGeneric)
3198 targs = method.TypeArguments;
3200 method = base_override;
3205 // When base access is used inside anonymous method/iterator/etc we need to
3206 // get back to the context of original type. We do it by emiting proxy
3207 // method in original class and rewriting base call to this compiler
3208 // generated method call which does the actual base invocation. This may
3209 // introduce redundant storey but with `this' only but it's tricky to avoid
3210 // at this stage as we don't know what expressions follow base
3212 if (rc.CurrentAnonymousMethod != null) {
3213 if (targs == null && method.IsGeneric) {
3214 targs = method.TypeArguments;
3215 method = method.GetGenericMethodDefinition ();
3218 if (method.Parameters.HasArglist)
3219 throw new NotImplementedException ("__arglist base call proxy");
3221 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3223 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3224 // get/set member expressions second call would fail to proxy because left expression
3225 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3226 // FIXME: The async check is another hack but will probably fail with mutators
3227 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3228 InstanceExpression = new This (loc).Resolve (rc);
3232 method = method.MakeGenericMethod (rc, targs);
3236 // Only base will allow this invocation to happen.
3238 if (method.IsAbstract) {
3239 rc.Report.SymbolRelatedToPreviousError (method);
3240 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3246 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3248 if (InstanceExpression == null)
3251 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3252 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3253 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3258 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3260 if (InstanceExpression == null)
3263 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3266 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3268 var ct = rc.CurrentType;
3269 if (ct == qualifier)
3272 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3275 qualifier = qualifier.GetDefinition ();
3276 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3283 public override bool ContainsEmitWithAwait ()
3285 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3288 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3291 type = type.GetDefinition ();
3293 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3296 type = type.DeclaringType;
3297 } while (type != null);
3302 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3304 if (InstanceExpression != null) {
3305 InstanceExpression = InstanceExpression.Resolve (rc);
3306 CheckProtectedMemberAccess (rc, member);
3309 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3310 UnsafeError (rc, loc);
3313 var dep = member.GetMissingDependencies ();
3315 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3318 if (!rc.IsObsolete) {
3319 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3321 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3324 if (!(member is FieldSpec))
3325 member.MemberDefinition.SetIsUsed ();
3328 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3330 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3333 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3335 rc.Report.SymbolRelatedToPreviousError (member);
3336 rc.Report.Error (1540, loc,
3337 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3338 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3341 public override void FlowAnalysis (FlowAnalysisContext fc)
3343 if (InstanceExpression != null)
3344 InstanceExpression.FlowAnalysis (fc);
3347 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3349 if (!ResolveInstanceExpressionCore (rc, rhs))
3353 // Check intermediate value modification which won't have any effect
3355 if (rhs != null && InstanceExpression.Type.IsStruct) {
3356 var fexpr = InstanceExpression as FieldExpr;
3357 if (fexpr != null) {
3358 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3361 if (fexpr.IsStatic) {
3362 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3363 fexpr.GetSignatureForError ());
3365 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3366 fexpr.GetSignatureForError ());
3372 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3373 if (rc.CurrentInitializerVariable != null) {
3374 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3375 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3377 rc.Report.Error (1612, loc,
3378 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3379 InstanceExpression.GetSignatureForError ());
3385 var lvr = InstanceExpression as LocalVariableReference;
3388 if (!lvr.local_info.IsReadonly)
3391 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3392 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3399 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3402 if (InstanceExpression != null) {
3403 if (InstanceExpression is TypeExpr) {
3404 var t = InstanceExpression.Type;
3406 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3407 if (oa != null && !rc.IsObsolete) {
3408 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3411 t = t.DeclaringType;
3412 } while (t != null);
3414 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3415 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3416 rc.Report.Error (176, loc,
3417 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3418 GetSignatureForError ());
3422 InstanceExpression = null;
3428 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3429 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3430 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3431 rc.Report.Error (236, loc,
3432 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3433 GetSignatureForError ());
3435 var fe = this as FieldExpr;
3436 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3437 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3438 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3440 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3444 rc.Report.Error (120, loc,
3445 "An object reference is required to access non-static member `{0}'",
3446 GetSignatureForError ());
3450 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3454 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3455 rc.Report.Error (38, loc,
3456 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3457 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3460 InstanceExpression = new This (loc).Resolve (rc);
3464 var me = InstanceExpression as MemberExpr;
3466 me.ResolveInstanceExpressionCore (rc, rhs);
3468 var fe = me as FieldExpr;
3469 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3470 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3471 rc.Report.Warning (1690, 1, loc,
3472 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3473 me.GetSignatureForError ());
3480 // Additional checks for l-value member access
3483 if (InstanceExpression is UnboxCast) {
3484 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3491 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3493 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3494 ec.Report.Warning (1720, 1, left.Location,
3495 "Expression will always cause a `{0}'", "System.NullReferenceException");
3498 InstanceExpression = left;
3502 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3504 TypeSpec instance_type = InstanceExpression.Type;
3505 if (TypeSpec.IsValueType (instance_type)) {
3506 if (InstanceExpression is IMemoryLocation) {
3507 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3509 // Cannot release the temporary variable when its address
3510 // is required to be on stack for any parent
3511 LocalTemporary t = new LocalTemporary (instance_type);
3512 InstanceExpression.Emit (ec);
3514 t.AddressOf (ec, AddressOp.Store);
3517 InstanceExpression.Emit (ec);
3519 // Only to make verifier happy
3520 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3521 ec.Emit (OpCodes.Box, instance_type);
3524 if (prepare_for_load)
3525 ec.Emit (OpCodes.Dup);
3528 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3531 public class ExtensionMethodCandidates
3533 readonly NamespaceContainer container;
3534 readonly IList<MethodSpec> methods;
3536 readonly IMemberContext context;
3538 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3540 this.context = context;
3541 this.methods = methods;
3542 this.container = nsContainer;
3543 this.index = lookupIndex;
3546 public NamespaceContainer Container {
3552 public IMemberContext Context {
3558 public int LookupIndex {
3564 public IList<MethodSpec> Methods {
3572 // Represents a group of extension method candidates for whole namespace
3574 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3576 ExtensionMethodCandidates candidates;
3577 public Expression ExtensionExpression;
3579 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3580 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3582 this.candidates = candidates;
3583 this.ExtensionExpression = extensionExpr;
3586 public override bool IsStatic {
3587 get { return true; }
3591 // For extension methodgroup we are not looking for base members but parent
3592 // namespace extension methods
3594 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3596 // TODO: candidates are null only when doing error reporting, that's
3597 // incorrect. We have to discover same extension methods in error mode
3598 if (candidates == null)
3601 int arity = type_arguments == null ? 0 : type_arguments.Count;
3603 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3604 if (candidates == null)
3607 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3610 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3612 // We are already here
3616 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3618 if (arguments == null)
3619 arguments = new Arguments (1);
3621 ExtensionExpression = ExtensionExpression.Resolve (ec);
3622 if (ExtensionExpression == null)
3625 var cand = candidates;
3626 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3627 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3629 // Restore candidates in case we are running in probing mode
3632 // Store resolved argument and restore original arguments
3634 // Clean-up modified arguments for error reporting
3635 arguments.RemoveAt (0);
3639 var me = ExtensionExpression as MemberExpr;
3641 me.ResolveInstanceExpression (ec, null);
3642 var fe = me as FieldExpr;
3644 fe.Spec.MemberDefinition.SetIsUsed ();
3647 InstanceExpression = null;
3651 #region IErrorHandler Members
3653 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3658 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3660 rc.Report.SymbolRelatedToPreviousError (best);
3661 rc.Report.Error (1928, loc,
3662 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3663 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3666 rc.Report.Error (1929, loc,
3667 "Extension method instance type `{0}' cannot be converted to `{1}'",
3668 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3674 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3679 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3688 /// MethodGroupExpr represents a group of method candidates which
3689 /// can be resolved to the best method overload
3691 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3693 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3695 protected IList<MemberSpec> Methods;
3696 MethodSpec best_candidate;
3697 TypeSpec best_candidate_return;
3698 protected TypeArguments type_arguments;
3700 SimpleName simple_name;
3701 protected TypeSpec queried_type;
3703 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3707 this.type = InternalType.MethodGroup;
3709 eclass = ExprClass.MethodGroup;
3710 queried_type = type;
3713 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3714 : this (new MemberSpec[] { m }, type, loc)
3720 public MethodSpec BestCandidate {
3722 return best_candidate;
3726 public TypeSpec BestCandidateReturnType {
3728 return best_candidate_return;
3732 public IList<MemberSpec> Candidates {
3738 protected override TypeSpec DeclaringType {
3740 return queried_type;
3744 public bool IsConditionallyExcluded {
3746 return Methods == Excluded;
3750 public override bool IsInstance {
3752 if (best_candidate != null)
3753 return !best_candidate.IsStatic;
3759 public override bool IsSideEffectFree {
3761 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3765 public override bool IsStatic {
3767 if (best_candidate != null)
3768 return best_candidate.IsStatic;
3774 public override string KindName {
3775 get { return "method"; }
3778 public override string Name {
3780 if (best_candidate != null)
3781 return best_candidate.Name;
3784 return Methods.First ().Name;
3791 // When best candidate is already know this factory can be used
3792 // to avoid expensive overload resolution to be called
3794 // NOTE: InstanceExpression has to be set manually
3796 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3798 return new MethodGroupExpr (best, queriedType, loc) {
3799 best_candidate = best,
3800 best_candidate_return = best.ReturnType
3804 public override string GetSignatureForError ()
3806 if (best_candidate != null)
3807 return best_candidate.GetSignatureForError ();
3809 return Methods.First ().GetSignatureForError ();
3812 public override Expression CreateExpressionTree (ResolveContext ec)
3814 if (best_candidate == null) {
3815 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3819 if (IsConditionallyExcluded)
3820 ec.Report.Error (765, loc,
3821 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3823 return new TypeOfMethod (best_candidate, loc);
3826 protected override Expression DoResolve (ResolveContext ec)
3828 this.eclass = ExprClass.MethodGroup;
3830 if (InstanceExpression != null) {
3831 InstanceExpression = InstanceExpression.Resolve (ec);
3832 if (InstanceExpression == null)
3839 public override void Emit (EmitContext ec)
3841 throw new NotSupportedException ();
3844 public void EmitCall (EmitContext ec, Arguments arguments)
3846 var call = new CallEmitter ();
3847 call.InstanceExpression = InstanceExpression;
3848 call.Emit (ec, best_candidate, arguments, loc);
3851 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3853 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3854 Name, target.GetSignatureForError ());
3857 public static bool IsExtensionMethodArgument (Expression expr)
3860 // LAMESPEC: No details about which expressions are not allowed
3862 return !(expr is TypeExpr) && !(expr is BaseThis);
3866 /// Find the Applicable Function Members (7.4.2.1)
3868 /// me: Method Group expression with the members to select.
3869 /// it might contain constructors or methods (or anything
3870 /// that maps to a method).
3872 /// Arguments: ArrayList containing resolved Argument objects.
3874 /// loc: The location if we want an error to be reported, or a Null
3875 /// location for "probing" purposes.
3877 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3878 /// that is the best match of me on Arguments.
3881 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3883 // TODO: causes issues with probing mode, remove explicit Kind check
3884 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3887 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3888 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3889 r.BaseMembersProvider = this;
3890 r.InstanceQualifier = this;
3893 if (cerrors != null)
3894 r.CustomErrors = cerrors;
3896 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3897 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3898 if (best_candidate == null)
3899 return r.BestCandidateIsDynamic ? this : null;
3901 // Overload resolver had to create a new method group, all checks bellow have already been executed
3902 if (r.BestCandidateNewMethodGroup != null)
3903 return r.BestCandidateNewMethodGroup;
3905 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3906 if (InstanceExpression != null) {
3907 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3908 InstanceExpression = null;
3910 if (best_candidate.IsStatic && simple_name != null) {
3911 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3914 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3918 ResolveInstanceExpression (ec, null);
3921 var base_override = CandidateToBaseOverride (ec, best_candidate);
3922 if (base_override == best_candidate) {
3923 best_candidate_return = r.BestCandidateReturnType;
3925 best_candidate = base_override;
3926 best_candidate_return = best_candidate.ReturnType;
3929 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3930 ConstraintChecker cc = new ConstraintChecker (ec);
3931 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3935 // Additional check for possible imported base override method which
3936 // could not be done during IsOverrideMethodBaseTypeAccessible
3938 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3939 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3940 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3941 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3944 // Speed up the check by not doing it on disallowed targets
3945 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3951 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3953 var fe = left as FieldExpr;
3956 // Using method-group on struct fields makes the struct assigned. I am not sure
3957 // why but that's what .net does
3959 fe.Spec.MemberDefinition.SetIsAssigned ();
3962 simple_name = original;
3963 return base.ResolveMemberAccess (ec, left, original);
3966 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3968 type_arguments = ta;
3971 #region IBaseMembersProvider Members
3973 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3975 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3978 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3980 if (queried_type == member.DeclaringType)
3983 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3984 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3988 // Extension methods lookup after ordinary methods candidates failed to apply
3990 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3992 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3995 if (!IsExtensionMethodArgument (InstanceExpression))
3998 int arity = type_arguments == null ? 0 : type_arguments.Count;
3999 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4000 if (methods == null)
4003 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4004 emg.SetTypeArguments (rc, type_arguments);
4011 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4013 public ConstructorInstanceQualifier (TypeSpec type)
4016 InstanceType = type;
4019 public TypeSpec InstanceType { get; private set; }
4021 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4023 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4027 public struct OverloadResolver
4030 public enum Restrictions
4034 ProbingOnly = 1 << 1,
4035 CovariantDelegate = 1 << 2,
4036 NoBaseMembers = 1 << 3,
4037 BaseMembersIncluded = 1 << 4
4040 public interface IBaseMembersProvider
4042 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4043 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4044 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4047 public interface IErrorHandler
4049 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4050 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4051 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4052 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4055 public interface IInstanceQualifier
4057 TypeSpec InstanceType { get; }
4058 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4061 sealed class NoBaseMembers : IBaseMembersProvider
4063 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4065 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4070 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4075 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4081 struct AmbiguousCandidate
4083 public readonly MemberSpec Member;
4084 public readonly bool Expanded;
4085 public readonly AParametersCollection Parameters;
4087 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4090 Parameters = parameters;
4091 Expanded = expanded;
4096 IList<MemberSpec> members;
4097 TypeArguments type_arguments;
4098 IBaseMembersProvider base_provider;
4099 IErrorHandler custom_errors;
4100 IInstanceQualifier instance_qualifier;
4101 Restrictions restrictions;
4102 MethodGroupExpr best_candidate_extension_group;
4103 TypeSpec best_candidate_return_type;
4105 SessionReportPrinter lambda_conv_msgs;
4107 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4108 : this (members, null, restrictions, loc)
4112 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4115 if (members == null || members.Count == 0)
4116 throw new ArgumentException ("empty members set");
4118 this.members = members;
4120 type_arguments = targs;
4121 this.restrictions = restrictions;
4122 if (IsDelegateInvoke)
4123 this.restrictions |= Restrictions.NoBaseMembers;
4125 base_provider = NoBaseMembers.Instance;
4130 public IBaseMembersProvider BaseMembersProvider {
4132 return base_provider;
4135 base_provider = value;
4139 public bool BestCandidateIsDynamic { get; set; }
4142 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4144 public MethodGroupExpr BestCandidateNewMethodGroup {
4146 return best_candidate_extension_group;
4151 // Return type can be different between best candidate and closest override
4153 public TypeSpec BestCandidateReturnType {
4155 return best_candidate_return_type;
4159 public IErrorHandler CustomErrors {
4161 return custom_errors;
4164 custom_errors = value;
4168 TypeSpec DelegateType {
4170 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4171 throw new InternalErrorException ("Not running in delegate mode", loc);
4173 return members [0].DeclaringType;
4177 public IInstanceQualifier InstanceQualifier {
4179 return instance_qualifier;
4182 instance_qualifier = value;
4186 bool IsProbingOnly {
4188 return (restrictions & Restrictions.ProbingOnly) != 0;
4192 bool IsDelegateInvoke {
4194 return (restrictions & Restrictions.DelegateInvoke) != 0;
4201 // 7.4.3.3 Better conversion from expression
4202 // Returns : 1 if a->p is better,
4203 // 2 if a->q is better,
4204 // 0 if neither is better
4206 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4208 TypeSpec argument_type = a.Type;
4211 // If argument is an anonymous function
4213 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4215 // p and q are delegate types or expression tree types
4217 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4218 if (q.MemberDefinition != p.MemberDefinition) {
4223 // Uwrap delegate from Expression<T>
4225 q = TypeManager.GetTypeArguments (q)[0];
4226 p = TypeManager.GetTypeArguments (p)[0];
4229 var p_m = Delegate.GetInvokeMethod (p);
4230 var q_m = Delegate.GetInvokeMethod (q);
4233 // With identical parameter lists
4235 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4244 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4246 if (p.Kind == MemberKind.Void) {
4247 return q.Kind != MemberKind.Void ? 2 : 0;
4251 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4253 if (q.Kind == MemberKind.Void) {
4254 return p.Kind != MemberKind.Void ? 1: 0;
4257 var am = (AnonymousMethodExpression) a.Expr;
4260 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4261 // better conversion is performed between underlying types Y1 and Y2
4263 if (p.IsGenericTask || q.IsGenericTask) {
4264 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4265 q = q.TypeArguments[0];
4266 p = p.TypeArguments[0];
4268 } else if (q != p) {
4270 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4272 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4273 var am_rt = am.InferReturnType (ec, null, orig_q);
4274 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4276 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4277 var am_rt = am.InferReturnType (ec, null, orig_p);
4278 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4284 // The parameters are identicial and return type is not void, use better type conversion
4285 // on return type to determine better one
4288 if (argument_type == p)
4291 if (argument_type == q)
4295 return BetterTypeConversion (ec, p, q);
4299 // 7.4.3.4 Better conversion from type
4301 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4303 if (p == null || q == null)
4304 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4306 switch (p.BuiltinType) {
4307 case BuiltinTypeSpec.Type.Int:
4308 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4311 case BuiltinTypeSpec.Type.Long:
4312 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4315 case BuiltinTypeSpec.Type.SByte:
4316 switch (q.BuiltinType) {
4317 case BuiltinTypeSpec.Type.Byte:
4318 case BuiltinTypeSpec.Type.UShort:
4319 case BuiltinTypeSpec.Type.UInt:
4320 case BuiltinTypeSpec.Type.ULong:
4324 case BuiltinTypeSpec.Type.Short:
4325 switch (q.BuiltinType) {
4326 case BuiltinTypeSpec.Type.UShort:
4327 case BuiltinTypeSpec.Type.UInt:
4328 case BuiltinTypeSpec.Type.ULong:
4332 case BuiltinTypeSpec.Type.Dynamic:
4333 // Dynamic is never better
4337 switch (q.BuiltinType) {
4338 case BuiltinTypeSpec.Type.Int:
4339 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4342 case BuiltinTypeSpec.Type.Long:
4343 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4346 case BuiltinTypeSpec.Type.SByte:
4347 switch (p.BuiltinType) {
4348 case BuiltinTypeSpec.Type.Byte:
4349 case BuiltinTypeSpec.Type.UShort:
4350 case BuiltinTypeSpec.Type.UInt:
4351 case BuiltinTypeSpec.Type.ULong:
4355 case BuiltinTypeSpec.Type.Short:
4356 switch (p.BuiltinType) {
4357 case BuiltinTypeSpec.Type.UShort:
4358 case BuiltinTypeSpec.Type.UInt:
4359 case BuiltinTypeSpec.Type.ULong:
4363 case BuiltinTypeSpec.Type.Dynamic:
4364 // Dynamic is never better
4368 // FIXME: handle lifted operators
4370 // TODO: this is expensive
4371 Expression p_tmp = new EmptyExpression (p);
4372 Expression q_tmp = new EmptyExpression (q);
4374 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4375 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4377 if (p_to_q && !q_to_p)
4380 if (q_to_p && !p_to_q)
4387 /// Determines "Better function" between candidate
4388 /// and the current best match
4391 /// Returns a boolean indicating :
4392 /// false if candidate ain't better
4393 /// true if candidate is better than the current best match
4395 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4396 MemberSpec best, AParametersCollection bparam, bool best_params)
4398 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4399 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4401 bool better_at_least_one = false;
4402 bool are_equivalent = true;
4403 int args_count = args == null ? 0 : args.Count;
4407 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4410 // Default arguments are ignored for better decision
4411 if (a.IsDefaultArgument)
4415 // When comparing named argument the parameter type index has to be looked up
4416 // in original parameter set (override version for virtual members)
4418 NamedArgument na = a as NamedArgument;
4420 int idx = cparam.GetParameterIndexByName (na.Name);
4421 ct = candidate_pd.Types[idx];
4422 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4423 ct = TypeManager.GetElementType (ct);
4425 idx = bparam.GetParameterIndexByName (na.Name);
4426 bt = best_pd.Types[idx];
4427 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4428 bt = TypeManager.GetElementType (bt);
4430 ct = candidate_pd.Types[c_idx];
4431 bt = best_pd.Types[b_idx];
4433 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4434 ct = TypeManager.GetElementType (ct);
4438 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4439 bt = TypeManager.GetElementType (bt);
4444 if (TypeSpecComparer.IsEqual (ct, bt))
4447 are_equivalent = false;
4448 int result = BetterExpressionConversion (ec, a, ct, bt);
4450 // for each argument, the conversion to 'ct' should be no worse than
4451 // the conversion to 'bt'.
4455 // for at least one argument, the conversion to 'ct' should be better than
4456 // the conversion to 'bt'.
4458 better_at_least_one = true;
4461 if (better_at_least_one)
4465 // Tie-breaking rules are applied only for equivalent parameter types
4467 if (!are_equivalent)
4471 // If candidate is applicable in its normal form and best has a params array and is applicable
4472 // only in its expanded form, then candidate is better
4474 if (candidate_params != best_params)
4475 return !candidate_params;
4478 // We have not reached end of parameters list due to params or used default parameters
4480 while (j < candidate_pd.Count && j < best_pd.Count) {
4481 var cand_param = candidate_pd.FixedParameters [j];
4482 var best_param = best_pd.FixedParameters [j];
4484 if (candidate_pd.Count == best_pd.Count) {
4488 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4489 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4491 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4492 return cand_param.HasDefaultValue;
4494 if (cand_param.HasDefaultValue) {
4500 // Neither is better when not all arguments are provided
4502 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4503 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4504 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4506 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4513 if (candidate_pd.Count != best_pd.Count)
4514 return candidate_pd.Count < best_pd.Count;
4517 // One is a non-generic method and second is a generic method, then non-generic is better
4519 if (best.IsGeneric != candidate.IsGeneric)
4520 return best.IsGeneric;
4523 // Both methods have the same number of parameters, and the parameters have equal types
4524 // Pick the "more specific" signature using rules over original (non-inflated) types
4526 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4527 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4529 bool specific_at_least_once = false;
4530 for (j = 0; j < args_count; ++j) {
4531 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4533 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4534 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4536 ct = candidate_def_pd.Types[j];
4537 bt = best_def_pd.Types[j];
4542 TypeSpec specific = MoreSpecific (ct, bt);
4546 specific_at_least_once = true;
4549 if (specific_at_least_once)
4555 static bool CheckInflatedArguments (MethodSpec ms)
4557 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4560 // Setup constraint checker for probing only
4561 ConstraintChecker cc = new ConstraintChecker (null);
4563 var mp = ms.Parameters.Types;
4564 for (int i = 0; i < mp.Length; ++i) {
4565 var type = mp[i] as InflatedTypeSpec;
4569 var targs = type.TypeArguments;
4570 if (targs.Length == 0)
4573 // TODO: Checking inflated MVAR arguments should be enough
4574 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4581 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4583 rc.Report.Error (1729, loc,
4584 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4585 type.GetSignatureForError (), argCount.ToString ());
4589 // Determines if the candidate method is applicable to the given set of arguments
4590 // There could be two different set of parameters for same candidate where one
4591 // is the closest override for default values and named arguments checks and second
4592 // one being the virtual base for the parameter types and modifiers.
4594 // A return value rates candidate method compatibility,
4595 // 0 = the best, int.MaxValue = the worst
4598 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)
4600 // Parameters of most-derived type used mainly for named and optional parameters
4601 var pd = pm.Parameters;
4603 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4604 // params modifier instead of most-derived type
4605 var cpd = ((IParametersMember) candidate).Parameters;
4606 int param_count = pd.Count;
4607 int optional_count = 0;
4609 Arguments orig_args = arguments;
4611 if (arg_count != param_count) {
4613 // No arguments expansion when doing exact match for delegates
4615 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4616 for (int i = 0; i < pd.Count; ++i) {
4617 if (pd.FixedParameters[i].HasDefaultValue) {
4618 optional_count = pd.Count - i;
4624 if (optional_count != 0) {
4625 // Readjust expected number when params used
4626 if (cpd.HasParams) {
4628 if (arg_count < param_count)
4630 } else if (arg_count > param_count) {
4631 int args_gap = System.Math.Abs (arg_count - param_count);
4632 return int.MaxValue - 10000 + args_gap;
4633 } else if (arg_count < param_count - optional_count) {
4634 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4635 return int.MaxValue - 10000 + args_gap;
4637 } else if (arg_count != param_count) {
4638 int args_gap = System.Math.Abs (arg_count - param_count);
4640 return int.MaxValue - 10000 + args_gap;
4641 if (arg_count < param_count - 1)
4642 return int.MaxValue - 10000 + args_gap;
4645 // Resize to fit optional arguments
4646 if (optional_count != 0) {
4647 if (arguments == null) {
4648 arguments = new Arguments (optional_count);
4650 // Have to create a new container, so the next run can do same
4651 var resized = new Arguments (param_count);
4652 resized.AddRange (arguments);
4653 arguments = resized;
4656 for (int i = arg_count; i < param_count; ++i)
4657 arguments.Add (null);
4661 if (arg_count > 0) {
4663 // Shuffle named arguments to the right positions if there are any
4665 if (arguments[arg_count - 1] is NamedArgument) {
4666 arg_count = arguments.Count;
4668 for (int i = 0; i < arg_count; ++i) {
4669 bool arg_moved = false;
4671 NamedArgument na = arguments[i] as NamedArgument;
4675 int index = pd.GetParameterIndexByName (na.Name);
4677 // Named parameter not found
4681 // already reordered
4686 if (index >= param_count) {
4687 // When using parameters which should not be available to the user
4688 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4691 arguments.Add (null);
4695 if (index == arg_count)
4698 temp = arguments [index];
4700 // The slot has been taken by positional argument
4701 if (temp != null && !(temp is NamedArgument))
4706 arguments = arguments.MarkOrderedArgument (na);
4710 if (arguments == orig_args) {
4711 arguments = new Arguments (orig_args.Count);
4712 arguments.AddRange (orig_args);
4715 arguments[index] = arguments[i];
4716 arguments[i] = temp;
4723 arg_count = arguments.Count;
4725 } else if (arguments != null) {
4726 arg_count = arguments.Count;
4730 // Don't do any expensive checks when the candidate cannot succeed
4732 if (arg_count != param_count && !cpd.HasParams)
4733 return (param_count - arg_count) * 2 + 1;
4735 var dep = candidate.GetMissingDependencies ();
4737 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4742 // 1. Handle generic method using type arguments when specified or type inference
4745 var ms = candidate as MethodSpec;
4746 if (ms != null && ms.IsGeneric) {
4747 if (type_arguments != null) {
4748 var g_args_count = ms.Arity;
4749 if (g_args_count != type_arguments.Count)
4750 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4752 if (type_arguments.Arguments != null)
4753 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4756 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4757 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4758 // candidate was found use the set to report more details about what was wrong with lambda body.
4759 // The general idea is to distinguish between code errors and errors caused by
4760 // trial-and-error type inference
4762 if (lambda_conv_msgs == null) {
4763 for (int i = 0; i < arg_count; i++) {
4764 Argument a = arguments[i];
4768 var am = a.Expr as AnonymousMethodExpression;
4770 if (lambda_conv_msgs == null)
4771 lambda_conv_msgs = new SessionReportPrinter ();
4773 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4778 var ti = new TypeInference (arguments);
4779 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4782 return ti.InferenceScore - 20000;
4785 // Clear any error messages when the result was success
4787 if (lambda_conv_msgs != null)
4788 lambda_conv_msgs.ClearSession ();
4790 if (i_args.Length != 0) {
4791 ms = ms.MakeGenericMethod (ec, i_args);
4796 // Type arguments constraints have to match for the method to be applicable
4798 if (!CheckInflatedArguments (ms)) {
4800 return int.MaxValue - 25000;
4804 // We have a generic return type and at same time the method is override which
4805 // means we have to also inflate override return type in case the candidate is
4806 // best candidate and override return type is different to base return type.
4808 // virtual Foo<T, object> with override Foo<T, dynamic>
4810 if (candidate != pm) {
4811 MethodSpec override_ms = (MethodSpec) pm;
4812 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4813 returnType = inflator.Inflate (returnType);
4815 returnType = ms.ReturnType;
4822 if (type_arguments != null)
4823 return int.MaxValue - 15000;
4829 // 2. Each argument has to be implicitly convertible to method parameter
4831 Parameter.Modifier p_mod = 0;
4834 for (int i = 0; i < arg_count; i++) {
4835 Argument a = arguments[i];
4837 var fp = pd.FixedParameters[i];
4838 if (!fp.HasDefaultValue) {
4839 arguments = orig_args;
4840 return arg_count * 2 + 2;
4844 // Get the default value expression, we can use the same expression
4845 // if the type matches
4847 Expression e = fp.DefaultValue;
4849 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4851 // Restore for possible error reporting
4852 for (int ii = i; ii < arg_count; ++ii)
4853 arguments.RemoveAt (i);
4855 return (arg_count - i) * 2 + 1;
4859 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4861 // LAMESPEC: Attributes can be mixed together with build-in priority
4863 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4864 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4865 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4866 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4867 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4868 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4872 arguments[i] = new Argument (e, Argument.AType.Default);
4876 if (p_mod != Parameter.Modifier.PARAMS) {
4877 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4879 } else if (!params_expanded_form) {
4880 params_expanded_form = true;
4881 pt = ((ElementTypeSpec) pt).Element;
4887 if (!params_expanded_form) {
4888 if (a.ArgType == Argument.AType.ExtensionType) {
4890 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4892 // LAMESPEC: or implicit type parameter conversion
4895 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4896 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4897 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4902 score = IsArgumentCompatible (ec, a, p_mod, pt);
4905 dynamicArgument = true;
4910 // It can be applicable in expanded form (when not doing exact match like for delegates)
4912 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4913 if (!params_expanded_form) {
4914 pt = ((ElementTypeSpec) pt).Element;
4918 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4921 params_expanded_form = true;
4922 dynamicArgument = true;
4923 } else if (score == 0 || arg_count > pd.Count) {
4924 params_expanded_form = true;
4929 if (params_expanded_form)
4931 return (arg_count - i) * 2 + score;
4936 // Restore original arguments for dynamic binder to keep the intention of original source code
4938 if (dynamicArgument)
4939 arguments = orig_args;
4944 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4946 if (e is Constant && e.Type == ptype)
4950 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4952 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4953 e = new MemberAccess (new MemberAccess (new MemberAccess (
4954 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4955 } else if (e is Constant) {
4957 // Handles int to int? conversions, DefaultParameterValue check
4959 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4963 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4966 return e.Resolve (ec);
4970 // Tests argument compatibility with the parameter
4971 // The possible return values are
4973 // 1 - modifier mismatch
4974 // 2 - type mismatch
4975 // -1 - dynamic binding required
4977 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4980 // Types have to be identical when ref or out modifer
4981 // is used and argument is not of dynamic type
4983 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4984 if (argument.Type != parameter) {
4986 // Do full equality check after quick path
4988 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4990 // Using dynamic for ref/out parameter can still succeed at runtime
4992 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4999 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5001 // Using dynamic for ref/out parameter can still succeed at runtime
5003 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5010 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5014 // Use implicit conversion in all modes to return same candidates when the expression
5015 // is used as argument or delegate conversion
5017 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5018 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5025 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5027 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5029 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5032 var ac_p = p as ArrayContainer;
5034 var ac_q = q as ArrayContainer;
5038 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5039 if (specific == ac_p.Element)
5041 if (specific == ac_q.Element)
5043 } else if (p.IsGeneric && q.IsGeneric) {
5044 var pargs = TypeManager.GetTypeArguments (p);
5045 var qargs = TypeManager.GetTypeArguments (q);
5047 bool p_specific_at_least_once = false;
5048 bool q_specific_at_least_once = false;
5050 for (int i = 0; i < pargs.Length; i++) {
5051 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5052 if (specific == pargs[i])
5053 p_specific_at_least_once = true;
5054 if (specific == qargs[i])
5055 q_specific_at_least_once = true;
5058 if (p_specific_at_least_once && !q_specific_at_least_once)
5060 if (!p_specific_at_least_once && q_specific_at_least_once)
5068 // Find the best method from candidate list
5070 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5072 List<AmbiguousCandidate> ambiguous_candidates = null;
5074 MemberSpec best_candidate;
5075 Arguments best_candidate_args = null;
5076 bool best_candidate_params = false;
5077 bool best_candidate_dynamic = false;
5078 int best_candidate_rate;
5079 IParametersMember best_parameter_member = null;
5081 int args_count = args != null ? args.Count : 0;
5083 Arguments candidate_args = args;
5084 bool error_mode = false;
5085 MemberSpec invocable_member = null;
5088 best_candidate = null;
5089 best_candidate_rate = int.MaxValue;
5091 var type_members = members;
5093 for (int i = 0; i < type_members.Count; ++i) {
5094 var member = type_members[i];
5097 // Methods in a base class are not candidates if any method in a derived
5098 // class is applicable
5100 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5104 if (!member.IsAccessible (rc))
5107 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5110 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5111 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5116 IParametersMember pm = member as IParametersMember;
5119 // Will use it later to report ambiguity between best method and invocable member
5121 if (Invocation.IsMemberInvocable (member))
5122 invocable_member = member;
5128 // Overload resolution is looking for base member but using parameter names
5129 // and default values from the closest member. That means to do expensive lookup
5130 // for the closest override for virtual or abstract members
5132 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5133 var override_params = base_provider.GetOverrideMemberParameters (member);
5134 if (override_params != null)
5135 pm = override_params;
5139 // Check if the member candidate is applicable
5141 bool params_expanded_form = false;
5142 bool dynamic_argument = false;
5143 TypeSpec rt = pm.MemberType;
5144 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5146 if (lambda_conv_msgs != null)
5147 lambda_conv_msgs.EndSession ();
5150 // How does it score compare to others
5152 if (candidate_rate < best_candidate_rate) {
5154 // Fatal error (missing dependency), cannot continue
5155 if (candidate_rate < 0)
5158 best_candidate_rate = candidate_rate;
5159 best_candidate = member;
5160 best_candidate_args = candidate_args;
5161 best_candidate_params = params_expanded_form;
5162 best_candidate_dynamic = dynamic_argument;
5163 best_parameter_member = pm;
5164 best_candidate_return_type = rt;
5165 } else if (candidate_rate == 0) {
5167 // The member look is done per type for most operations but sometimes
5168 // it's not possible like for binary operators overload because they
5169 // are unioned between 2 sides
5171 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5172 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5177 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5179 // We pack all interface members into top level type which makes the overload resolution
5180 // more complicated for interfaces. We compensate it by removing methods with same
5181 // signature when building the cache hence this path should not really be hit often
5184 // interface IA { void Foo (int arg); }
5185 // interface IB : IA { void Foo (params int[] args); }
5187 // IB::Foo is the best overload when calling IB.Foo (1)
5190 if (ambiguous_candidates != null) {
5191 foreach (var amb_cand in ambiguous_candidates) {
5192 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5201 ambiguous_candidates = null;
5204 // Is the new candidate better
5205 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5209 best_candidate = member;
5210 best_candidate_args = candidate_args;
5211 best_candidate_params = params_expanded_form;
5212 best_candidate_dynamic = dynamic_argument;
5213 best_parameter_member = pm;
5214 best_candidate_return_type = rt;
5216 // It's not better but any other found later could be but we are not sure yet
5217 if (ambiguous_candidates == null)
5218 ambiguous_candidates = new List<AmbiguousCandidate> ();
5220 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5224 // Restore expanded arguments
5225 candidate_args = args;
5227 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5230 // We've found exact match
5232 if (best_candidate_rate == 0)
5236 // Try extension methods lookup when no ordinary method match was found and provider enables it
5239 var emg = base_provider.LookupExtensionMethod (rc);
5241 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5243 best_candidate_extension_group = emg;
5244 return (T) (MemberSpec) emg.BestCandidate;
5249 // Don't run expensive error reporting mode for probing
5256 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5259 lambda_conv_msgs = null;
5264 // No best member match found, report an error
5266 if (best_candidate_rate != 0 || error_mode) {
5267 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5271 if (best_candidate_dynamic) {
5272 if (args[0].ArgType == Argument.AType.ExtensionType) {
5273 rc.Report.Error (1973, loc,
5274 "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",
5275 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5279 // Check type constraints only when explicit type arguments are used
5281 if (best_candidate.IsGeneric && type_arguments != null) {
5282 MethodSpec bc = best_candidate as MethodSpec;
5283 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5284 ConstraintChecker cc = new ConstraintChecker (rc);
5285 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5289 BestCandidateIsDynamic = true;
5294 // These flags indicates we are running delegate probing conversion. No need to
5295 // do more expensive checks
5297 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5298 return (T) best_candidate;
5300 if (ambiguous_candidates != null) {
5302 // Now check that there are no ambiguities i.e the selected method
5303 // should be better than all the others
5305 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5306 var candidate = ambiguous_candidates [ix];
5308 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5309 var ambiguous = candidate.Member;
5310 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5311 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5312 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5313 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5314 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5317 return (T) best_candidate;
5322 if (invocable_member != null && !IsProbingOnly) {
5323 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5324 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5325 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5326 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5330 // And now check if the arguments are all
5331 // compatible, perform conversions if
5332 // necessary etc. and return if everything is
5335 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5338 if (best_candidate == null)
5342 // Don't run possibly expensive checks in probing mode
5344 if (!IsProbingOnly && !rc.IsInProbingMode) {
5346 // Check ObsoleteAttribute on the best method
5348 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5349 if (oa != null && !rc.IsObsolete)
5350 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5352 best_candidate.MemberDefinition.SetIsUsed ();
5355 args = best_candidate_args;
5356 return (T) best_candidate;
5359 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5361 return ResolveMember<MethodSpec> (rc, ref args);
5364 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5365 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5367 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5370 if (a.Type == InternalType.ErrorType)
5373 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5374 ec.Report.SymbolRelatedToPreviousError (method);
5375 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5376 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5377 TypeManager.CSharpSignature (method));
5380 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5381 TypeManager.CSharpSignature (method));
5382 } else if (IsDelegateInvoke) {
5383 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5384 DelegateType.GetSignatureForError ());
5386 ec.Report.SymbolRelatedToPreviousError (method);
5387 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5388 method.GetSignatureForError ());
5391 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5393 string index = (idx + 1).ToString ();
5394 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5395 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5396 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5397 index, Parameter.GetModifierSignature (a.Modifier));
5399 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5400 index, Parameter.GetModifierSignature (mod));
5402 string p1 = a.GetSignatureForError ();
5403 string p2 = paramType.GetSignatureForError ();
5406 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5407 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5410 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5411 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5412 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5415 ec.Report.Error (1503, a.Expr.Location,
5416 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5421 // We have failed to find exact match so we return error info about the closest match
5423 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5425 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5426 int arg_count = args == null ? 0 : args.Count;
5428 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5429 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5430 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5434 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5439 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5440 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5441 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5445 // For candidates which match on parameters count report more details about incorrect arguments
5448 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5449 // Reject any inaccessible member
5450 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5451 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5452 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5456 var ms = best_candidate as MethodSpec;
5457 if (ms != null && ms.IsGeneric) {
5458 bool constr_ok = true;
5459 if (ms.TypeArguments != null)
5460 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5462 if (ta_count == 0 && ms.TypeArguments == null) {
5463 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5467 rc.Report.Error (411, loc,
5468 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5469 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5476 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5482 // We failed to find any method with correct argument count, report best candidate
5484 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5487 if (best_candidate.Kind == MemberKind.Constructor) {
5488 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5489 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5490 } else if (IsDelegateInvoke) {
5491 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5492 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5493 DelegateType.GetSignatureForError (), arg_count.ToString ());
5495 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5496 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5497 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5498 name, arg_count.ToString ());
5502 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5504 var p = ((IParametersMember)best_candidate).Parameters;
5509 for (int i = p.Count - 1; i != 0; --i) {
5510 var fp = p.FixedParameters [i];
5511 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5518 foreach (var arg in args) {
5519 var na = arg as NamedArgument;
5523 if (na.Name == name) {
5532 return args.Count + 1 == pm.Parameters.Count;
5535 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5537 var pd = pm.Parameters;
5538 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5540 Parameter.Modifier p_mod = 0;
5542 int a_idx = 0, a_pos = 0;
5544 ArrayInitializer params_initializers = null;
5545 bool has_unsafe_arg = pm.MemberType.IsPointer;
5546 int arg_count = args == null ? 0 : args.Count;
5548 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5553 if (p_mod != Parameter.Modifier.PARAMS) {
5554 p_mod = pd.FixedParameters[a_idx].ModFlags;
5556 has_unsafe_arg |= pt.IsPointer;
5558 if (p_mod == Parameter.Modifier.PARAMS) {
5559 if (chose_params_expanded) {
5560 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5561 pt = TypeManager.GetElementType (pt);
5567 // Types have to be identical when ref or out modifer is used
5569 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5570 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5573 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5579 NamedArgument na = a as NamedArgument;
5581 int name_index = pd.GetParameterIndexByName (na.Name);
5582 if (name_index < 0 || name_index >= pd.Count) {
5583 if (IsDelegateInvoke) {
5584 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5585 ec.Report.Error (1746, na.Location,
5586 "The delegate `{0}' does not contain a parameter named `{1}'",
5587 DelegateType.GetSignatureForError (), na.Name);
5589 ec.Report.SymbolRelatedToPreviousError (member);
5590 ec.Report.Error (1739, na.Location,
5591 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5592 TypeManager.CSharpSignature (member), na.Name);
5594 } else if (args[name_index] != a && args[name_index] != null) {
5595 if (IsDelegateInvoke)
5596 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5598 ec.Report.SymbolRelatedToPreviousError (member);
5600 ec.Report.Error (1744, na.Location,
5601 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5606 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5609 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5610 custom_errors.NoArgumentMatch (ec, member);
5615 if (a.ArgType == Argument.AType.ExtensionType) {
5616 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5619 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5621 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5624 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5631 // Convert params arguments to an array initializer
5633 if (params_initializers != null) {
5634 // we choose to use 'a.Expr' rather than 'conv' so that
5635 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5636 params_initializers.Add (a.Expr);
5637 args.RemoveAt (a_idx--);
5643 // Update the argument with the implicit conversion
5647 if (a_idx != arg_count) {
5648 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5653 // Fill not provided arguments required by params modifier
5655 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5657 args = new Arguments (1);
5659 pt = ptypes[pd.Count - 1];
5660 pt = TypeManager.GetElementType (pt);
5661 has_unsafe_arg |= pt.IsPointer;
5662 params_initializers = new ArrayInitializer (0, loc);
5666 // Append an array argument with all params arguments
5668 if (params_initializers != null) {
5669 args.Add (new Argument (
5670 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5674 if (has_unsafe_arg && !ec.IsUnsafe) {
5675 Expression.UnsafeError (ec, loc);
5679 // We could infer inaccesible type arguments
5681 if (type_arguments == null && member.IsGeneric) {
5682 var ms = (MethodSpec) member;
5683 foreach (var ta in ms.TypeArguments) {
5684 if (!ta.IsAccessible (ec)) {
5685 ec.Report.SymbolRelatedToPreviousError (ta);
5686 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5696 public class ConstantExpr : MemberExpr
5698 readonly ConstSpec constant;
5700 public ConstantExpr (ConstSpec constant, Location loc)
5702 this.constant = constant;
5706 public override string Name {
5707 get { throw new NotImplementedException (); }
5710 public override string KindName {
5711 get { return "constant"; }
5714 public override bool IsInstance {
5715 get { return !IsStatic; }
5718 public override bool IsStatic {
5719 get { return true; }
5722 protected override TypeSpec DeclaringType {
5723 get { return constant.DeclaringType; }
5726 public override Expression CreateExpressionTree (ResolveContext ec)
5728 throw new NotSupportedException ("ET");
5731 protected override Expression DoResolve (ResolveContext rc)
5733 ResolveInstanceExpression (rc, null);
5734 DoBestMemberChecks (rc, constant);
5736 var c = constant.GetConstant (rc);
5738 // Creates reference expression to the constant value
5739 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5742 public override void Emit (EmitContext ec)
5744 throw new NotSupportedException ();
5747 public override string GetSignatureForError ()
5749 return constant.GetSignatureForError ();
5752 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5754 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5759 // Fully resolved expression that references a Field
5761 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5763 protected FieldSpec spec;
5764 VariableInfo variable_info;
5766 LocalTemporary temp;
5769 protected FieldExpr (Location l)
5774 public FieldExpr (FieldSpec spec, Location loc)
5779 type = spec.MemberType;
5782 public FieldExpr (FieldBase fi, Location l)
5789 public override string Name {
5795 public bool IsHoisted {
5797 IVariableReference hv = InstanceExpression as IVariableReference;
5798 return hv != null && hv.IsHoisted;
5802 public override bool IsInstance {
5804 return !spec.IsStatic;
5808 public override bool IsStatic {
5810 return spec.IsStatic;
5814 public override string KindName {
5815 get { return "field"; }
5818 public FieldSpec Spec {
5824 protected override TypeSpec DeclaringType {
5826 return spec.DeclaringType;
5830 public VariableInfo VariableInfo {
5832 return variable_info;
5838 public override string GetSignatureForError ()
5840 return spec.GetSignatureForError ();
5843 public bool IsMarshalByRefAccess (ResolveContext rc)
5845 // Checks possible ldflda of field access expression
5846 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5847 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5848 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5851 public void SetHasAddressTaken ()
5853 IVariableReference vr = InstanceExpression as IVariableReference;
5855 vr.SetHasAddressTaken ();
5859 protected override void CloneTo (CloneContext clonectx, Expression target)
5861 var t = (FieldExpr) target;
5863 if (InstanceExpression != null)
5864 t.InstanceExpression = InstanceExpression.Clone (clonectx);
5867 public override Expression CreateExpressionTree (ResolveContext ec)
5869 return CreateExpressionTree (ec, true);
5872 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5875 Expression instance;
5877 if (InstanceExpression == null) {
5878 instance = new NullLiteral (loc);
5879 } else if (convertInstance) {
5880 instance = InstanceExpression.CreateExpressionTree (ec);
5882 args = new Arguments (1);
5883 args.Add (new Argument (InstanceExpression));
5884 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5887 args = Arguments.CreateForExpressionTree (ec, null,
5889 CreateTypeOfExpression ());
5891 return CreateExpressionFactoryCall (ec, "Field", args);
5894 public Expression CreateTypeOfExpression ()
5896 return new TypeOfField (spec, loc);
5899 protected override Expression DoResolve (ResolveContext ec)
5901 spec.MemberDefinition.SetIsUsed ();
5903 return DoResolve (ec, null);
5906 Expression DoResolve (ResolveContext ec, Expression rhs)
5908 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5911 if (ResolveInstanceExpression (ec, rhs)) {
5912 // Resolve the field's instance expression while flow analysis is turned
5913 // off: when accessing a field "a.b", we must check whether the field
5914 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5916 if (lvalue_instance) {
5917 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5919 Expression right_side =
5920 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5922 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5924 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5927 if (InstanceExpression == null)
5931 DoBestMemberChecks (ec, spec);
5934 var fb = spec as FixedFieldSpec;
5935 IVariableReference var = InstanceExpression as IVariableReference;
5938 IFixedExpression fe = InstanceExpression as IFixedExpression;
5939 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5940 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5943 if (InstanceExpression.eclass != ExprClass.Variable) {
5944 ec.Report.SymbolRelatedToPreviousError (spec);
5945 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5946 TypeManager.GetFullNameSignature (spec));
5947 } else if (var != null && var.IsHoisted) {
5948 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5951 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5955 // Set flow-analysis variable info for struct member access. It will be check later
5956 // for precise error reporting
5958 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5959 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5962 eclass = ExprClass.Variable;
5966 public void SetFieldAssigned (FlowAnalysisContext fc)
5971 bool lvalue_instance = spec.DeclaringType.IsStruct;
5972 if (lvalue_instance) {
5973 var var = InstanceExpression as IVariableReference;
5974 if (var != null && var.VariableInfo != null) {
5975 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5979 var fe = InstanceExpression as FieldExpr;
5981 Expression instance;
5984 instance = fe.InstanceExpression;
5985 var fe_instance = instance as FieldExpr;
5986 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5987 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5988 var var = InstanceExpression as IVariableReference;
5989 if (var != null && var.VariableInfo == null) {
5990 var var_inst = instance as IVariableReference;
5991 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5992 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5996 if (fe_instance != null) {
6005 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6006 instance.FlowAnalysis (fc);
6008 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6009 InstanceExpression.FlowAnalysis (fc);
6013 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6015 // The return value is always null. Returning a value simplifies calling code.
6017 if (right_side == EmptyExpression.OutAccess) {
6019 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6020 GetSignatureForError ());
6022 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6023 GetSignatureForError ());
6029 if (right_side == EmptyExpression.LValueMemberAccess) {
6030 // Already reported as CS1648/CS1650
6034 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6036 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6037 GetSignatureForError ());
6039 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6040 GetSignatureForError ());
6046 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6047 GetSignatureForError ());
6049 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6050 GetSignatureForError ());
6056 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6058 if (spec is FixedFieldSpec) {
6059 // It could be much better error message but we want to be error compatible
6060 Error_ValueAssignment (ec, right_side);
6063 Expression e = DoResolve (ec, right_side);
6068 spec.MemberDefinition.SetIsAssigned ();
6070 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6071 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6072 ec.Report.Warning (420, 1, loc,
6073 "`{0}': A volatile field references will not be treated as volatile",
6074 spec.GetSignatureForError ());
6077 if (spec.IsReadOnly) {
6078 // InitOnly fields can only be assigned in constructors or initializers
6079 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6080 return Error_AssignToReadonly (ec, right_side);
6082 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6084 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6085 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6086 return Error_AssignToReadonly (ec, right_side);
6087 // static InitOnly fields cannot be assigned-to in an instance constructor
6088 if (IsStatic && !ec.IsStatic)
6089 return Error_AssignToReadonly (ec, right_side);
6090 // instance constructors can't modify InitOnly fields of other instances of the same type
6091 if (!IsStatic && !(InstanceExpression is This))
6092 return Error_AssignToReadonly (ec, right_side);
6096 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6097 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6098 ec.Report.Warning (197, 1, loc,
6099 "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",
6100 GetSignatureForError ());
6103 eclass = ExprClass.Variable;
6107 public override void FlowAnalysis (FlowAnalysisContext fc)
6109 var var = InstanceExpression as IVariableReference;
6111 var vi = var.VariableInfo;
6112 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6113 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6117 if (TypeSpec.IsValueType (InstanceExpression.Type))
6121 base.FlowAnalysis (fc);
6124 public override int GetHashCode ()
6126 return spec.GetHashCode ();
6129 public bool IsFixed {
6132 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6134 IVariableReference variable = InstanceExpression as IVariableReference;
6135 if (variable != null)
6136 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6138 IFixedExpression fe = InstanceExpression as IFixedExpression;
6139 return fe != null && fe.IsFixed;
6143 public override bool Equals (object obj)
6145 FieldExpr fe = obj as FieldExpr;
6149 if (spec != fe.spec)
6152 if (InstanceExpression == null || fe.InstanceExpression == null)
6155 return InstanceExpression.Equals (fe.InstanceExpression);
6158 public void Emit (EmitContext ec, bool leave_copy)
6160 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6164 ec.Emit (OpCodes.Volatile);
6166 ec.Emit (OpCodes.Ldsfld, spec);
6169 EmitInstance (ec, false);
6171 // Optimization for build-in types
6172 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6173 ec.EmitLoadFromPtr (type);
6175 var ff = spec as FixedFieldSpec;
6177 ec.Emit (OpCodes.Ldflda, spec);
6178 ec.Emit (OpCodes.Ldflda, ff.Element);
6181 ec.Emit (OpCodes.Volatile);
6183 ec.Emit (OpCodes.Ldfld, spec);
6189 ec.Emit (OpCodes.Dup);
6191 temp = new LocalTemporary (this.Type);
6197 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6199 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6200 if (isCompound && !(source is DynamicExpressionStatement)) {
6201 if (has_await_source) {
6203 InstanceExpression = InstanceExpression.EmitToField (ec);
6210 if (has_await_source)
6211 source = source.EmitToField (ec);
6213 EmitInstance (ec, prepared);
6219 ec.Emit (OpCodes.Dup);
6221 temp = new LocalTemporary (this.Type);
6226 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6227 ec.Emit (OpCodes.Volatile);
6229 spec.MemberDefinition.SetIsAssigned ();
6232 ec.Emit (OpCodes.Stsfld, spec);
6234 ec.Emit (OpCodes.Stfld, spec);
6244 // Emits store to field with prepared values on stack
6246 public void EmitAssignFromStack (EmitContext ec)
6249 ec.Emit (OpCodes.Stsfld, spec);
6251 ec.Emit (OpCodes.Stfld, spec);
6255 public override void Emit (EmitContext ec)
6260 public override void EmitSideEffect (EmitContext ec)
6262 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6264 if (is_volatile) // || is_marshal_by_ref ())
6265 base.EmitSideEffect (ec);
6268 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6270 if ((mode & AddressOp.Store) != 0)
6271 spec.MemberDefinition.SetIsAssigned ();
6272 if ((mode & AddressOp.Load) != 0)
6273 spec.MemberDefinition.SetIsUsed ();
6276 // Handle initonly fields specially: make a copy and then
6277 // get the address of the copy.
6280 if (spec.IsReadOnly){
6282 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6294 var temp = ec.GetTemporaryLocal (type);
6295 ec.Emit (OpCodes.Stloc, temp);
6296 ec.Emit (OpCodes.Ldloca, temp);
6302 ec.Emit (OpCodes.Ldsflda, spec);
6305 EmitInstance (ec, false);
6306 ec.Emit (OpCodes.Ldflda, spec);
6310 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6312 return MakeExpression (ctx);
6315 public override SLE.Expression MakeExpression (BuilderContext ctx)
6318 return base.MakeExpression (ctx);
6320 return SLE.Expression.Field (
6321 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6322 spec.GetMetaInfo ());
6326 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6328 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6334 // Expression that evaluates to a Property.
6336 // This is not an LValue because we need to re-write the expression. We
6337 // can not take data from the stack and store it.
6339 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6341 Arguments arguments;
6343 public PropertyExpr (PropertySpec spec, Location l)
6346 best_candidate = spec;
6347 type = spec.MemberType;
6352 protected override Arguments Arguments {
6361 protected override TypeSpec DeclaringType {
6363 return best_candidate.DeclaringType;
6367 public override string Name {
6369 return best_candidate.Name;
6373 public override bool IsInstance {
6379 public override bool IsStatic {
6381 return best_candidate.IsStatic;
6385 public override string KindName {
6386 get { return "property"; }
6389 public PropertySpec PropertyInfo {
6391 return best_candidate;
6397 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6399 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6402 var args_count = arguments == null ? 0 : arguments.Count;
6403 if (args_count != body.Parameters.Count && args_count == 0)
6406 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6407 mg.InstanceExpression = InstanceExpression;
6412 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6414 return new PropertyExpr (spec, loc) {
6420 public override Expression CreateExpressionTree (ResolveContext ec)
6423 if (IsSingleDimensionalArrayLength ()) {
6424 args = new Arguments (1);
6425 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6426 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6429 args = new Arguments (2);
6430 if (InstanceExpression == null)
6431 args.Add (new Argument (new NullLiteral (loc)));
6433 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6434 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6435 return CreateExpressionFactoryCall (ec, "Property", args);
6438 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6440 DoResolveLValue (rc, null);
6441 return new TypeOfMethod (Setter, loc);
6444 public override string GetSignatureForError ()
6446 return best_candidate.GetSignatureForError ();
6449 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6452 return base.MakeExpression (ctx);
6454 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6458 public override SLE.Expression MakeExpression (BuilderContext ctx)
6461 return base.MakeExpression (ctx);
6463 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6467 void Error_PropertyNotValid (ResolveContext ec)
6469 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6470 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6471 GetSignatureForError ());
6474 bool IsSingleDimensionalArrayLength ()
6476 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6479 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6480 return ac != null && ac.Rank == 1;
6483 public override void Emit (EmitContext ec, bool leave_copy)
6486 // Special case: length of single dimension array property is turned into ldlen
6488 if (IsSingleDimensionalArrayLength ()) {
6489 EmitInstance (ec, false);
6490 ec.Emit (OpCodes.Ldlen);
6491 ec.Emit (OpCodes.Conv_I4);
6495 base.Emit (ec, leave_copy);
6498 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6501 LocalTemporary await_source_arg = null;
6503 if (isCompound && !(source is DynamicExpressionStatement)) {
6504 emitting_compound_assignment = true;
6507 if (has_await_arguments) {
6508 await_source_arg = new LocalTemporary (Type);
6509 await_source_arg.Store (ec);
6511 args = new Arguments (1);
6512 args.Add (new Argument (await_source_arg));
6515 temp = await_source_arg;
6518 has_await_arguments = false;
6523 ec.Emit (OpCodes.Dup);
6524 temp = new LocalTemporary (this.Type);
6529 args = arguments ?? new Arguments (1);
6533 temp = new LocalTemporary (this.Type);
6535 args.Add (new Argument (temp));
6537 args.Add (new Argument (source));
6541 emitting_compound_assignment = false;
6543 var call = new CallEmitter ();
6544 call.InstanceExpression = InstanceExpression;
6546 call.InstanceExpressionOnStack = true;
6548 call.Emit (ec, Setter, args, loc);
6555 if (await_source_arg != null) {
6556 await_source_arg.Release (ec);
6560 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6562 eclass = ExprClass.PropertyAccess;
6564 if (best_candidate.IsNotCSharpCompatible) {
6565 Error_PropertyNotValid (rc);
6568 ResolveInstanceExpression (rc, right_side);
6570 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6571 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6572 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6574 type = p.MemberType;
6578 DoBestMemberChecks (rc, best_candidate);
6580 // Handling of com-imported properties with any number of default property parameters
6581 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6582 var p = best_candidate.Get.Parameters;
6583 arguments = new Arguments (p.Count);
6584 for (int i = 0; i < p.Count; ++i) {
6585 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6587 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6588 var p = best_candidate.Set.Parameters;
6589 arguments = new Arguments (p.Count - 1);
6590 for (int i = 0; i < p.Count - 1; ++i) {
6591 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6598 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6600 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6604 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6606 // getter and setter can be different for base calls
6607 MethodSpec getter, setter;
6608 protected T best_candidate;
6610 protected LocalTemporary temp;
6611 protected bool emitting_compound_assignment;
6612 protected bool has_await_arguments;
6614 protected PropertyOrIndexerExpr (Location l)
6621 protected abstract Arguments Arguments { get; set; }
6623 public MethodSpec Getter {
6632 public MethodSpec Setter {
6643 protected override Expression DoResolve (ResolveContext ec)
6645 if (eclass == ExprClass.Unresolved) {
6646 var expr = OverloadResolve (ec, null);
6651 return expr.Resolve (ec);
6654 if (!ResolveGetter (ec))
6660 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6662 if (right_side == EmptyExpression.OutAccess) {
6663 // TODO: best_candidate can be null at this point
6664 INamedBlockVariable variable = null;
6665 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6666 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6667 best_candidate.Name);
6669 right_side.DoResolveLValue (ec, this);
6674 if (eclass == ExprClass.Unresolved) {
6675 var expr = OverloadResolve (ec, right_side);
6680 return expr.ResolveLValue (ec, right_side);
6682 ResolveInstanceExpression (ec, right_side);
6685 if (!ResolveSetter (ec))
6692 // Implements the IAssignMethod interface for assignments
6694 public virtual void Emit (EmitContext ec, bool leave_copy)
6696 var call = new CallEmitter ();
6697 call.InstanceExpression = InstanceExpression;
6698 if (has_await_arguments)
6699 call.HasAwaitArguments = true;
6701 call.DuplicateArguments = emitting_compound_assignment;
6703 call.Emit (ec, Getter, Arguments, loc);
6705 if (call.HasAwaitArguments) {
6706 InstanceExpression = call.InstanceExpression;
6707 Arguments = call.EmittedArguments;
6708 has_await_arguments = true;
6712 ec.Emit (OpCodes.Dup);
6713 temp = new LocalTemporary (Type);
6718 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6720 public override void Emit (EmitContext ec)
6725 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6727 has_await_arguments = true;
6732 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6734 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6736 bool ResolveGetter (ResolveContext rc)
6738 if (!best_candidate.HasGet) {
6739 if (InstanceExpression != EmptyExpression.Null) {
6740 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6741 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6742 best_candidate.GetSignatureForError ());
6745 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6746 if (best_candidate.HasDifferentAccessibility) {
6747 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6748 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6749 TypeManager.CSharpSignature (best_candidate));
6751 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6752 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6756 if (best_candidate.HasDifferentAccessibility) {
6757 CheckProtectedMemberAccess (rc, best_candidate.Get);
6760 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6764 bool ResolveSetter (ResolveContext rc)
6766 if (!best_candidate.HasSet) {
6767 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6768 GetSignatureForError ());
6772 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6773 if (best_candidate.HasDifferentAccessibility) {
6774 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6775 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6776 GetSignatureForError ());
6778 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6779 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6783 if (best_candidate.HasDifferentAccessibility)
6784 CheckProtectedMemberAccess (rc, best_candidate.Set);
6786 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6792 /// Fully resolved expression that evaluates to an Event
6794 public class EventExpr : MemberExpr, IAssignMethod
6796 readonly EventSpec spec;
6799 public EventExpr (EventSpec spec, Location loc)
6807 protected override TypeSpec DeclaringType {
6809 return spec.DeclaringType;
6813 public override string Name {
6819 public override bool IsInstance {
6821 return !spec.IsStatic;
6825 public override bool IsStatic {
6827 return spec.IsStatic;
6831 public override string KindName {
6832 get { return "event"; }
6835 public MethodSpec Operator {
6843 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6846 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6848 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6849 if (spec.BackingField != null &&
6850 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6852 spec.MemberDefinition.SetIsUsed ();
6854 if (!ec.IsObsolete) {
6855 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6857 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6860 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6861 Error_AssignmentEventOnly (ec);
6863 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6865 InstanceExpression = null;
6867 return ml.ResolveMemberAccess (ec, left, original);
6871 return base.ResolveMemberAccess (ec, left, original);
6874 public override Expression CreateExpressionTree (ResolveContext ec)
6876 throw new NotSupportedException ("ET");
6879 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6881 if (right_side == EmptyExpression.EventAddition) {
6882 op = spec.AccessorAdd;
6883 } else if (right_side == EmptyExpression.EventSubtraction) {
6884 op = spec.AccessorRemove;
6888 Error_AssignmentEventOnly (ec);
6892 op = CandidateToBaseOverride (ec, op);
6896 protected override Expression DoResolve (ResolveContext ec)
6898 eclass = ExprClass.EventAccess;
6899 type = spec.MemberType;
6901 ResolveInstanceExpression (ec, null);
6903 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6904 Error_AssignmentEventOnly (ec);
6907 DoBestMemberChecks (ec, spec);
6911 public override void Emit (EmitContext ec)
6913 throw new NotSupportedException ();
6914 //Error_CannotAssign ();
6917 #region IAssignMethod Members
6919 public void Emit (EmitContext ec, bool leave_copy)
6921 throw new NotImplementedException ();
6924 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6926 if (leave_copy || !isCompound)
6927 throw new NotImplementedException ("EventExpr::EmitAssign");
6929 Arguments args = new Arguments (1);
6930 args.Add (new Argument (source));
6932 var call = new CallEmitter ();
6933 call.InstanceExpression = InstanceExpression;
6934 call.Emit (ec, op, args, loc);
6939 void Error_AssignmentEventOnly (ResolveContext ec)
6941 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6942 ec.Report.Error (79, loc,
6943 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6944 GetSignatureForError ());
6946 ec.Report.Error (70, loc,
6947 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6948 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6952 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6954 name = name.Substring (0, name.LastIndexOf ('.'));
6955 base.Error_CannotCallAbstractBase (rc, name);
6958 public override string GetSignatureForError ()
6960 return TypeManager.CSharpSignature (spec);
6963 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6965 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6969 public class TemporaryVariableReference : VariableReference
6971 public class Declarator : Statement
6973 TemporaryVariableReference variable;
6975 public Declarator (TemporaryVariableReference variable)
6977 this.variable = variable;
6981 protected override void DoEmit (EmitContext ec)
6983 variable.li.CreateBuilder (ec);
6986 public override void Emit (EmitContext ec)
6988 // Don't create sequence point
6992 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6997 protected override void CloneTo (CloneContext clonectx, Statement target)
7005 public TemporaryVariableReference (LocalVariable li, Location loc)
7008 this.type = li.Type;
7012 public override bool IsLockedByStatement {
7020 public LocalVariable LocalInfo {
7026 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7028 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7029 return new TemporaryVariableReference (li, loc);
7032 protected override Expression DoResolve (ResolveContext ec)
7034 eclass = ExprClass.Variable;
7037 // Don't capture temporary variables except when using
7038 // state machine redirection and block yields
7040 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7041 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7042 ec.IsVariableCapturingRequired) {
7043 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7044 storey.CaptureLocalVariable (ec, li);
7050 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7052 return Resolve (ec);
7055 public override void Emit (EmitContext ec)
7057 li.CreateBuilder (ec);
7062 public void EmitAssign (EmitContext ec, Expression source)
7064 li.CreateBuilder (ec);
7066 EmitAssign (ec, source, false, false);
7069 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7071 return li.HoistedVariant;
7074 public override bool IsFixed {
7075 get { return true; }
7078 public override bool IsRef {
7079 get { return false; }
7082 public override string Name {
7083 get { throw new NotImplementedException (); }
7086 public override void SetHasAddressTaken ()
7088 throw new NotImplementedException ();
7091 protected override ILocalVariable Variable {
7095 public override VariableInfo VariableInfo {
7096 get { return null; }
7101 /// Handles `var' contextual keyword; var becomes a keyword only
7102 /// if no type called var exists in a variable scope
7104 class VarExpr : SimpleName
7106 public VarExpr (Location loc)
7111 public bool InferType (ResolveContext ec, Expression right_side)
7114 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7116 type = right_side.Type;
7117 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7118 ec.Report.Error (815, loc,
7119 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7120 type.GetSignatureForError ());
7124 eclass = ExprClass.Variable;
7128 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7130 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7131 base.Error_TypeOrNamespaceNotFound (ec);
7133 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");