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);
2785 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2786 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2788 rc.Report.SymbolRelatedToPreviousError (e.Type);
2789 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2793 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2795 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2796 return ErrorExpression.Instance;
2800 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2802 if (e.Type.Arity != Arity) {
2803 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2807 if (e is TypeExpr) {
2808 // TypeExpression does not have correct location
2809 if (e is TypeExpression)
2810 e = new TypeExpression (e.Type, loc);
2816 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2819 return ErrorExpression.Instance;
2822 if (rc.Module.Evaluator != null) {
2823 var fi = rc.Module.Evaluator.LookupField (Name);
2825 return new FieldExpr (fi.Item1, loc);
2833 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2835 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2840 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2841 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2845 if (right_side != null) {
2846 e = e.ResolveLValue (ec, right_side);
2854 public override object Accept (StructuralVisitor visitor)
2856 return visitor.Visit (this);
2861 /// Represents a namespace or a type. The name of the class was inspired by
2862 /// section 10.8.1 (Fully Qualified Names).
2864 public abstract class FullNamedExpression : Expression
2866 protected override void CloneTo (CloneContext clonectx, Expression target)
2868 // Do nothing, most unresolved type expressions cannot be
2869 // resolved to different type
2872 public override bool ContainsEmitWithAwait ()
2877 public override Expression CreateExpressionTree (ResolveContext ec)
2879 throw new NotSupportedException ("ET");
2882 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2885 // This is used to resolve the expression as a type, a null
2886 // value will be returned if the expression is not a type
2889 public override TypeSpec ResolveAsType (IMemberContext mc)
2891 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2896 TypeExpr te = fne as TypeExpr;
2898 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2906 var dep = type.GetMissingDependencies ();
2908 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2911 if (type.Kind == MemberKind.Void) {
2912 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2916 // Obsolete checks cannot be done when resolving base context as they
2917 // require type dependencies to be set but we are in process of resolving them
2919 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2920 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2921 if (obsolete_attr != null && !mc.IsObsolete) {
2922 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2930 public override void Emit (EmitContext ec)
2932 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2933 GetSignatureForError ());
2938 /// Expression that evaluates to a type
2940 public abstract class TypeExpr : FullNamedExpression
2942 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2948 protected sealed override Expression DoResolve (ResolveContext ec)
2954 public override bool Equals (object obj)
2956 TypeExpr tobj = obj as TypeExpr;
2960 return Type == tobj.Type;
2963 public override int GetHashCode ()
2965 return Type.GetHashCode ();
2970 /// Fully resolved Expression that already evaluated to a type
2972 public class TypeExpression : TypeExpr
2974 public TypeExpression (TypeSpec t, Location l)
2977 eclass = ExprClass.Type;
2981 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2987 public class NamespaceExpression : FullNamedExpression
2989 readonly Namespace ns;
2991 public NamespaceExpression (Namespace ns, Location loc)
2994 this.Type = InternalType.Namespace;
2995 this.eclass = ExprClass.Namespace;
2999 public Namespace Namespace {
3005 protected override Expression DoResolve (ResolveContext rc)
3007 throw new NotImplementedException ();
3010 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
3015 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3017 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3018 if (retval != null) {
3019 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3020 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3024 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3025 if (retval != null) {
3026 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3031 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3032 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3036 string assembly = null;
3037 string possible_name = Namespace.GetSignatureForError () + "." + name;
3039 // Only assembly unique name should be added
3040 switch (possible_name) {
3041 case "System.Drawing":
3042 case "System.Web.Services":
3045 case "System.Configuration":
3046 case "System.Data.Services":
3047 case "System.DirectoryServices":
3049 case "System.Net.Http":
3050 case "System.Numerics":
3051 case "System.Runtime.Caching":
3052 case "System.ServiceModel":
3053 case "System.Transactions":
3054 case "System.Web.Routing":
3055 case "System.Xml.Linq":
3057 assembly = possible_name;
3061 case "System.Linq.Expressions":
3062 assembly = "System.Core";
3065 case "System.Windows.Forms":
3066 case "System.Windows.Forms.Layout":
3067 assembly = "System.Windows.Forms";
3071 assembly = assembly == null ? "an" : "`" + assembly + "'";
3073 if (Namespace is GlobalRootNamespace) {
3074 ctx.Module.Compiler.Report.Error (400, loc,
3075 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3078 ctx.Module.Compiler.Report.Error (234, loc,
3079 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3080 name, GetSignatureForError (), assembly);
3084 public override string GetSignatureForError ()
3086 return ns.GetSignatureForError ();
3089 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3091 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3096 /// This class denotes an expression which evaluates to a member
3097 /// of a struct or a class.
3099 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3102 // An instance expression associated with this member, if it's a
3103 // non-static member
3105 public Expression InstanceExpression;
3108 /// The name of this member.
3110 public abstract string Name {
3115 // When base.member is used
3117 public bool IsBase {
3118 get { return InstanceExpression is BaseThis; }
3122 /// Whether this is an instance member.
3124 public abstract bool IsInstance {
3129 /// Whether this is a static member.
3131 public abstract bool IsStatic {
3135 public abstract string KindName {
3139 protected abstract TypeSpec DeclaringType {
3143 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3145 return InstanceExpression.Type;
3150 // Converts best base candidate for virtual method starting from QueriedBaseType
3152 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3155 // Only when base.member is used and method is virtual
3161 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3162 // means for base.member access we have to find the closest match after we found best candidate
3164 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3166 // The method could already be what we are looking for
3168 TypeSpec[] targs = null;
3169 if (method.DeclaringType != InstanceExpression.Type) {
3171 // Candidate can have inflated MVAR parameters and we need to find
3172 // base match for original definition not inflated parameter types
3174 var parameters = method.Parameters;
3175 if (method.Arity > 0) {
3176 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3177 var inflated = method.DeclaringType as InflatedTypeSpec;
3178 if (inflated != null) {
3179 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3183 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3184 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3185 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3186 if (base_override.IsGeneric)
3187 targs = method.TypeArguments;
3189 method = base_override;
3194 // When base access is used inside anonymous method/iterator/etc we need to
3195 // get back to the context of original type. We do it by emiting proxy
3196 // method in original class and rewriting base call to this compiler
3197 // generated method call which does the actual base invocation. This may
3198 // introduce redundant storey but with `this' only but it's tricky to avoid
3199 // at this stage as we don't know what expressions follow base
3201 if (rc.CurrentAnonymousMethod != null) {
3202 if (targs == null && method.IsGeneric) {
3203 targs = method.TypeArguments;
3204 method = method.GetGenericMethodDefinition ();
3207 if (method.Parameters.HasArglist)
3208 throw new NotImplementedException ("__arglist base call proxy");
3210 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3212 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3213 // get/set member expressions second call would fail to proxy because left expression
3214 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3215 // FIXME: The async check is another hack but will probably fail with mutators
3216 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3217 InstanceExpression = new This (loc).Resolve (rc);
3221 method = method.MakeGenericMethod (rc, targs);
3225 // Only base will allow this invocation to happen.
3227 if (method.IsAbstract) {
3228 rc.Report.SymbolRelatedToPreviousError (method);
3229 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3235 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3237 if (InstanceExpression == null)
3240 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3241 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3242 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3247 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3249 if (InstanceExpression == null)
3252 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3255 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3257 var ct = rc.CurrentType;
3258 if (ct == qualifier)
3261 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3264 qualifier = qualifier.GetDefinition ();
3265 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3272 public override bool ContainsEmitWithAwait ()
3274 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3277 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3280 type = type.GetDefinition ();
3282 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3285 type = type.DeclaringType;
3286 } while (type != null);
3291 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3293 if (InstanceExpression != null) {
3294 InstanceExpression = InstanceExpression.Resolve (rc);
3295 CheckProtectedMemberAccess (rc, member);
3298 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3299 UnsafeError (rc, loc);
3302 var dep = member.GetMissingDependencies ();
3304 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3307 if (!rc.IsObsolete) {
3308 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3310 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3313 if (!(member is FieldSpec))
3314 member.MemberDefinition.SetIsUsed ();
3317 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3319 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3322 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3324 rc.Report.SymbolRelatedToPreviousError (member);
3325 rc.Report.Error (1540, loc,
3326 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3327 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3330 public override void FlowAnalysis (FlowAnalysisContext fc)
3332 if (InstanceExpression != null)
3333 InstanceExpression.FlowAnalysis (fc);
3336 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3338 if (!ResolveInstanceExpressionCore (rc, rhs))
3342 // Check intermediate value modification which won't have any effect
3344 if (rhs != null && InstanceExpression.Type.IsStruct) {
3345 var fexpr = InstanceExpression as FieldExpr;
3346 if (fexpr != null) {
3347 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3350 if (fexpr.IsStatic) {
3351 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3352 fexpr.GetSignatureForError ());
3354 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3355 fexpr.GetSignatureForError ());
3361 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3362 if (rc.CurrentInitializerVariable != null) {
3363 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3364 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3366 rc.Report.Error (1612, loc,
3367 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3368 InstanceExpression.GetSignatureForError ());
3374 var lvr = InstanceExpression as LocalVariableReference;
3377 if (!lvr.local_info.IsReadonly)
3380 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3381 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3388 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3391 if (InstanceExpression != null) {
3392 if (InstanceExpression is TypeExpr) {
3393 var t = InstanceExpression.Type;
3395 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3396 if (oa != null && !rc.IsObsolete) {
3397 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3400 t = t.DeclaringType;
3401 } while (t != null);
3403 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3404 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3405 rc.Report.Error (176, loc,
3406 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3407 GetSignatureForError ());
3411 InstanceExpression = null;
3417 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3418 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3419 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3420 rc.Report.Error (236, loc,
3421 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3422 GetSignatureForError ());
3424 rc.Report.Error (120, loc,
3425 "An object reference is required to access non-static member `{0}'",
3426 GetSignatureForError ());
3428 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3432 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3433 rc.Report.Error (38, loc,
3434 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3435 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3438 InstanceExpression = new This (loc).Resolve (rc);
3442 var me = InstanceExpression as MemberExpr;
3444 me.ResolveInstanceExpressionCore (rc, rhs);
3446 var fe = me as FieldExpr;
3447 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3448 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3449 rc.Report.Warning (1690, 1, loc,
3450 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3451 me.GetSignatureForError ());
3458 // Additional checks for l-value member access
3461 if (InstanceExpression is UnboxCast) {
3462 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3469 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3471 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3472 ec.Report.Warning (1720, 1, left.Location,
3473 "Expression will always cause a `{0}'", "System.NullReferenceException");
3476 InstanceExpression = left;
3480 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3482 TypeSpec instance_type = InstanceExpression.Type;
3483 if (TypeSpec.IsValueType (instance_type)) {
3484 if (InstanceExpression is IMemoryLocation) {
3485 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3487 // Cannot release the temporary variable when its address
3488 // is required to be on stack for any parent
3489 LocalTemporary t = new LocalTemporary (instance_type);
3490 InstanceExpression.Emit (ec);
3492 t.AddressOf (ec, AddressOp.Store);
3495 InstanceExpression.Emit (ec);
3497 // Only to make verifier happy
3498 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3499 ec.Emit (OpCodes.Box, instance_type);
3502 if (prepare_for_load)
3503 ec.Emit (OpCodes.Dup);
3506 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3509 public class ExtensionMethodCandidates
3511 readonly NamespaceContainer container;
3512 readonly IList<MethodSpec> methods;
3514 readonly IMemberContext context;
3516 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3518 this.context = context;
3519 this.methods = methods;
3520 this.container = nsContainer;
3521 this.index = lookupIndex;
3524 public NamespaceContainer Container {
3530 public IMemberContext Context {
3536 public int LookupIndex {
3542 public IList<MethodSpec> Methods {
3550 // Represents a group of extension method candidates for whole namespace
3552 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3554 ExtensionMethodCandidates candidates;
3555 public Expression ExtensionExpression;
3557 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3558 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3560 this.candidates = candidates;
3561 this.ExtensionExpression = extensionExpr;
3564 public override bool IsStatic {
3565 get { return true; }
3569 // For extension methodgroup we are not looking for base members but parent
3570 // namespace extension methods
3572 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3574 // TODO: candidates are null only when doing error reporting, that's
3575 // incorrect. We have to discover same extension methods in error mode
3576 if (candidates == null)
3579 int arity = type_arguments == null ? 0 : type_arguments.Count;
3581 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3582 if (candidates == null)
3585 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3588 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3590 // We are already here
3594 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3596 if (arguments == null)
3597 arguments = new Arguments (1);
3599 ExtensionExpression = ExtensionExpression.Resolve (ec);
3600 if (ExtensionExpression == null)
3603 var cand = candidates;
3604 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3605 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3607 // Restore candidates in case we are running in probing mode
3610 // Store resolved argument and restore original arguments
3612 // Clean-up modified arguments for error reporting
3613 arguments.RemoveAt (0);
3617 var me = ExtensionExpression as MemberExpr;
3619 me.ResolveInstanceExpression (ec, null);
3620 var fe = me as FieldExpr;
3622 fe.Spec.MemberDefinition.SetIsUsed ();
3625 InstanceExpression = null;
3629 #region IErrorHandler Members
3631 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3636 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3638 rc.Report.SymbolRelatedToPreviousError (best);
3639 rc.Report.Error (1928, loc,
3640 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3641 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3644 rc.Report.Error (1929, loc,
3645 "Extension method instance type `{0}' cannot be converted to `{1}'",
3646 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3652 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3657 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3666 /// MethodGroupExpr represents a group of method candidates which
3667 /// can be resolved to the best method overload
3669 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3671 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3673 protected IList<MemberSpec> Methods;
3674 MethodSpec best_candidate;
3675 TypeSpec best_candidate_return;
3676 protected TypeArguments type_arguments;
3678 SimpleName simple_name;
3679 protected TypeSpec queried_type;
3681 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3685 this.type = InternalType.MethodGroup;
3687 eclass = ExprClass.MethodGroup;
3688 queried_type = type;
3691 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3692 : this (new MemberSpec[] { m }, type, loc)
3698 public MethodSpec BestCandidate {
3700 return best_candidate;
3704 public TypeSpec BestCandidateReturnType {
3706 return best_candidate_return;
3710 public IList<MemberSpec> Candidates {
3716 protected override TypeSpec DeclaringType {
3718 return queried_type;
3722 public bool IsConditionallyExcluded {
3724 return Methods == Excluded;
3728 public override bool IsInstance {
3730 if (best_candidate != null)
3731 return !best_candidate.IsStatic;
3737 public override bool IsSideEffectFree {
3739 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3743 public override bool IsStatic {
3745 if (best_candidate != null)
3746 return best_candidate.IsStatic;
3752 public override string KindName {
3753 get { return "method"; }
3756 public override string Name {
3758 if (best_candidate != null)
3759 return best_candidate.Name;
3762 return Methods.First ().Name;
3769 // When best candidate is already know this factory can be used
3770 // to avoid expensive overload resolution to be called
3772 // NOTE: InstanceExpression has to be set manually
3774 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3776 return new MethodGroupExpr (best, queriedType, loc) {
3777 best_candidate = best,
3778 best_candidate_return = best.ReturnType
3782 public override string GetSignatureForError ()
3784 if (best_candidate != null)
3785 return best_candidate.GetSignatureForError ();
3787 return Methods.First ().GetSignatureForError ();
3790 public override Expression CreateExpressionTree (ResolveContext ec)
3792 if (best_candidate == null) {
3793 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3797 if (IsConditionallyExcluded)
3798 ec.Report.Error (765, loc,
3799 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3801 return new TypeOfMethod (best_candidate, loc);
3804 protected override Expression DoResolve (ResolveContext ec)
3806 this.eclass = ExprClass.MethodGroup;
3808 if (InstanceExpression != null) {
3809 InstanceExpression = InstanceExpression.Resolve (ec);
3810 if (InstanceExpression == null)
3817 public override void Emit (EmitContext ec)
3819 throw new NotSupportedException ();
3822 public void EmitCall (EmitContext ec, Arguments arguments)
3824 var call = new CallEmitter ();
3825 call.InstanceExpression = InstanceExpression;
3826 call.Emit (ec, best_candidate, arguments, loc);
3829 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3831 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3832 Name, target.GetSignatureForError ());
3835 public static bool IsExtensionMethodArgument (Expression expr)
3838 // LAMESPEC: No details about which expressions are not allowed
3840 return !(expr is TypeExpr) && !(expr is BaseThis);
3844 /// Find the Applicable Function Members (7.4.2.1)
3846 /// me: Method Group expression with the members to select.
3847 /// it might contain constructors or methods (or anything
3848 /// that maps to a method).
3850 /// Arguments: ArrayList containing resolved Argument objects.
3852 /// loc: The location if we want an error to be reported, or a Null
3853 /// location for "probing" purposes.
3855 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3856 /// that is the best match of me on Arguments.
3859 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3861 // TODO: causes issues with probing mode, remove explicit Kind check
3862 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3865 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3866 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3867 r.BaseMembersProvider = this;
3868 r.InstanceQualifier = this;
3871 if (cerrors != null)
3872 r.CustomErrors = cerrors;
3874 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3875 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3876 if (best_candidate == null)
3877 return r.BestCandidateIsDynamic ? this : null;
3879 // Overload resolver had to create a new method group, all checks bellow have already been executed
3880 if (r.BestCandidateNewMethodGroup != null)
3881 return r.BestCandidateNewMethodGroup;
3883 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3884 if (InstanceExpression != null) {
3885 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3886 InstanceExpression = null;
3888 if (best_candidate.IsStatic && simple_name != null) {
3889 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3892 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3896 ResolveInstanceExpression (ec, null);
3899 var base_override = CandidateToBaseOverride (ec, best_candidate);
3900 if (base_override == best_candidate) {
3901 best_candidate_return = r.BestCandidateReturnType;
3903 best_candidate = base_override;
3904 best_candidate_return = best_candidate.ReturnType;
3907 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3908 ConstraintChecker cc = new ConstraintChecker (ec);
3909 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3913 // Additional check for possible imported base override method which
3914 // could not be done during IsOverrideMethodBaseTypeAccessible
3916 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3917 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3918 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3919 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3922 // Speed up the check by not doing it on disallowed targets
3923 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3929 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3931 var fe = left as FieldExpr;
3934 // Using method-group on struct fields makes the struct assigned. I am not sure
3935 // why but that's what .net does
3937 fe.Spec.MemberDefinition.SetIsAssigned ();
3940 simple_name = original;
3941 return base.ResolveMemberAccess (ec, left, original);
3944 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3946 type_arguments = ta;
3949 #region IBaseMembersProvider Members
3951 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3953 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3956 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3958 if (queried_type == member.DeclaringType)
3961 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3962 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3966 // Extension methods lookup after ordinary methods candidates failed to apply
3968 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3970 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3973 if (!IsExtensionMethodArgument (InstanceExpression))
3976 int arity = type_arguments == null ? 0 : type_arguments.Count;
3977 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3978 if (methods == null)
3981 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3982 emg.SetTypeArguments (rc, type_arguments);
3989 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3991 public ConstructorInstanceQualifier (TypeSpec type)
3994 InstanceType = type;
3997 public TypeSpec InstanceType { get; private set; }
3999 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4001 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4005 public struct OverloadResolver
4008 public enum Restrictions
4012 ProbingOnly = 1 << 1,
4013 CovariantDelegate = 1 << 2,
4014 NoBaseMembers = 1 << 3,
4015 BaseMembersIncluded = 1 << 4
4018 public interface IBaseMembersProvider
4020 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4021 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4022 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4025 public interface IErrorHandler
4027 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4028 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4029 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4030 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4033 public interface IInstanceQualifier
4035 TypeSpec InstanceType { get; }
4036 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4039 sealed class NoBaseMembers : IBaseMembersProvider
4041 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4043 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4048 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4053 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4059 struct AmbiguousCandidate
4061 public readonly MemberSpec Member;
4062 public readonly bool Expanded;
4063 public readonly AParametersCollection Parameters;
4065 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4068 Parameters = parameters;
4069 Expanded = expanded;
4074 IList<MemberSpec> members;
4075 TypeArguments type_arguments;
4076 IBaseMembersProvider base_provider;
4077 IErrorHandler custom_errors;
4078 IInstanceQualifier instance_qualifier;
4079 Restrictions restrictions;
4080 MethodGroupExpr best_candidate_extension_group;
4081 TypeSpec best_candidate_return_type;
4083 SessionReportPrinter lambda_conv_msgs;
4085 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4086 : this (members, null, restrictions, loc)
4090 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4093 if (members == null || members.Count == 0)
4094 throw new ArgumentException ("empty members set");
4096 this.members = members;
4098 type_arguments = targs;
4099 this.restrictions = restrictions;
4100 if (IsDelegateInvoke)
4101 this.restrictions |= Restrictions.NoBaseMembers;
4103 base_provider = NoBaseMembers.Instance;
4108 public IBaseMembersProvider BaseMembersProvider {
4110 return base_provider;
4113 base_provider = value;
4117 public bool BestCandidateIsDynamic { get; set; }
4120 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4122 public MethodGroupExpr BestCandidateNewMethodGroup {
4124 return best_candidate_extension_group;
4129 // Return type can be different between best candidate and closest override
4131 public TypeSpec BestCandidateReturnType {
4133 return best_candidate_return_type;
4137 public IErrorHandler CustomErrors {
4139 return custom_errors;
4142 custom_errors = value;
4146 TypeSpec DelegateType {
4148 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4149 throw new InternalErrorException ("Not running in delegate mode", loc);
4151 return members [0].DeclaringType;
4155 public IInstanceQualifier InstanceQualifier {
4157 return instance_qualifier;
4160 instance_qualifier = value;
4164 bool IsProbingOnly {
4166 return (restrictions & Restrictions.ProbingOnly) != 0;
4170 bool IsDelegateInvoke {
4172 return (restrictions & Restrictions.DelegateInvoke) != 0;
4179 // 7.4.3.3 Better conversion from expression
4180 // Returns : 1 if a->p is better,
4181 // 2 if a->q is better,
4182 // 0 if neither is better
4184 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4186 TypeSpec argument_type = a.Type;
4189 // If argument is an anonymous function
4191 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4193 // p and q are delegate types or expression tree types
4195 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4196 if (q.MemberDefinition != p.MemberDefinition) {
4201 // Uwrap delegate from Expression<T>
4203 q = TypeManager.GetTypeArguments (q)[0];
4204 p = TypeManager.GetTypeArguments (p)[0];
4207 var p_m = Delegate.GetInvokeMethod (p);
4208 var q_m = Delegate.GetInvokeMethod (q);
4211 // With identical parameter lists
4213 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4222 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4224 if (p.Kind == MemberKind.Void) {
4225 return q.Kind != MemberKind.Void ? 2 : 0;
4229 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4231 if (q.Kind == MemberKind.Void) {
4232 return p.Kind != MemberKind.Void ? 1: 0;
4235 var am = (AnonymousMethodExpression) a.Expr;
4238 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4239 // better conversion is performed between underlying types Y1 and Y2
4241 if (p.IsGenericTask || q.IsGenericTask) {
4242 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4243 q = q.TypeArguments[0];
4244 p = p.TypeArguments[0];
4246 } else if (q != p) {
4248 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4250 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4251 var am_rt = am.InferReturnType (ec, null, orig_q);
4252 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4254 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4255 var am_rt = am.InferReturnType (ec, null, orig_p);
4256 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4262 // The parameters are identicial and return type is not void, use better type conversion
4263 // on return type to determine better one
4266 if (argument_type == p)
4269 if (argument_type == q)
4273 return BetterTypeConversion (ec, p, q);
4277 // 7.4.3.4 Better conversion from type
4279 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4281 if (p == null || q == null)
4282 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4284 switch (p.BuiltinType) {
4285 case BuiltinTypeSpec.Type.Int:
4286 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4289 case BuiltinTypeSpec.Type.Long:
4290 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4293 case BuiltinTypeSpec.Type.SByte:
4294 switch (q.BuiltinType) {
4295 case BuiltinTypeSpec.Type.Byte:
4296 case BuiltinTypeSpec.Type.UShort:
4297 case BuiltinTypeSpec.Type.UInt:
4298 case BuiltinTypeSpec.Type.ULong:
4302 case BuiltinTypeSpec.Type.Short:
4303 switch (q.BuiltinType) {
4304 case BuiltinTypeSpec.Type.UShort:
4305 case BuiltinTypeSpec.Type.UInt:
4306 case BuiltinTypeSpec.Type.ULong:
4310 case BuiltinTypeSpec.Type.Dynamic:
4311 // Dynamic is never better
4315 switch (q.BuiltinType) {
4316 case BuiltinTypeSpec.Type.Int:
4317 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4320 case BuiltinTypeSpec.Type.Long:
4321 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4324 case BuiltinTypeSpec.Type.SByte:
4325 switch (p.BuiltinType) {
4326 case BuiltinTypeSpec.Type.Byte:
4327 case BuiltinTypeSpec.Type.UShort:
4328 case BuiltinTypeSpec.Type.UInt:
4329 case BuiltinTypeSpec.Type.ULong:
4333 case BuiltinTypeSpec.Type.Short:
4334 switch (p.BuiltinType) {
4335 case BuiltinTypeSpec.Type.UShort:
4336 case BuiltinTypeSpec.Type.UInt:
4337 case BuiltinTypeSpec.Type.ULong:
4341 case BuiltinTypeSpec.Type.Dynamic:
4342 // Dynamic is never better
4346 // FIXME: handle lifted operators
4348 // TODO: this is expensive
4349 Expression p_tmp = new EmptyExpression (p);
4350 Expression q_tmp = new EmptyExpression (q);
4352 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4353 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4355 if (p_to_q && !q_to_p)
4358 if (q_to_p && !p_to_q)
4365 /// Determines "Better function" between candidate
4366 /// and the current best match
4369 /// Returns a boolean indicating :
4370 /// false if candidate ain't better
4371 /// true if candidate is better than the current best match
4373 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4374 MemberSpec best, AParametersCollection bparam, bool best_params)
4376 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4377 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4379 bool better_at_least_one = false;
4380 bool are_equivalent = true;
4381 int args_count = args == null ? 0 : args.Count;
4385 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4388 // Default arguments are ignored for better decision
4389 if (a.IsDefaultArgument)
4393 // When comparing named argument the parameter type index has to be looked up
4394 // in original parameter set (override version for virtual members)
4396 NamedArgument na = a as NamedArgument;
4398 int idx = cparam.GetParameterIndexByName (na.Name);
4399 ct = candidate_pd.Types[idx];
4400 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4401 ct = TypeManager.GetElementType (ct);
4403 idx = bparam.GetParameterIndexByName (na.Name);
4404 bt = best_pd.Types[idx];
4405 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4406 bt = TypeManager.GetElementType (bt);
4408 ct = candidate_pd.Types[c_idx];
4409 bt = best_pd.Types[b_idx];
4411 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4412 ct = TypeManager.GetElementType (ct);
4416 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4417 bt = TypeManager.GetElementType (bt);
4422 if (TypeSpecComparer.IsEqual (ct, bt))
4425 are_equivalent = false;
4426 int result = BetterExpressionConversion (ec, a, ct, bt);
4428 // for each argument, the conversion to 'ct' should be no worse than
4429 // the conversion to 'bt'.
4433 // for at least one argument, the conversion to 'ct' should be better than
4434 // the conversion to 'bt'.
4436 better_at_least_one = true;
4439 if (better_at_least_one)
4443 // Tie-breaking rules are applied only for equivalent parameter types
4445 if (!are_equivalent)
4449 // If candidate is applicable in its normal form and best has a params array and is applicable
4450 // only in its expanded form, then candidate is better
4452 if (candidate_params != best_params)
4453 return !candidate_params;
4456 // We have not reached end of parameters list due to params or used default parameters
4458 if (j < candidate_pd.Count && j < best_pd.Count) {
4459 var cand_param = candidate_pd.FixedParameters [j];
4460 var best_param = best_pd.FixedParameters [j];
4462 if (candidate_pd.Count == best_pd.Count) {
4466 // void Foo (params int[]) is better than void Foo (int i = 0) for Foo ()
4467 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null)
4469 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4470 return !candidate_params;
4473 // Neither is better when not all arguments are provided
4475 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4476 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4477 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4479 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4484 if (candidate_pd.Count != best_pd.Count)
4485 return candidate_pd.Count < best_pd.Count;
4488 // One is a non-generic method and second is a generic method, then non-generic is better
4490 if (best.IsGeneric != candidate.IsGeneric)
4491 return best.IsGeneric;
4494 // Both methods have the same number of parameters, and the parameters have equal types
4495 // Pick the "more specific" signature using rules over original (non-inflated) types
4497 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4498 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4500 bool specific_at_least_once = false;
4501 for (j = 0; j < args_count; ++j) {
4502 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4504 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4505 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4507 ct = candidate_def_pd.Types[j];
4508 bt = best_def_pd.Types[j];
4513 TypeSpec specific = MoreSpecific (ct, bt);
4517 specific_at_least_once = true;
4520 if (specific_at_least_once)
4526 static bool CheckInflatedArguments (MethodSpec ms)
4528 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4531 // Setup constraint checker for probing only
4532 ConstraintChecker cc = new ConstraintChecker (null);
4534 var mp = ms.Parameters.Types;
4535 for (int i = 0; i < mp.Length; ++i) {
4536 var type = mp[i] as InflatedTypeSpec;
4540 var targs = type.TypeArguments;
4541 if (targs.Length == 0)
4544 // TODO: Checking inflated MVAR arguments should be enough
4545 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4552 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4554 rc.Report.Error (1729, loc,
4555 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4556 type.GetSignatureForError (), argCount.ToString ());
4560 // Determines if the candidate method is applicable to the given set of arguments
4561 // There could be two different set of parameters for same candidate where one
4562 // is the closest override for default values and named arguments checks and second
4563 // one being the virtual base for the parameter types and modifiers.
4565 // A return value rates candidate method compatibility,
4566 // 0 = the best, int.MaxValue = the worst
4569 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)
4571 // Parameters of most-derived type used mainly for named and optional parameters
4572 var pd = pm.Parameters;
4574 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4575 // params modifier instead of most-derived type
4576 var cpd = ((IParametersMember) candidate).Parameters;
4577 int param_count = pd.Count;
4578 int optional_count = 0;
4580 Arguments orig_args = arguments;
4582 if (arg_count != param_count) {
4584 // No arguments expansion when doing exact match for delegates
4586 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4587 for (int i = 0; i < pd.Count; ++i) {
4588 if (pd.FixedParameters[i].HasDefaultValue) {
4589 optional_count = pd.Count - i;
4595 if (optional_count != 0) {
4596 // Readjust expected number when params used
4597 if (cpd.HasParams) {
4599 if (arg_count < param_count)
4601 } else if (arg_count > param_count) {
4602 int args_gap = System.Math.Abs (arg_count - param_count);
4603 return int.MaxValue - 10000 + args_gap;
4604 } else if (arg_count < param_count - optional_count) {
4605 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4606 return int.MaxValue - 10000 + args_gap;
4608 } else if (arg_count != param_count) {
4609 int args_gap = System.Math.Abs (arg_count - param_count);
4611 return int.MaxValue - 10000 + args_gap;
4612 if (arg_count < param_count - 1)
4613 return int.MaxValue - 10000 + args_gap;
4616 // Resize to fit optional arguments
4617 if (optional_count != 0) {
4618 if (arguments == null) {
4619 arguments = new Arguments (optional_count);
4621 // Have to create a new container, so the next run can do same
4622 var resized = new Arguments (param_count);
4623 resized.AddRange (arguments);
4624 arguments = resized;
4627 for (int i = arg_count; i < param_count; ++i)
4628 arguments.Add (null);
4632 if (arg_count > 0) {
4634 // Shuffle named arguments to the right positions if there are any
4636 if (arguments[arg_count - 1] is NamedArgument) {
4637 arg_count = arguments.Count;
4639 for (int i = 0; i < arg_count; ++i) {
4640 bool arg_moved = false;
4642 NamedArgument na = arguments[i] as NamedArgument;
4646 int index = pd.GetParameterIndexByName (na.Name);
4648 // Named parameter not found
4652 // already reordered
4657 if (index >= param_count) {
4658 // When using parameters which should not be available to the user
4659 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4662 arguments.Add (null);
4666 temp = arguments[index];
4668 // The slot has been taken by positional argument
4669 if (temp != null && !(temp is NamedArgument))
4674 arguments = arguments.MarkOrderedArgument (na);
4678 if (arguments == orig_args) {
4679 arguments = new Arguments (orig_args.Count);
4680 arguments.AddRange (orig_args);
4683 arguments[index] = arguments[i];
4684 arguments[i] = temp;
4691 arg_count = arguments.Count;
4693 } else if (arguments != null) {
4694 arg_count = arguments.Count;
4698 // Don't do any expensive checks when the candidate cannot succeed
4700 if (arg_count != param_count && !cpd.HasParams)
4701 return (param_count - arg_count) * 2 + 1;
4703 var dep = candidate.GetMissingDependencies ();
4705 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4710 // 1. Handle generic method using type arguments when specified or type inference
4713 var ms = candidate as MethodSpec;
4714 if (ms != null && ms.IsGeneric) {
4715 if (type_arguments != null) {
4716 var g_args_count = ms.Arity;
4717 if (g_args_count != type_arguments.Count)
4718 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4720 if (type_arguments.Arguments != null)
4721 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4724 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4725 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4726 // candidate was found use the set to report more details about what was wrong with lambda body.
4727 // The general idea is to distinguish between code errors and errors caused by
4728 // trial-and-error type inference
4730 if (lambda_conv_msgs == null) {
4731 for (int i = 0; i < arg_count; i++) {
4732 Argument a = arguments[i];
4736 var am = a.Expr as AnonymousMethodExpression;
4738 if (lambda_conv_msgs == null)
4739 lambda_conv_msgs = new SessionReportPrinter ();
4741 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4746 var ti = new TypeInference (arguments);
4747 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4750 return ti.InferenceScore - 20000;
4753 // Clear any error messages when the result was success
4755 if (lambda_conv_msgs != null)
4756 lambda_conv_msgs.ClearSession ();
4758 if (i_args.Length != 0) {
4759 ms = ms.MakeGenericMethod (ec, i_args);
4764 // Type arguments constraints have to match for the method to be applicable
4766 if (!CheckInflatedArguments (ms)) {
4768 return int.MaxValue - 25000;
4772 // We have a generic return type and at same time the method is override which
4773 // means we have to also inflate override return type in case the candidate is
4774 // best candidate and override return type is different to base return type.
4776 // virtual Foo<T, object> with override Foo<T, dynamic>
4778 if (candidate != pm) {
4779 MethodSpec override_ms = (MethodSpec) pm;
4780 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4781 returnType = inflator.Inflate (returnType);
4783 returnType = ms.ReturnType;
4790 if (type_arguments != null)
4791 return int.MaxValue - 15000;
4797 // 2. Each argument has to be implicitly convertible to method parameter
4799 Parameter.Modifier p_mod = 0;
4802 for (int i = 0; i < arg_count; i++) {
4803 Argument a = arguments[i];
4805 var fp = pd.FixedParameters[i];
4806 if (!fp.HasDefaultValue) {
4807 arguments = orig_args;
4808 return arg_count * 2 + 2;
4812 // Get the default value expression, we can use the same expression
4813 // if the type matches
4815 Expression e = fp.DefaultValue;
4817 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4819 // Restore for possible error reporting
4820 for (int ii = i; ii < arg_count; ++ii)
4821 arguments.RemoveAt (i);
4823 return (arg_count - i) * 2 + 1;
4827 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4829 // LAMESPEC: Attributes can be mixed together with build-in priority
4831 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4832 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4833 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4834 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4835 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4836 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4840 arguments[i] = new Argument (e, Argument.AType.Default);
4844 if (p_mod != Parameter.Modifier.PARAMS) {
4845 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4847 } else if (!params_expanded_form) {
4848 params_expanded_form = true;
4849 pt = ((ElementTypeSpec) pt).Element;
4855 if (!params_expanded_form) {
4856 if (a.ArgType == Argument.AType.ExtensionType) {
4858 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4860 // LAMESPEC: or implicit type parameter conversion
4863 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4864 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4865 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4870 score = IsArgumentCompatible (ec, a, p_mod, pt);
4873 dynamicArgument = true;
4878 // It can be applicable in expanded form (when not doing exact match like for delegates)
4880 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4881 if (!params_expanded_form) {
4882 pt = ((ElementTypeSpec) pt).Element;
4886 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4889 params_expanded_form = true;
4890 dynamicArgument = true;
4891 } else if (score == 0 || arg_count > pd.Count) {
4892 params_expanded_form = true;
4897 if (params_expanded_form)
4899 return (arg_count - i) * 2 + score;
4904 // Restore original arguments for dynamic binder to keep the intention of original source code
4906 if (dynamicArgument)
4907 arguments = orig_args;
4912 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4914 if (e is Constant && e.Type == ptype)
4918 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4920 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4921 e = new MemberAccess (new MemberAccess (new MemberAccess (
4922 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4923 } else if (e is Constant) {
4925 // Handles int to int? conversions, DefaultParameterValue check
4927 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4931 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4934 return e.Resolve (ec);
4938 // Tests argument compatibility with the parameter
4939 // The possible return values are
4941 // 1 - modifier mismatch
4942 // 2 - type mismatch
4943 // -1 - dynamic binding required
4945 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4948 // Types have to be identical when ref or out modifer
4949 // is used and argument is not of dynamic type
4951 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4952 if (argument.Type != parameter) {
4954 // Do full equality check after quick path
4956 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4958 // Using dynamic for ref/out parameter can still succeed at runtime
4960 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4967 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4969 // Using dynamic for ref/out parameter can still succeed at runtime
4971 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4978 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4982 // Use implicit conversion in all modes to return same candidates when the expression
4983 // is used as argument or delegate conversion
4985 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4986 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4993 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4995 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4997 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5000 var ac_p = p as ArrayContainer;
5002 var ac_q = q as ArrayContainer;
5006 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5007 if (specific == ac_p.Element)
5009 if (specific == ac_q.Element)
5011 } else if (p.IsGeneric && q.IsGeneric) {
5012 var pargs = TypeManager.GetTypeArguments (p);
5013 var qargs = TypeManager.GetTypeArguments (q);
5015 bool p_specific_at_least_once = false;
5016 bool q_specific_at_least_once = false;
5018 for (int i = 0; i < pargs.Length; i++) {
5019 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5020 if (specific == pargs[i])
5021 p_specific_at_least_once = true;
5022 if (specific == qargs[i])
5023 q_specific_at_least_once = true;
5026 if (p_specific_at_least_once && !q_specific_at_least_once)
5028 if (!p_specific_at_least_once && q_specific_at_least_once)
5036 // Find the best method from candidate list
5038 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5040 List<AmbiguousCandidate> ambiguous_candidates = null;
5042 MemberSpec best_candidate;
5043 Arguments best_candidate_args = null;
5044 bool best_candidate_params = false;
5045 bool best_candidate_dynamic = false;
5046 int best_candidate_rate;
5047 IParametersMember best_parameter_member = null;
5049 int args_count = args != null ? args.Count : 0;
5051 Arguments candidate_args = args;
5052 bool error_mode = false;
5053 MemberSpec invocable_member = null;
5056 best_candidate = null;
5057 best_candidate_rate = int.MaxValue;
5059 var type_members = members;
5061 for (int i = 0; i < type_members.Count; ++i) {
5062 var member = type_members[i];
5065 // Methods in a base class are not candidates if any method in a derived
5066 // class is applicable
5068 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5072 if (!member.IsAccessible (rc))
5075 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5078 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5079 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5084 IParametersMember pm = member as IParametersMember;
5087 // Will use it later to report ambiguity between best method and invocable member
5089 if (Invocation.IsMemberInvocable (member))
5090 invocable_member = member;
5096 // Overload resolution is looking for base member but using parameter names
5097 // and default values from the closest member. That means to do expensive lookup
5098 // for the closest override for virtual or abstract members
5100 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5101 var override_params = base_provider.GetOverrideMemberParameters (member);
5102 if (override_params != null)
5103 pm = override_params;
5107 // Check if the member candidate is applicable
5109 bool params_expanded_form = false;
5110 bool dynamic_argument = false;
5111 TypeSpec rt = pm.MemberType;
5112 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5114 if (lambda_conv_msgs != null)
5115 lambda_conv_msgs.EndSession ();
5118 // How does it score compare to others
5120 if (candidate_rate < best_candidate_rate) {
5122 // Fatal error (missing dependency), cannot continue
5123 if (candidate_rate < 0)
5126 best_candidate_rate = candidate_rate;
5127 best_candidate = member;
5128 best_candidate_args = candidate_args;
5129 best_candidate_params = params_expanded_form;
5130 best_candidate_dynamic = dynamic_argument;
5131 best_parameter_member = pm;
5132 best_candidate_return_type = rt;
5133 } else if (candidate_rate == 0) {
5135 // The member look is done per type for most operations but sometimes
5136 // it's not possible like for binary operators overload because they
5137 // are unioned between 2 sides
5139 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5140 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5145 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5147 // We pack all interface members into top level type which makes the overload resolution
5148 // more complicated for interfaces. We compensate it by removing methods with same
5149 // signature when building the cache hence this path should not really be hit often
5152 // interface IA { void Foo (int arg); }
5153 // interface IB : IA { void Foo (params int[] args); }
5155 // IB::Foo is the best overload when calling IB.Foo (1)
5158 if (ambiguous_candidates != null) {
5159 foreach (var amb_cand in ambiguous_candidates) {
5160 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5169 ambiguous_candidates = null;
5172 // Is the new candidate better
5173 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5177 best_candidate = member;
5178 best_candidate_args = candidate_args;
5179 best_candidate_params = params_expanded_form;
5180 best_candidate_dynamic = dynamic_argument;
5181 best_parameter_member = pm;
5182 best_candidate_return_type = rt;
5184 // It's not better but any other found later could be but we are not sure yet
5185 if (ambiguous_candidates == null)
5186 ambiguous_candidates = new List<AmbiguousCandidate> ();
5188 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5192 // Restore expanded arguments
5193 candidate_args = args;
5195 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5198 // We've found exact match
5200 if (best_candidate_rate == 0)
5204 // Try extension methods lookup when no ordinary method match was found and provider enables it
5207 var emg = base_provider.LookupExtensionMethod (rc);
5209 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5211 best_candidate_extension_group = emg;
5212 return (T) (MemberSpec) emg.BestCandidate;
5217 // Don't run expensive error reporting mode for probing
5224 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5227 lambda_conv_msgs = null;
5232 // No best member match found, report an error
5234 if (best_candidate_rate != 0 || error_mode) {
5235 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5239 if (best_candidate_dynamic) {
5240 if (args[0].ArgType == Argument.AType.ExtensionType) {
5241 rc.Report.Error (1973, loc,
5242 "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",
5243 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5247 // Check type constraints only when explicit type arguments are used
5249 if (best_candidate.IsGeneric && type_arguments != null) {
5250 MethodSpec bc = best_candidate as MethodSpec;
5251 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5252 ConstraintChecker cc = new ConstraintChecker (rc);
5253 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5257 BestCandidateIsDynamic = true;
5262 // These flags indicates we are running delegate probing conversion. No need to
5263 // do more expensive checks
5265 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5266 return (T) best_candidate;
5268 if (ambiguous_candidates != null) {
5270 // Now check that there are no ambiguities i.e the selected method
5271 // should be better than all the others
5273 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5274 var candidate = ambiguous_candidates [ix];
5276 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5277 var ambiguous = candidate.Member;
5278 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5279 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5280 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5281 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5282 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5285 return (T) best_candidate;
5290 if (invocable_member != null && !IsProbingOnly) {
5291 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5292 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5293 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5294 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5298 // And now check if the arguments are all
5299 // compatible, perform conversions if
5300 // necessary etc. and return if everything is
5303 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5306 if (best_candidate == null)
5310 // Don't run possibly expensive checks in probing mode
5312 if (!IsProbingOnly && !rc.IsInProbingMode) {
5314 // Check ObsoleteAttribute on the best method
5316 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5317 if (oa != null && !rc.IsObsolete)
5318 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5320 best_candidate.MemberDefinition.SetIsUsed ();
5323 args = best_candidate_args;
5324 return (T) best_candidate;
5327 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5329 return ResolveMember<MethodSpec> (rc, ref args);
5332 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5333 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5335 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5338 if (a.Type == InternalType.ErrorType)
5341 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5342 ec.Report.SymbolRelatedToPreviousError (method);
5343 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5344 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5345 TypeManager.CSharpSignature (method));
5348 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5349 TypeManager.CSharpSignature (method));
5350 } else if (IsDelegateInvoke) {
5351 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5352 DelegateType.GetSignatureForError ());
5354 ec.Report.SymbolRelatedToPreviousError (method);
5355 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5356 method.GetSignatureForError ());
5359 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5361 string index = (idx + 1).ToString ();
5362 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5363 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5364 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5365 index, Parameter.GetModifierSignature (a.Modifier));
5367 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5368 index, Parameter.GetModifierSignature (mod));
5370 string p1 = a.GetSignatureForError ();
5371 string p2 = paramType.GetSignatureForError ();
5374 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5375 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5378 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5379 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5380 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5383 ec.Report.Error (1503, a.Expr.Location,
5384 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5389 // We have failed to find exact match so we return error info about the closest match
5391 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5393 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5394 int arg_count = args == null ? 0 : args.Count;
5396 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5397 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5398 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5402 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5407 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5408 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5409 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5413 // For candidates which match on parameters count report more details about incorrect arguments
5416 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5417 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5418 // Reject any inaccessible member
5419 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5420 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5421 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5425 var ms = best_candidate as MethodSpec;
5426 if (ms != null && ms.IsGeneric) {
5427 bool constr_ok = true;
5428 if (ms.TypeArguments != null)
5429 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5431 if (ta_count == 0 && ms.TypeArguments == null) {
5432 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5436 rc.Report.Error (411, loc,
5437 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5438 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5445 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5451 // We failed to find any method with correct argument count, report best candidate
5453 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5456 if (best_candidate.Kind == MemberKind.Constructor) {
5457 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5458 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5459 } else if (IsDelegateInvoke) {
5460 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5461 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5462 DelegateType.GetSignatureForError (), arg_count.ToString ());
5464 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5465 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5466 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5467 name, arg_count.ToString ());
5471 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5473 var pd = pm.Parameters;
5474 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5476 Parameter.Modifier p_mod = 0;
5478 int a_idx = 0, a_pos = 0;
5480 ArrayInitializer params_initializers = null;
5481 bool has_unsafe_arg = pm.MemberType.IsPointer;
5482 int arg_count = args == null ? 0 : args.Count;
5484 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5489 if (p_mod != Parameter.Modifier.PARAMS) {
5490 p_mod = pd.FixedParameters[a_idx].ModFlags;
5492 has_unsafe_arg |= pt.IsPointer;
5494 if (p_mod == Parameter.Modifier.PARAMS) {
5495 if (chose_params_expanded) {
5496 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5497 pt = TypeManager.GetElementType (pt);
5503 // Types have to be identical when ref or out modifer is used
5505 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5506 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5509 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5515 NamedArgument na = a as NamedArgument;
5517 int name_index = pd.GetParameterIndexByName (na.Name);
5518 if (name_index < 0 || name_index >= pd.Count) {
5519 if (IsDelegateInvoke) {
5520 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5521 ec.Report.Error (1746, na.Location,
5522 "The delegate `{0}' does not contain a parameter named `{1}'",
5523 DelegateType.GetSignatureForError (), na.Name);
5525 ec.Report.SymbolRelatedToPreviousError (member);
5526 ec.Report.Error (1739, na.Location,
5527 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5528 TypeManager.CSharpSignature (member), na.Name);
5530 } else if (args[name_index] != a && args[name_index] != null) {
5531 if (IsDelegateInvoke)
5532 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5534 ec.Report.SymbolRelatedToPreviousError (member);
5536 ec.Report.Error (1744, na.Location,
5537 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5542 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5545 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5546 custom_errors.NoArgumentMatch (ec, member);
5551 if (a.ArgType == Argument.AType.ExtensionType) {
5552 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5555 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5557 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5560 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5567 // Convert params arguments to an array initializer
5569 if (params_initializers != null) {
5570 // we choose to use 'a.Expr' rather than 'conv' so that
5571 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5572 params_initializers.Add (a.Expr);
5573 args.RemoveAt (a_idx--);
5579 // Update the argument with the implicit conversion
5583 if (a_idx != arg_count) {
5584 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5589 // Fill not provided arguments required by params modifier
5591 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5593 args = new Arguments (1);
5595 pt = ptypes[pd.Count - 1];
5596 pt = TypeManager.GetElementType (pt);
5597 has_unsafe_arg |= pt.IsPointer;
5598 params_initializers = new ArrayInitializer (0, loc);
5602 // Append an array argument with all params arguments
5604 if (params_initializers != null) {
5605 args.Add (new Argument (
5606 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5610 if (has_unsafe_arg && !ec.IsUnsafe) {
5611 Expression.UnsafeError (ec, loc);
5615 // We could infer inaccesible type arguments
5617 if (type_arguments == null && member.IsGeneric) {
5618 var ms = (MethodSpec) member;
5619 foreach (var ta in ms.TypeArguments) {
5620 if (!ta.IsAccessible (ec)) {
5621 ec.Report.SymbolRelatedToPreviousError (ta);
5622 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5632 public class ConstantExpr : MemberExpr
5634 readonly ConstSpec constant;
5636 public ConstantExpr (ConstSpec constant, Location loc)
5638 this.constant = constant;
5642 public override string Name {
5643 get { throw new NotImplementedException (); }
5646 public override string KindName {
5647 get { return "constant"; }
5650 public override bool IsInstance {
5651 get { return !IsStatic; }
5654 public override bool IsStatic {
5655 get { return true; }
5658 protected override TypeSpec DeclaringType {
5659 get { return constant.DeclaringType; }
5662 public override Expression CreateExpressionTree (ResolveContext ec)
5664 throw new NotSupportedException ("ET");
5667 protected override Expression DoResolve (ResolveContext rc)
5669 ResolveInstanceExpression (rc, null);
5670 DoBestMemberChecks (rc, constant);
5672 var c = constant.GetConstant (rc);
5674 // Creates reference expression to the constant value
5675 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5678 public override void Emit (EmitContext ec)
5680 throw new NotSupportedException ();
5683 public override string GetSignatureForError ()
5685 return constant.GetSignatureForError ();
5688 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5690 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5695 // Fully resolved expression that references a Field
5697 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5699 protected FieldSpec spec;
5700 VariableInfo variable_info;
5702 LocalTemporary temp;
5705 protected FieldExpr (Location l)
5710 public FieldExpr (FieldSpec spec, Location loc)
5715 type = spec.MemberType;
5718 public FieldExpr (FieldBase fi, Location l)
5725 public override string Name {
5731 public bool IsHoisted {
5733 IVariableReference hv = InstanceExpression as IVariableReference;
5734 return hv != null && hv.IsHoisted;
5738 public override bool IsInstance {
5740 return !spec.IsStatic;
5744 public override bool IsStatic {
5746 return spec.IsStatic;
5750 public override string KindName {
5751 get { return "field"; }
5754 public FieldSpec Spec {
5760 protected override TypeSpec DeclaringType {
5762 return spec.DeclaringType;
5766 public VariableInfo VariableInfo {
5768 return variable_info;
5774 public override string GetSignatureForError ()
5776 return spec.GetSignatureForError ();
5779 public bool IsMarshalByRefAccess (ResolveContext rc)
5781 // Checks possible ldflda of field access expression
5782 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5783 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5784 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5787 public void SetHasAddressTaken ()
5789 IVariableReference vr = InstanceExpression as IVariableReference;
5791 vr.SetHasAddressTaken ();
5795 protected override void CloneTo (CloneContext clonectx, Expression target)
5797 var t = (FieldExpr) target;
5799 if (InstanceExpression != null)
5800 t.InstanceExpression = InstanceExpression.Clone (clonectx);
5803 public override Expression CreateExpressionTree (ResolveContext ec)
5805 return CreateExpressionTree (ec, true);
5808 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5811 Expression instance;
5813 if (InstanceExpression == null) {
5814 instance = new NullLiteral (loc);
5815 } else if (convertInstance) {
5816 instance = InstanceExpression.CreateExpressionTree (ec);
5818 args = new Arguments (1);
5819 args.Add (new Argument (InstanceExpression));
5820 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5823 args = Arguments.CreateForExpressionTree (ec, null,
5825 CreateTypeOfExpression ());
5827 return CreateExpressionFactoryCall (ec, "Field", args);
5830 public Expression CreateTypeOfExpression ()
5832 return new TypeOfField (spec, loc);
5835 protected override Expression DoResolve (ResolveContext ec)
5837 spec.MemberDefinition.SetIsUsed ();
5839 return DoResolve (ec, null);
5842 Expression DoResolve (ResolveContext ec, Expression rhs)
5844 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5847 if (ResolveInstanceExpression (ec, rhs)) {
5848 // Resolve the field's instance expression while flow analysis is turned
5849 // off: when accessing a field "a.b", we must check whether the field
5850 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5852 if (lvalue_instance) {
5853 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5855 Expression right_side =
5856 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5858 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5860 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5863 if (InstanceExpression == null)
5867 DoBestMemberChecks (ec, spec);
5870 var fb = spec as FixedFieldSpec;
5871 IVariableReference var = InstanceExpression as IVariableReference;
5874 IFixedExpression fe = InstanceExpression as IFixedExpression;
5875 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5876 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5879 if (InstanceExpression.eclass != ExprClass.Variable) {
5880 ec.Report.SymbolRelatedToPreviousError (spec);
5881 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5882 TypeManager.GetFullNameSignature (spec));
5883 } else if (var != null && var.IsHoisted) {
5884 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5887 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5891 // Set flow-analysis variable info for struct member access. It will be check later
5892 // for precise error reporting
5894 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5895 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5898 eclass = ExprClass.Variable;
5902 public void SetFieldAssigned (FlowAnalysisContext fc)
5907 bool lvalue_instance = spec.DeclaringType.IsStruct;
5908 if (lvalue_instance) {
5909 var var = InstanceExpression as IVariableReference;
5910 if (var != null && var.VariableInfo != null) {
5911 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5915 var fe = InstanceExpression as FieldExpr;
5917 Expression instance;
5920 instance = fe.InstanceExpression;
5921 var fe_instance = instance as FieldExpr;
5922 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5923 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5924 var var = InstanceExpression as IVariableReference;
5925 if (var != null && var.VariableInfo == null) {
5926 var var_inst = instance as IVariableReference;
5927 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5928 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5932 if (fe_instance != null) {
5941 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
5942 instance.FlowAnalysis (fc);
5944 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
5945 InstanceExpression.FlowAnalysis (fc);
5949 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5951 // The return value is always null. Returning a value simplifies calling code.
5953 if (right_side == EmptyExpression.OutAccess) {
5955 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5956 GetSignatureForError ());
5958 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5959 GetSignatureForError ());
5965 if (right_side == EmptyExpression.LValueMemberAccess) {
5966 // Already reported as CS1648/CS1650
5970 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5972 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5973 GetSignatureForError ());
5975 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5976 GetSignatureForError ());
5982 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5983 GetSignatureForError ());
5985 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5986 GetSignatureForError ());
5992 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5994 if (spec is FixedFieldSpec) {
5995 // It could be much better error message but we want to be error compatible
5996 Error_ValueAssignment (ec, right_side);
5999 Expression e = DoResolve (ec, right_side);
6004 spec.MemberDefinition.SetIsAssigned ();
6006 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6007 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6008 ec.Report.Warning (420, 1, loc,
6009 "`{0}': A volatile field references will not be treated as volatile",
6010 spec.GetSignatureForError ());
6013 if (spec.IsReadOnly) {
6014 // InitOnly fields can only be assigned in constructors or initializers
6015 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6016 return Error_AssignToReadonly (ec, right_side);
6018 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6020 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6021 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6022 return Error_AssignToReadonly (ec, right_side);
6023 // static InitOnly fields cannot be assigned-to in an instance constructor
6024 if (IsStatic && !ec.IsStatic)
6025 return Error_AssignToReadonly (ec, right_side);
6026 // instance constructors can't modify InitOnly fields of other instances of the same type
6027 if (!IsStatic && !(InstanceExpression is This))
6028 return Error_AssignToReadonly (ec, right_side);
6032 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6033 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6034 ec.Report.Warning (197, 1, loc,
6035 "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",
6036 GetSignatureForError ());
6039 eclass = ExprClass.Variable;
6043 public override void FlowAnalysis (FlowAnalysisContext fc)
6045 var var = InstanceExpression as IVariableReference;
6047 var vi = var.VariableInfo;
6048 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6049 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6053 if (TypeSpec.IsValueType (InstanceExpression.Type))
6057 base.FlowAnalysis (fc);
6060 public override int GetHashCode ()
6062 return spec.GetHashCode ();
6065 public bool IsFixed {
6068 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6070 IVariableReference variable = InstanceExpression as IVariableReference;
6071 if (variable != null)
6072 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6074 IFixedExpression fe = InstanceExpression as IFixedExpression;
6075 return fe != null && fe.IsFixed;
6079 public override bool Equals (object obj)
6081 FieldExpr fe = obj as FieldExpr;
6085 if (spec != fe.spec)
6088 if (InstanceExpression == null || fe.InstanceExpression == null)
6091 return InstanceExpression.Equals (fe.InstanceExpression);
6094 public void Emit (EmitContext ec, bool leave_copy)
6096 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6100 ec.Emit (OpCodes.Volatile);
6102 ec.Emit (OpCodes.Ldsfld, spec);
6105 EmitInstance (ec, false);
6107 // Optimization for build-in types
6108 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6109 ec.EmitLoadFromPtr (type);
6111 var ff = spec as FixedFieldSpec;
6113 ec.Emit (OpCodes.Ldflda, spec);
6114 ec.Emit (OpCodes.Ldflda, ff.Element);
6117 ec.Emit (OpCodes.Volatile);
6119 ec.Emit (OpCodes.Ldfld, spec);
6125 ec.Emit (OpCodes.Dup);
6127 temp = new LocalTemporary (this.Type);
6133 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6135 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6136 if (isCompound && !(source is DynamicExpressionStatement)) {
6137 if (has_await_source) {
6139 InstanceExpression = InstanceExpression.EmitToField (ec);
6146 if (has_await_source)
6147 source = source.EmitToField (ec);
6149 EmitInstance (ec, prepared);
6155 ec.Emit (OpCodes.Dup);
6157 temp = new LocalTemporary (this.Type);
6162 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6163 ec.Emit (OpCodes.Volatile);
6165 spec.MemberDefinition.SetIsAssigned ();
6168 ec.Emit (OpCodes.Stsfld, spec);
6170 ec.Emit (OpCodes.Stfld, spec);
6180 // Emits store to field with prepared values on stack
6182 public void EmitAssignFromStack (EmitContext ec)
6185 ec.Emit (OpCodes.Stsfld, spec);
6187 ec.Emit (OpCodes.Stfld, spec);
6191 public override void Emit (EmitContext ec)
6196 public override void EmitSideEffect (EmitContext ec)
6198 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6200 if (is_volatile) // || is_marshal_by_ref ())
6201 base.EmitSideEffect (ec);
6204 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6206 if ((mode & AddressOp.Store) != 0)
6207 spec.MemberDefinition.SetIsAssigned ();
6208 if ((mode & AddressOp.Load) != 0)
6209 spec.MemberDefinition.SetIsUsed ();
6212 // Handle initonly fields specially: make a copy and then
6213 // get the address of the copy.
6216 if (spec.IsReadOnly){
6218 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6230 var temp = ec.GetTemporaryLocal (type);
6231 ec.Emit (OpCodes.Stloc, temp);
6232 ec.Emit (OpCodes.Ldloca, temp);
6233 ec.FreeTemporaryLocal (temp, type);
6239 ec.Emit (OpCodes.Ldsflda, spec);
6242 EmitInstance (ec, false);
6243 ec.Emit (OpCodes.Ldflda, spec);
6247 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6249 return MakeExpression (ctx);
6252 public override SLE.Expression MakeExpression (BuilderContext ctx)
6255 return base.MakeExpression (ctx);
6257 return SLE.Expression.Field (
6258 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6259 spec.GetMetaInfo ());
6263 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6265 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6271 // Expression that evaluates to a Property.
6273 // This is not an LValue because we need to re-write the expression. We
6274 // can not take data from the stack and store it.
6276 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6278 Arguments arguments;
6280 public PropertyExpr (PropertySpec spec, Location l)
6283 best_candidate = spec;
6284 type = spec.MemberType;
6289 protected override Arguments Arguments {
6298 protected override TypeSpec DeclaringType {
6300 return best_candidate.DeclaringType;
6304 public override string Name {
6306 return best_candidate.Name;
6310 public override bool IsInstance {
6316 public override bool IsStatic {
6318 return best_candidate.IsStatic;
6322 public override string KindName {
6323 get { return "property"; }
6326 public PropertySpec PropertyInfo {
6328 return best_candidate;
6334 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6336 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6339 var args_count = arguments == null ? 0 : arguments.Count;
6340 if (args_count != body.Parameters.Count && args_count == 0)
6343 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6344 mg.InstanceExpression = InstanceExpression;
6349 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6351 return new PropertyExpr (spec, loc) {
6357 public override Expression CreateExpressionTree (ResolveContext ec)
6360 if (IsSingleDimensionalArrayLength ()) {
6361 args = new Arguments (1);
6362 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6363 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6366 args = new Arguments (2);
6367 if (InstanceExpression == null)
6368 args.Add (new Argument (new NullLiteral (loc)));
6370 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6371 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6372 return CreateExpressionFactoryCall (ec, "Property", args);
6375 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6377 DoResolveLValue (rc, null);
6378 return new TypeOfMethod (Setter, loc);
6381 public override string GetSignatureForError ()
6383 return best_candidate.GetSignatureForError ();
6386 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6389 return base.MakeExpression (ctx);
6391 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6395 public override SLE.Expression MakeExpression (BuilderContext ctx)
6398 return base.MakeExpression (ctx);
6400 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6404 void Error_PropertyNotValid (ResolveContext ec)
6406 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6407 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6408 GetSignatureForError ());
6411 bool IsSingleDimensionalArrayLength ()
6413 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6416 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6417 return ac != null && ac.Rank == 1;
6420 public override void Emit (EmitContext ec, bool leave_copy)
6423 // Special case: length of single dimension array property is turned into ldlen
6425 if (IsSingleDimensionalArrayLength ()) {
6426 EmitInstance (ec, false);
6427 ec.Emit (OpCodes.Ldlen);
6428 ec.Emit (OpCodes.Conv_I4);
6432 base.Emit (ec, leave_copy);
6435 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6438 LocalTemporary await_source_arg = null;
6440 if (isCompound && !(source is DynamicExpressionStatement)) {
6441 emitting_compound_assignment = true;
6444 if (has_await_arguments) {
6445 await_source_arg = new LocalTemporary (Type);
6446 await_source_arg.Store (ec);
6448 args = new Arguments (1);
6449 args.Add (new Argument (await_source_arg));
6452 temp = await_source_arg;
6455 has_await_arguments = false;
6460 ec.Emit (OpCodes.Dup);
6461 temp = new LocalTemporary (this.Type);
6466 args = arguments ?? new Arguments (1);
6470 temp = new LocalTemporary (this.Type);
6472 args.Add (new Argument (temp));
6474 args.Add (new Argument (source));
6478 emitting_compound_assignment = false;
6480 var call = new CallEmitter ();
6481 call.InstanceExpression = InstanceExpression;
6483 call.InstanceExpressionOnStack = true;
6485 call.Emit (ec, Setter, args, loc);
6492 if (await_source_arg != null) {
6493 await_source_arg.Release (ec);
6497 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6499 eclass = ExprClass.PropertyAccess;
6501 if (best_candidate.IsNotCSharpCompatible) {
6502 Error_PropertyNotValid (rc);
6505 ResolveInstanceExpression (rc, right_side);
6507 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6508 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6509 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6511 type = p.MemberType;
6515 DoBestMemberChecks (rc, best_candidate);
6517 // Handling of com-imported properties with any number of default property parameters
6518 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6519 var p = best_candidate.Get.Parameters;
6520 arguments = new Arguments (p.Count);
6521 for (int i = 0; i < p.Count; ++i) {
6522 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6524 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6525 var p = best_candidate.Set.Parameters;
6526 arguments = new Arguments (p.Count - 1);
6527 for (int i = 0; i < p.Count - 1; ++i) {
6528 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6535 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6537 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6541 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6543 // getter and setter can be different for base calls
6544 MethodSpec getter, setter;
6545 protected T best_candidate;
6547 protected LocalTemporary temp;
6548 protected bool emitting_compound_assignment;
6549 protected bool has_await_arguments;
6551 protected PropertyOrIndexerExpr (Location l)
6558 protected abstract Arguments Arguments { get; set; }
6560 public MethodSpec Getter {
6569 public MethodSpec Setter {
6580 protected override Expression DoResolve (ResolveContext ec)
6582 if (eclass == ExprClass.Unresolved) {
6583 var expr = OverloadResolve (ec, null);
6588 return expr.Resolve (ec);
6591 if (!ResolveGetter (ec))
6597 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6599 if (right_side == EmptyExpression.OutAccess) {
6600 // TODO: best_candidate can be null at this point
6601 INamedBlockVariable variable = null;
6602 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6603 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6604 best_candidate.Name);
6606 right_side.DoResolveLValue (ec, this);
6611 if (eclass == ExprClass.Unresolved) {
6612 var expr = OverloadResolve (ec, right_side);
6617 return expr.ResolveLValue (ec, right_side);
6619 ResolveInstanceExpression (ec, right_side);
6622 if (!ResolveSetter (ec))
6629 // Implements the IAssignMethod interface for assignments
6631 public virtual void Emit (EmitContext ec, bool leave_copy)
6633 var call = new CallEmitter ();
6634 call.InstanceExpression = InstanceExpression;
6635 if (has_await_arguments)
6636 call.HasAwaitArguments = true;
6638 call.DuplicateArguments = emitting_compound_assignment;
6640 call.Emit (ec, Getter, Arguments, loc);
6642 if (call.HasAwaitArguments) {
6643 InstanceExpression = call.InstanceExpression;
6644 Arguments = call.EmittedArguments;
6645 has_await_arguments = true;
6649 ec.Emit (OpCodes.Dup);
6650 temp = new LocalTemporary (Type);
6655 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6657 public override void Emit (EmitContext ec)
6662 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6664 has_await_arguments = true;
6669 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6671 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6673 bool ResolveGetter (ResolveContext rc)
6675 if (!best_candidate.HasGet) {
6676 if (InstanceExpression != EmptyExpression.Null) {
6677 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6678 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6679 best_candidate.GetSignatureForError ());
6682 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6683 if (best_candidate.HasDifferentAccessibility) {
6684 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6685 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6686 TypeManager.CSharpSignature (best_candidate));
6688 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6689 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6693 if (best_candidate.HasDifferentAccessibility) {
6694 CheckProtectedMemberAccess (rc, best_candidate.Get);
6697 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6701 bool ResolveSetter (ResolveContext rc)
6703 if (!best_candidate.HasSet) {
6704 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6705 GetSignatureForError ());
6709 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6710 if (best_candidate.HasDifferentAccessibility) {
6711 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6712 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6713 GetSignatureForError ());
6715 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6716 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6720 if (best_candidate.HasDifferentAccessibility)
6721 CheckProtectedMemberAccess (rc, best_candidate.Set);
6723 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6729 /// Fully resolved expression that evaluates to an Event
6731 public class EventExpr : MemberExpr, IAssignMethod
6733 readonly EventSpec spec;
6736 public EventExpr (EventSpec spec, Location loc)
6744 protected override TypeSpec DeclaringType {
6746 return spec.DeclaringType;
6750 public override string Name {
6756 public override bool IsInstance {
6758 return !spec.IsStatic;
6762 public override bool IsStatic {
6764 return spec.IsStatic;
6768 public override string KindName {
6769 get { return "event"; }
6772 public MethodSpec Operator {
6780 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6783 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6785 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6786 if (spec.BackingField != null &&
6787 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6789 spec.MemberDefinition.SetIsUsed ();
6791 if (!ec.IsObsolete) {
6792 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6794 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6797 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6798 Error_AssignmentEventOnly (ec);
6800 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6802 InstanceExpression = null;
6804 return ml.ResolveMemberAccess (ec, left, original);
6808 return base.ResolveMemberAccess (ec, left, original);
6811 public override Expression CreateExpressionTree (ResolveContext ec)
6813 throw new NotSupportedException ("ET");
6816 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6818 if (right_side == EmptyExpression.EventAddition) {
6819 op = spec.AccessorAdd;
6820 } else if (right_side == EmptyExpression.EventSubtraction) {
6821 op = spec.AccessorRemove;
6825 Error_AssignmentEventOnly (ec);
6829 op = CandidateToBaseOverride (ec, op);
6833 protected override Expression DoResolve (ResolveContext ec)
6835 eclass = ExprClass.EventAccess;
6836 type = spec.MemberType;
6838 ResolveInstanceExpression (ec, null);
6840 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6841 Error_AssignmentEventOnly (ec);
6844 DoBestMemberChecks (ec, spec);
6848 public override void Emit (EmitContext ec)
6850 throw new NotSupportedException ();
6851 //Error_CannotAssign ();
6854 #region IAssignMethod Members
6856 public void Emit (EmitContext ec, bool leave_copy)
6858 throw new NotImplementedException ();
6861 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6863 if (leave_copy || !isCompound)
6864 throw new NotImplementedException ("EventExpr::EmitAssign");
6866 Arguments args = new Arguments (1);
6867 args.Add (new Argument (source));
6869 var call = new CallEmitter ();
6870 call.InstanceExpression = InstanceExpression;
6871 call.Emit (ec, op, args, loc);
6876 void Error_AssignmentEventOnly (ResolveContext ec)
6878 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6879 ec.Report.Error (79, loc,
6880 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6881 GetSignatureForError ());
6883 ec.Report.Error (70, loc,
6884 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6885 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6889 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6891 name = name.Substring (0, name.LastIndexOf ('.'));
6892 base.Error_CannotCallAbstractBase (rc, name);
6895 public override string GetSignatureForError ()
6897 return TypeManager.CSharpSignature (spec);
6900 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6902 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6906 public class TemporaryVariableReference : VariableReference
6908 public class Declarator : Statement
6910 TemporaryVariableReference variable;
6912 public Declarator (TemporaryVariableReference variable)
6914 this.variable = variable;
6918 protected override void DoEmit (EmitContext ec)
6920 variable.li.CreateBuilder (ec);
6923 public override void Emit (EmitContext ec)
6925 // Don't create sequence point
6929 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6934 protected override void CloneTo (CloneContext clonectx, Statement target)
6942 public TemporaryVariableReference (LocalVariable li, Location loc)
6945 this.type = li.Type;
6949 public override bool IsLockedByStatement {
6957 public LocalVariable LocalInfo {
6963 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6965 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6966 return new TemporaryVariableReference (li, loc);
6969 protected override Expression DoResolve (ResolveContext ec)
6971 eclass = ExprClass.Variable;
6974 // Don't capture temporary variables except when using
6975 // state machine redirection and block yields
6977 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6978 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6979 ec.IsVariableCapturingRequired) {
6980 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6981 storey.CaptureLocalVariable (ec, li);
6987 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6989 return Resolve (ec);
6992 public override void Emit (EmitContext ec)
6994 li.CreateBuilder (ec);
6999 public void EmitAssign (EmitContext ec, Expression source)
7001 li.CreateBuilder (ec);
7003 EmitAssign (ec, source, false, false);
7006 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7008 return li.HoistedVariant;
7011 public override bool IsFixed {
7012 get { return true; }
7015 public override bool IsRef {
7016 get { return false; }
7019 public override string Name {
7020 get { throw new NotImplementedException (); }
7023 public override void SetHasAddressTaken ()
7025 throw new NotImplementedException ();
7028 protected override ILocalVariable Variable {
7032 public override VariableInfo VariableInfo {
7033 get { return null; }
7038 /// Handles `var' contextual keyword; var becomes a keyword only
7039 /// if no type called var exists in a variable scope
7041 class VarExpr : SimpleName
7043 public VarExpr (Location loc)
7048 public bool InferType (ResolveContext ec, Expression right_side)
7051 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7053 type = right_side.Type;
7054 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7055 ec.Report.Error (815, loc,
7056 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7057 type.GetSignatureForError ());
7061 eclass = ExprClass.Variable;
7065 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7067 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7068 base.Error_TypeOrNamespaceNotFound (ec);
7070 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");