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;
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))
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 // This handles the case
4445 // Add (float f1, float f2, float f3);
4446 // Add (params decimal [] foo);
4448 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4449 // first candidate would've chosen as better.
4451 if (!same && !a.IsDefaultArgument)
4455 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4459 // This handles the following cases:
4461 // Foo (int i) is better than Foo (int i, long l = 0)
4462 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4463 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4465 // Prefer non-optional version
4467 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4469 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4470 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4473 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4476 return candidate_pd.Count >= best_pd.Count;
4480 // One is a non-generic method and second is a generic method, then non-generic is better
4482 if (best.IsGeneric != candidate.IsGeneric)
4483 return best.IsGeneric;
4486 // This handles the following cases:
4488 // Trim () is better than Trim (params char[] chars)
4489 // Concat (string s1, string s2, string s3) is better than
4490 // Concat (string s1, params string [] srest)
4491 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4493 // Prefer non-expanded version
4495 if (candidate_params != best_params)
4498 int candidate_param_count = candidate_pd.Count;
4499 int best_param_count = best_pd.Count;
4501 if (candidate_param_count != best_param_count)
4502 // can only happen if (candidate_params && best_params)
4503 return candidate_param_count > best_param_count && best_pd.HasParams;
4506 // Both methods have the same number of parameters, and the parameters have equal types
4507 // Pick the "more specific" signature using rules over original (non-inflated) types
4509 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4510 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4512 bool specific_at_least_once = false;
4513 for (j = 0; j < args_count; ++j) {
4514 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4516 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4517 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4519 ct = candidate_def_pd.Types[j];
4520 bt = best_def_pd.Types[j];
4525 TypeSpec specific = MoreSpecific (ct, bt);
4529 specific_at_least_once = true;
4532 if (specific_at_least_once)
4538 static bool CheckInflatedArguments (MethodSpec ms)
4540 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4543 // Setup constraint checker for probing only
4544 ConstraintChecker cc = new ConstraintChecker (null);
4546 var mp = ms.Parameters.Types;
4547 for (int i = 0; i < mp.Length; ++i) {
4548 var type = mp[i] as InflatedTypeSpec;
4552 var targs = type.TypeArguments;
4553 if (targs.Length == 0)
4556 // TODO: Checking inflated MVAR arguments should be enough
4557 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4564 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4566 rc.Report.Error (1729, loc,
4567 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4568 type.GetSignatureForError (), argCount.ToString ());
4572 // Determines if the candidate method is applicable to the given set of arguments
4573 // There could be two different set of parameters for same candidate where one
4574 // is the closest override for default values and named arguments checks and second
4575 // one being the virtual base for the parameter types and modifiers.
4577 // A return value rates candidate method compatibility,
4578 // 0 = the best, int.MaxValue = the worst
4581 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)
4583 // Parameters of most-derived type used mainly for named and optional parameters
4584 var pd = pm.Parameters;
4586 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4587 // params modifier instead of most-derived type
4588 var cpd = ((IParametersMember) candidate).Parameters;
4589 int param_count = pd.Count;
4590 int optional_count = 0;
4592 Arguments orig_args = arguments;
4594 if (arg_count != param_count) {
4596 // No arguments expansion when doing exact match for delegates
4598 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4599 for (int i = 0; i < pd.Count; ++i) {
4600 if (pd.FixedParameters[i].HasDefaultValue) {
4601 optional_count = pd.Count - i;
4607 if (optional_count != 0) {
4608 // Readjust expected number when params used
4609 if (cpd.HasParams) {
4611 if (arg_count < param_count)
4613 } else if (arg_count > param_count) {
4614 int args_gap = System.Math.Abs (arg_count - param_count);
4615 return int.MaxValue - 10000 + args_gap;
4616 } else if (arg_count < param_count - optional_count) {
4617 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4618 return int.MaxValue - 10000 + args_gap;
4620 } else if (arg_count != param_count) {
4621 int args_gap = System.Math.Abs (arg_count - param_count);
4623 return int.MaxValue - 10000 + args_gap;
4624 if (arg_count < param_count - 1)
4625 return int.MaxValue - 10000 + args_gap;
4628 // Resize to fit optional arguments
4629 if (optional_count != 0) {
4630 if (arguments == null) {
4631 arguments = new Arguments (optional_count);
4633 // Have to create a new container, so the next run can do same
4634 var resized = new Arguments (param_count);
4635 resized.AddRange (arguments);
4636 arguments = resized;
4639 for (int i = arg_count; i < param_count; ++i)
4640 arguments.Add (null);
4644 if (arg_count > 0) {
4646 // Shuffle named arguments to the right positions if there are any
4648 if (arguments[arg_count - 1] is NamedArgument) {
4649 arg_count = arguments.Count;
4651 for (int i = 0; i < arg_count; ++i) {
4652 bool arg_moved = false;
4654 NamedArgument na = arguments[i] as NamedArgument;
4658 int index = pd.GetParameterIndexByName (na.Name);
4660 // Named parameter not found
4664 // already reordered
4669 if (index >= param_count) {
4670 // When using parameters which should not be available to the user
4671 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4674 arguments.Add (null);
4678 temp = arguments[index];
4680 // The slot has been taken by positional argument
4681 if (temp != null && !(temp is NamedArgument))
4686 arguments = arguments.MarkOrderedArgument (na);
4690 if (arguments == orig_args) {
4691 arguments = new Arguments (orig_args.Count);
4692 arguments.AddRange (orig_args);
4695 arguments[index] = arguments[i];
4696 arguments[i] = temp;
4703 arg_count = arguments.Count;
4705 } else if (arguments != null) {
4706 arg_count = arguments.Count;
4710 // Don't do any expensive checks when the candidate cannot succeed
4712 if (arg_count != param_count && !cpd.HasParams)
4713 return (param_count - arg_count) * 2 + 1;
4715 var dep = candidate.GetMissingDependencies ();
4717 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4722 // 1. Handle generic method using type arguments when specified or type inference
4725 var ms = candidate as MethodSpec;
4726 if (ms != null && ms.IsGeneric) {
4727 if (type_arguments != null) {
4728 var g_args_count = ms.Arity;
4729 if (g_args_count != type_arguments.Count)
4730 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4732 if (type_arguments.Arguments != null)
4733 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4736 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4737 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4738 // candidate was found use the set to report more details about what was wrong with lambda body.
4739 // The general idea is to distinguish between code errors and errors caused by
4740 // trial-and-error type inference
4742 if (lambda_conv_msgs == null) {
4743 for (int i = 0; i < arg_count; i++) {
4744 Argument a = arguments[i];
4748 var am = a.Expr as AnonymousMethodExpression;
4750 if (lambda_conv_msgs == null)
4751 lambda_conv_msgs = new SessionReportPrinter ();
4753 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4758 var ti = new TypeInference (arguments);
4759 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4762 return ti.InferenceScore - 20000;
4765 // Clear any error messages when the result was success
4767 if (lambda_conv_msgs != null)
4768 lambda_conv_msgs.ClearSession ();
4770 if (i_args.Length != 0) {
4771 ms = ms.MakeGenericMethod (ec, i_args);
4776 // Type arguments constraints have to match for the method to be applicable
4778 if (!CheckInflatedArguments (ms)) {
4780 return int.MaxValue - 25000;
4784 // We have a generic return type and at same time the method is override which
4785 // means we have to also inflate override return type in case the candidate is
4786 // best candidate and override return type is different to base return type.
4788 // virtual Foo<T, object> with override Foo<T, dynamic>
4790 if (candidate != pm) {
4791 MethodSpec override_ms = (MethodSpec) pm;
4792 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4793 returnType = inflator.Inflate (returnType);
4795 returnType = ms.ReturnType;
4802 if (type_arguments != null)
4803 return int.MaxValue - 15000;
4809 // 2. Each argument has to be implicitly convertible to method parameter
4811 Parameter.Modifier p_mod = 0;
4814 for (int i = 0; i < arg_count; i++) {
4815 Argument a = arguments[i];
4817 var fp = pd.FixedParameters[i];
4818 if (!fp.HasDefaultValue) {
4819 arguments = orig_args;
4820 return arg_count * 2 + 2;
4824 // Get the default value expression, we can use the same expression
4825 // if the type matches
4827 Expression e = fp.DefaultValue;
4829 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4831 // Restore for possible error reporting
4832 for (int ii = i; ii < arg_count; ++ii)
4833 arguments.RemoveAt (i);
4835 return (arg_count - i) * 2 + 1;
4839 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4841 // LAMESPEC: Attributes can be mixed together with build-in priority
4843 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4844 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4845 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4846 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4847 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4848 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4852 arguments[i] = new Argument (e, Argument.AType.Default);
4856 if (p_mod != Parameter.Modifier.PARAMS) {
4857 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4859 } else if (!params_expanded_form) {
4860 params_expanded_form = true;
4861 pt = ((ElementTypeSpec) pt).Element;
4867 if (!params_expanded_form) {
4868 if (a.ArgType == Argument.AType.ExtensionType) {
4870 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4872 // LAMESPEC: or implicit type parameter conversion
4875 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4876 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4877 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4882 score = IsArgumentCompatible (ec, a, p_mod, pt);
4885 dynamicArgument = true;
4890 // It can be applicable in expanded form (when not doing exact match like for delegates)
4892 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4893 if (!params_expanded_form) {
4894 pt = ((ElementTypeSpec) pt).Element;
4898 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4901 params_expanded_form = true;
4902 dynamicArgument = true;
4903 } else if (score == 0 || arg_count > pd.Count) {
4904 params_expanded_form = true;
4909 if (params_expanded_form)
4911 return (arg_count - i) * 2 + score;
4916 // When params parameter has no argument it will be provided later if the method is the best candidate
4918 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4919 params_expanded_form = true;
4922 // Restore original arguments for dynamic binder to keep the intention of original source code
4924 if (dynamicArgument)
4925 arguments = orig_args;
4930 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4932 if (e is Constant && e.Type == ptype)
4936 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4938 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4939 e = new MemberAccess (new MemberAccess (new MemberAccess (
4940 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4941 } else if (e is Constant) {
4943 // Handles int to int? conversions, DefaultParameterValue check
4945 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4949 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4952 return e.Resolve (ec);
4956 // Tests argument compatibility with the parameter
4957 // The possible return values are
4959 // 1 - modifier mismatch
4960 // 2 - type mismatch
4961 // -1 - dynamic binding required
4963 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4966 // Types have to be identical when ref or out modifer
4967 // is used and argument is not of dynamic type
4969 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4970 if (argument.Type != parameter) {
4972 // Do full equality check after quick path
4974 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4976 // Using dynamic for ref/out parameter can still succeed at runtime
4978 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4985 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4987 // Using dynamic for ref/out parameter can still succeed at runtime
4989 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4996 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5000 // Use implicit conversion in all modes to return same candidates when the expression
5001 // is used as argument or delegate conversion
5003 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5004 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5011 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5013 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5015 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5018 var ac_p = p as ArrayContainer;
5020 var ac_q = q as ArrayContainer;
5024 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5025 if (specific == ac_p.Element)
5027 if (specific == ac_q.Element)
5029 } else if (p.IsGeneric && q.IsGeneric) {
5030 var pargs = TypeManager.GetTypeArguments (p);
5031 var qargs = TypeManager.GetTypeArguments (q);
5033 bool p_specific_at_least_once = false;
5034 bool q_specific_at_least_once = false;
5036 for (int i = 0; i < pargs.Length; i++) {
5037 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5038 if (specific == pargs[i])
5039 p_specific_at_least_once = true;
5040 if (specific == qargs[i])
5041 q_specific_at_least_once = true;
5044 if (p_specific_at_least_once && !q_specific_at_least_once)
5046 if (!p_specific_at_least_once && q_specific_at_least_once)
5054 // Find the best method from candidate list
5056 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5058 List<AmbiguousCandidate> ambiguous_candidates = null;
5060 MemberSpec best_candidate;
5061 Arguments best_candidate_args = null;
5062 bool best_candidate_params = false;
5063 bool best_candidate_dynamic = false;
5064 int best_candidate_rate;
5065 IParametersMember best_parameter_member = null;
5067 int args_count = args != null ? args.Count : 0;
5069 Arguments candidate_args = args;
5070 bool error_mode = false;
5071 MemberSpec invocable_member = null;
5074 best_candidate = null;
5075 best_candidate_rate = int.MaxValue;
5077 var type_members = members;
5079 for (int i = 0; i < type_members.Count; ++i) {
5080 var member = type_members[i];
5083 // Methods in a base class are not candidates if any method in a derived
5084 // class is applicable
5086 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5090 if (!member.IsAccessible (rc))
5093 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5096 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5097 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5102 IParametersMember pm = member as IParametersMember;
5105 // Will use it later to report ambiguity between best method and invocable member
5107 if (Invocation.IsMemberInvocable (member))
5108 invocable_member = member;
5114 // Overload resolution is looking for base member but using parameter names
5115 // and default values from the closest member. That means to do expensive lookup
5116 // for the closest override for virtual or abstract members
5118 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5119 var override_params = base_provider.GetOverrideMemberParameters (member);
5120 if (override_params != null)
5121 pm = override_params;
5125 // Check if the member candidate is applicable
5127 bool params_expanded_form = false;
5128 bool dynamic_argument = false;
5129 TypeSpec rt = pm.MemberType;
5130 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5132 if (lambda_conv_msgs != null)
5133 lambda_conv_msgs.EndSession ();
5136 // How does it score compare to others
5138 if (candidate_rate < best_candidate_rate) {
5140 // Fatal error (missing dependency), cannot continue
5141 if (candidate_rate < 0)
5144 best_candidate_rate = candidate_rate;
5145 best_candidate = member;
5146 best_candidate_args = candidate_args;
5147 best_candidate_params = params_expanded_form;
5148 best_candidate_dynamic = dynamic_argument;
5149 best_parameter_member = pm;
5150 best_candidate_return_type = rt;
5151 } else if (candidate_rate == 0) {
5153 // The member look is done per type for most operations but sometimes
5154 // it's not possible like for binary operators overload because they
5155 // are unioned between 2 sides
5157 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5158 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5163 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5165 // We pack all interface members into top level type which makes the overload resolution
5166 // more complicated for interfaces. We compensate it by removing methods with same
5167 // signature when building the cache hence this path should not really be hit often
5170 // interface IA { void Foo (int arg); }
5171 // interface IB : IA { void Foo (params int[] args); }
5173 // IB::Foo is the best overload when calling IB.Foo (1)
5176 if (ambiguous_candidates != null) {
5177 foreach (var amb_cand in ambiguous_candidates) {
5178 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5187 ambiguous_candidates = null;
5190 // Is the new candidate better
5191 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5195 best_candidate = member;
5196 best_candidate_args = candidate_args;
5197 best_candidate_params = params_expanded_form;
5198 best_candidate_dynamic = dynamic_argument;
5199 best_parameter_member = pm;
5200 best_candidate_return_type = rt;
5202 // It's not better but any other found later could be but we are not sure yet
5203 if (ambiguous_candidates == null)
5204 ambiguous_candidates = new List<AmbiguousCandidate> ();
5206 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5210 // Restore expanded arguments
5211 candidate_args = args;
5213 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5216 // We've found exact match
5218 if (best_candidate_rate == 0)
5222 // Try extension methods lookup when no ordinary method match was found and provider enables it
5225 var emg = base_provider.LookupExtensionMethod (rc);
5227 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5229 best_candidate_extension_group = emg;
5230 return (T) (MemberSpec) emg.BestCandidate;
5235 // Don't run expensive error reporting mode for probing
5242 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5245 lambda_conv_msgs = null;
5250 // No best member match found, report an error
5252 if (best_candidate_rate != 0 || error_mode) {
5253 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5257 if (best_candidate_dynamic) {
5258 if (args[0].ArgType == Argument.AType.ExtensionType) {
5259 rc.Report.Error (1973, loc,
5260 "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",
5261 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5265 // Check type constraints only when explicit type arguments are used
5267 if (best_candidate.IsGeneric && type_arguments != null) {
5268 MethodSpec bc = best_candidate as MethodSpec;
5269 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5270 ConstraintChecker cc = new ConstraintChecker (rc);
5271 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5275 BestCandidateIsDynamic = true;
5280 // These flags indicates we are running delegate probing conversion. No need to
5281 // do more expensive checks
5283 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5284 return (T) best_candidate;
5286 if (ambiguous_candidates != null) {
5288 // Now check that there are no ambiguities i.e the selected method
5289 // should be better than all the others
5291 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5292 var candidate = ambiguous_candidates [ix];
5294 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5295 var ambiguous = candidate.Member;
5296 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5297 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5298 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5299 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5300 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5303 return (T) best_candidate;
5308 if (invocable_member != null && !IsProbingOnly) {
5309 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5310 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5311 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5312 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5316 // And now check if the arguments are all
5317 // compatible, perform conversions if
5318 // necessary etc. and return if everything is
5321 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5324 if (best_candidate == null)
5328 // Don't run possibly expensive checks in probing mode
5330 if (!IsProbingOnly && !rc.IsInProbingMode) {
5332 // Check ObsoleteAttribute on the best method
5334 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5335 if (oa != null && !rc.IsObsolete)
5336 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5338 best_candidate.MemberDefinition.SetIsUsed ();
5341 args = best_candidate_args;
5342 return (T) best_candidate;
5345 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5347 return ResolveMember<MethodSpec> (rc, ref args);
5350 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5351 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5353 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5356 if (a.Type == InternalType.ErrorType)
5359 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5360 ec.Report.SymbolRelatedToPreviousError (method);
5361 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5362 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5363 TypeManager.CSharpSignature (method));
5366 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5367 TypeManager.CSharpSignature (method));
5368 } else if (IsDelegateInvoke) {
5369 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5370 DelegateType.GetSignatureForError ());
5372 ec.Report.SymbolRelatedToPreviousError (method);
5373 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5374 method.GetSignatureForError ());
5377 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5379 string index = (idx + 1).ToString ();
5380 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5381 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5382 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5383 index, Parameter.GetModifierSignature (a.Modifier));
5385 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5386 index, Parameter.GetModifierSignature (mod));
5388 string p1 = a.GetSignatureForError ();
5389 string p2 = paramType.GetSignatureForError ();
5392 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5393 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5396 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5397 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5398 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5401 ec.Report.Error (1503, a.Expr.Location,
5402 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5407 // We have failed to find exact match so we return error info about the closest match
5409 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5411 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5412 int arg_count = args == null ? 0 : args.Count;
5414 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5415 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5416 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5420 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5425 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5426 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5427 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5431 // For candidates which match on parameters count report more details about incorrect arguments
5434 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5435 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5436 // Reject any inaccessible member
5437 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5438 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5439 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5443 var ms = best_candidate as MethodSpec;
5444 if (ms != null && ms.IsGeneric) {
5445 bool constr_ok = true;
5446 if (ms.TypeArguments != null)
5447 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5449 if (ta_count == 0 && ms.TypeArguments == null) {
5450 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5454 rc.Report.Error (411, loc,
5455 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5456 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5463 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5469 // We failed to find any method with correct argument count, report best candidate
5471 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5474 if (best_candidate.Kind == MemberKind.Constructor) {
5475 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5476 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5477 } else if (IsDelegateInvoke) {
5478 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5479 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5480 DelegateType.GetSignatureForError (), arg_count.ToString ());
5482 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5483 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5484 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5485 name, arg_count.ToString ());
5489 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5491 var pd = pm.Parameters;
5492 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5494 Parameter.Modifier p_mod = 0;
5496 int a_idx = 0, a_pos = 0;
5498 ArrayInitializer params_initializers = null;
5499 bool has_unsafe_arg = pm.MemberType.IsPointer;
5500 int arg_count = args == null ? 0 : args.Count;
5502 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5507 if (p_mod != Parameter.Modifier.PARAMS) {
5508 p_mod = pd.FixedParameters[a_idx].ModFlags;
5510 has_unsafe_arg |= pt.IsPointer;
5512 if (p_mod == Parameter.Modifier.PARAMS) {
5513 if (chose_params_expanded) {
5514 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5515 pt = TypeManager.GetElementType (pt);
5521 // Types have to be identical when ref or out modifer is used
5523 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5524 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5527 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5533 NamedArgument na = a as NamedArgument;
5535 int name_index = pd.GetParameterIndexByName (na.Name);
5536 if (name_index < 0 || name_index >= pd.Count) {
5537 if (IsDelegateInvoke) {
5538 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5539 ec.Report.Error (1746, na.Location,
5540 "The delegate `{0}' does not contain a parameter named `{1}'",
5541 DelegateType.GetSignatureForError (), na.Name);
5543 ec.Report.SymbolRelatedToPreviousError (member);
5544 ec.Report.Error (1739, na.Location,
5545 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5546 TypeManager.CSharpSignature (member), na.Name);
5548 } else if (args[name_index] != a && args[name_index] != null) {
5549 if (IsDelegateInvoke)
5550 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5552 ec.Report.SymbolRelatedToPreviousError (member);
5554 ec.Report.Error (1744, na.Location,
5555 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5560 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5563 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5564 custom_errors.NoArgumentMatch (ec, member);
5569 if (a.ArgType == Argument.AType.ExtensionType) {
5570 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5573 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5575 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5578 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5585 // Convert params arguments to an array initializer
5587 if (params_initializers != null) {
5588 // we choose to use 'a.Expr' rather than 'conv' so that
5589 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5590 params_initializers.Add (a.Expr);
5591 args.RemoveAt (a_idx--);
5597 // Update the argument with the implicit conversion
5601 if (a_idx != arg_count) {
5602 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5607 // Fill not provided arguments required by params modifier
5609 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5611 args = new Arguments (1);
5613 pt = ptypes[pd.Count - 1];
5614 pt = TypeManager.GetElementType (pt);
5615 has_unsafe_arg |= pt.IsPointer;
5616 params_initializers = new ArrayInitializer (0, loc);
5620 // Append an array argument with all params arguments
5622 if (params_initializers != null) {
5623 args.Add (new Argument (
5624 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5628 if (has_unsafe_arg && !ec.IsUnsafe) {
5629 Expression.UnsafeError (ec, loc);
5633 // We could infer inaccesible type arguments
5635 if (type_arguments == null && member.IsGeneric) {
5636 var ms = (MethodSpec) member;
5637 foreach (var ta in ms.TypeArguments) {
5638 if (!ta.IsAccessible (ec)) {
5639 ec.Report.SymbolRelatedToPreviousError (ta);
5640 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5650 public class ConstantExpr : MemberExpr
5652 readonly ConstSpec constant;
5654 public ConstantExpr (ConstSpec constant, Location loc)
5656 this.constant = constant;
5660 public override string Name {
5661 get { throw new NotImplementedException (); }
5664 public override string KindName {
5665 get { return "constant"; }
5668 public override bool IsInstance {
5669 get { return !IsStatic; }
5672 public override bool IsStatic {
5673 get { return true; }
5676 protected override TypeSpec DeclaringType {
5677 get { return constant.DeclaringType; }
5680 public override Expression CreateExpressionTree (ResolveContext ec)
5682 throw new NotSupportedException ("ET");
5685 protected override Expression DoResolve (ResolveContext rc)
5687 ResolveInstanceExpression (rc, null);
5688 DoBestMemberChecks (rc, constant);
5690 var c = constant.GetConstant (rc);
5692 // Creates reference expression to the constant value
5693 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5696 public override void Emit (EmitContext ec)
5698 throw new NotSupportedException ();
5701 public override string GetSignatureForError ()
5703 return constant.GetSignatureForError ();
5706 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5708 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5713 // Fully resolved expression that references a Field
5715 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5717 protected FieldSpec spec;
5718 VariableInfo variable_info;
5720 LocalTemporary temp;
5723 protected FieldExpr (Location l)
5728 public FieldExpr (FieldSpec spec, Location loc)
5733 type = spec.MemberType;
5736 public FieldExpr (FieldBase fi, Location l)
5743 public override string Name {
5749 public bool IsHoisted {
5751 IVariableReference hv = InstanceExpression as IVariableReference;
5752 return hv != null && hv.IsHoisted;
5756 public override bool IsInstance {
5758 return !spec.IsStatic;
5762 public override bool IsStatic {
5764 return spec.IsStatic;
5768 public override string KindName {
5769 get { return "field"; }
5772 public FieldSpec Spec {
5778 protected override TypeSpec DeclaringType {
5780 return spec.DeclaringType;
5784 public VariableInfo VariableInfo {
5786 return variable_info;
5792 public override string GetSignatureForError ()
5794 return spec.GetSignatureForError ();
5797 public bool IsMarshalByRefAccess (ResolveContext rc)
5799 // Checks possible ldflda of field access expression
5800 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5801 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5802 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5805 public void SetHasAddressTaken ()
5807 IVariableReference vr = InstanceExpression as IVariableReference;
5809 vr.SetHasAddressTaken ();
5813 public override Expression CreateExpressionTree (ResolveContext ec)
5815 return CreateExpressionTree (ec, true);
5818 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5821 Expression instance;
5823 if (InstanceExpression == null) {
5824 instance = new NullLiteral (loc);
5825 } else if (convertInstance) {
5826 instance = InstanceExpression.CreateExpressionTree (ec);
5828 args = new Arguments (1);
5829 args.Add (new Argument (InstanceExpression));
5830 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5833 args = Arguments.CreateForExpressionTree (ec, null,
5835 CreateTypeOfExpression ());
5837 return CreateExpressionFactoryCall (ec, "Field", args);
5840 public Expression CreateTypeOfExpression ()
5842 return new TypeOfField (spec, loc);
5845 protected override Expression DoResolve (ResolveContext ec)
5847 spec.MemberDefinition.SetIsUsed ();
5849 return DoResolve (ec, null);
5852 Expression DoResolve (ResolveContext ec, Expression rhs)
5854 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5857 if (ResolveInstanceExpression (ec, rhs)) {
5858 // Resolve the field's instance expression while flow analysis is turned
5859 // off: when accessing a field "a.b", we must check whether the field
5860 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5862 if (lvalue_instance) {
5863 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5865 Expression right_side =
5866 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5868 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5870 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5873 if (InstanceExpression == null)
5877 DoBestMemberChecks (ec, spec);
5880 var fb = spec as FixedFieldSpec;
5881 IVariableReference var = InstanceExpression as IVariableReference;
5884 IFixedExpression fe = InstanceExpression as IFixedExpression;
5885 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5886 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5889 if (InstanceExpression.eclass != ExprClass.Variable) {
5890 ec.Report.SymbolRelatedToPreviousError (spec);
5891 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5892 TypeManager.GetFullNameSignature (spec));
5893 } else if (var != null && var.IsHoisted) {
5894 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5897 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5901 // Set flow-analysis variable info for struct member access. It will be check later
5902 // for precise error reporting
5904 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5905 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5908 eclass = ExprClass.Variable;
5912 public void SetFieldAssigned (FlowAnalysisContext fc)
5917 bool lvalue_instance = spec.DeclaringType.IsStruct;
5918 if (lvalue_instance) {
5919 var var = InstanceExpression as IVariableReference;
5920 if (var != null && var.VariableInfo != null) {
5921 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5925 var fe = InstanceExpression as FieldExpr;
5927 Expression instance;
5930 instance = fe.InstanceExpression;
5931 var fe_instance = instance as FieldExpr;
5932 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5933 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5934 var var = InstanceExpression as IVariableReference;
5935 if (var != null && var.VariableInfo == null) {
5936 var var_inst = instance as IVariableReference;
5937 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5938 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5942 if (fe_instance != null) {
5951 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
5952 instance.FlowAnalysis (fc);
5954 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
5955 InstanceExpression.FlowAnalysis (fc);
5959 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5961 // The return value is always null. Returning a value simplifies calling code.
5963 if (right_side == EmptyExpression.OutAccess) {
5965 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5966 GetSignatureForError ());
5968 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5969 GetSignatureForError ());
5975 if (right_side == EmptyExpression.LValueMemberAccess) {
5976 // Already reported as CS1648/CS1650
5980 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5982 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5983 GetSignatureForError ());
5985 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5986 GetSignatureForError ());
5992 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5993 GetSignatureForError ());
5995 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5996 GetSignatureForError ());
6002 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6004 if (spec is FixedFieldSpec) {
6005 // It could be much better error message but we want to be error compatible
6006 Error_ValueAssignment (ec, right_side);
6009 Expression e = DoResolve (ec, right_side);
6014 spec.MemberDefinition.SetIsAssigned ();
6016 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6017 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6018 ec.Report.Warning (420, 1, loc,
6019 "`{0}': A volatile field references will not be treated as volatile",
6020 spec.GetSignatureForError ());
6023 if (spec.IsReadOnly) {
6024 // InitOnly fields can only be assigned in constructors or initializers
6025 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6026 return Error_AssignToReadonly (ec, right_side);
6028 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6030 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6031 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6032 return Error_AssignToReadonly (ec, right_side);
6033 // static InitOnly fields cannot be assigned-to in an instance constructor
6034 if (IsStatic && !ec.IsStatic)
6035 return Error_AssignToReadonly (ec, right_side);
6036 // instance constructors can't modify InitOnly fields of other instances of the same type
6037 if (!IsStatic && !(InstanceExpression is This))
6038 return Error_AssignToReadonly (ec, right_side);
6042 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6043 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6044 ec.Report.Warning (197, 1, loc,
6045 "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",
6046 GetSignatureForError ());
6049 eclass = ExprClass.Variable;
6053 public override void FlowAnalysis (FlowAnalysisContext fc)
6055 var var = InstanceExpression as IVariableReference;
6057 var vi = var.VariableInfo;
6058 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6059 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6063 if (TypeSpec.IsValueType (InstanceExpression.Type))
6067 base.FlowAnalysis (fc);
6070 public override int GetHashCode ()
6072 return spec.GetHashCode ();
6075 public bool IsFixed {
6078 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6080 IVariableReference variable = InstanceExpression as IVariableReference;
6081 if (variable != null)
6082 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6084 IFixedExpression fe = InstanceExpression as IFixedExpression;
6085 return fe != null && fe.IsFixed;
6089 public override bool Equals (object obj)
6091 FieldExpr fe = obj as FieldExpr;
6095 if (spec != fe.spec)
6098 if (InstanceExpression == null || fe.InstanceExpression == null)
6101 return InstanceExpression.Equals (fe.InstanceExpression);
6104 public void Emit (EmitContext ec, bool leave_copy)
6106 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6110 ec.Emit (OpCodes.Volatile);
6112 ec.Emit (OpCodes.Ldsfld, spec);
6115 EmitInstance (ec, false);
6117 // Optimization for build-in types
6118 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6119 ec.EmitLoadFromPtr (type);
6121 var ff = spec as FixedFieldSpec;
6123 ec.Emit (OpCodes.Ldflda, spec);
6124 ec.Emit (OpCodes.Ldflda, ff.Element);
6127 ec.Emit (OpCodes.Volatile);
6129 ec.Emit (OpCodes.Ldfld, spec);
6135 ec.Emit (OpCodes.Dup);
6137 temp = new LocalTemporary (this.Type);
6143 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6145 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6146 if (isCompound && !(source is DynamicExpressionStatement)) {
6147 if (has_await_source) {
6149 InstanceExpression = InstanceExpression.EmitToField (ec);
6156 if (has_await_source)
6157 source = source.EmitToField (ec);
6159 EmitInstance (ec, prepared);
6165 ec.Emit (OpCodes.Dup);
6167 temp = new LocalTemporary (this.Type);
6172 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6173 ec.Emit (OpCodes.Volatile);
6175 spec.MemberDefinition.SetIsAssigned ();
6178 ec.Emit (OpCodes.Stsfld, spec);
6180 ec.Emit (OpCodes.Stfld, spec);
6190 // Emits store to field with prepared values on stack
6192 public void EmitAssignFromStack (EmitContext ec)
6195 ec.Emit (OpCodes.Stsfld, spec);
6197 ec.Emit (OpCodes.Stfld, spec);
6201 public override void Emit (EmitContext ec)
6206 public override void EmitSideEffect (EmitContext ec)
6208 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6210 if (is_volatile) // || is_marshal_by_ref ())
6211 base.EmitSideEffect (ec);
6214 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6216 if ((mode & AddressOp.Store) != 0)
6217 spec.MemberDefinition.SetIsAssigned ();
6218 if ((mode & AddressOp.Load) != 0)
6219 spec.MemberDefinition.SetIsUsed ();
6222 // Handle initonly fields specially: make a copy and then
6223 // get the address of the copy.
6226 if (spec.IsReadOnly){
6228 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6240 var temp = ec.GetTemporaryLocal (type);
6241 ec.Emit (OpCodes.Stloc, temp);
6242 ec.Emit (OpCodes.Ldloca, temp);
6243 ec.FreeTemporaryLocal (temp, type);
6249 ec.Emit (OpCodes.Ldsflda, spec);
6252 EmitInstance (ec, false);
6253 ec.Emit (OpCodes.Ldflda, spec);
6257 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6259 return MakeExpression (ctx);
6262 public override SLE.Expression MakeExpression (BuilderContext ctx)
6265 return base.MakeExpression (ctx);
6267 return SLE.Expression.Field (
6268 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6269 spec.GetMetaInfo ());
6273 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6275 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6281 // Expression that evaluates to a Property.
6283 // This is not an LValue because we need to re-write the expression. We
6284 // can not take data from the stack and store it.
6286 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6288 Arguments arguments;
6290 public PropertyExpr (PropertySpec spec, Location l)
6293 best_candidate = spec;
6294 type = spec.MemberType;
6299 protected override Arguments Arguments {
6308 protected override TypeSpec DeclaringType {
6310 return best_candidate.DeclaringType;
6314 public override string Name {
6316 return best_candidate.Name;
6320 public override bool IsInstance {
6326 public override bool IsStatic {
6328 return best_candidate.IsStatic;
6332 public override string KindName {
6333 get { return "property"; }
6336 public PropertySpec PropertyInfo {
6338 return best_candidate;
6344 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6346 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6349 var args_count = arguments == null ? 0 : arguments.Count;
6350 if (args_count != body.Parameters.Count && args_count == 0)
6353 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6354 mg.InstanceExpression = InstanceExpression;
6359 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6361 return new PropertyExpr (spec, loc) {
6367 public override Expression CreateExpressionTree (ResolveContext ec)
6370 if (IsSingleDimensionalArrayLength ()) {
6371 args = new Arguments (1);
6372 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6373 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6376 args = new Arguments (2);
6377 if (InstanceExpression == null)
6378 args.Add (new Argument (new NullLiteral (loc)));
6380 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6381 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6382 return CreateExpressionFactoryCall (ec, "Property", args);
6385 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6387 DoResolveLValue (rc, null);
6388 return new TypeOfMethod (Setter, loc);
6391 public override string GetSignatureForError ()
6393 return best_candidate.GetSignatureForError ();
6396 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6399 return base.MakeExpression (ctx);
6401 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6405 public override SLE.Expression MakeExpression (BuilderContext ctx)
6408 return base.MakeExpression (ctx);
6410 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6414 void Error_PropertyNotValid (ResolveContext ec)
6416 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6417 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6418 GetSignatureForError ());
6421 bool IsSingleDimensionalArrayLength ()
6423 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6426 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6427 return ac != null && ac.Rank == 1;
6430 public override void Emit (EmitContext ec, bool leave_copy)
6433 // Special case: length of single dimension array property is turned into ldlen
6435 if (IsSingleDimensionalArrayLength ()) {
6436 EmitInstance (ec, false);
6437 ec.Emit (OpCodes.Ldlen);
6438 ec.Emit (OpCodes.Conv_I4);
6442 base.Emit (ec, leave_copy);
6445 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6448 LocalTemporary await_source_arg = null;
6450 if (isCompound && !(source is DynamicExpressionStatement)) {
6451 emitting_compound_assignment = true;
6454 if (has_await_arguments) {
6455 await_source_arg = new LocalTemporary (Type);
6456 await_source_arg.Store (ec);
6458 args = new Arguments (1);
6459 args.Add (new Argument (await_source_arg));
6462 temp = await_source_arg;
6465 has_await_arguments = false;
6470 ec.Emit (OpCodes.Dup);
6471 temp = new LocalTemporary (this.Type);
6476 args = arguments ?? new Arguments (1);
6480 temp = new LocalTemporary (this.Type);
6482 args.Add (new Argument (temp));
6484 args.Add (new Argument (source));
6488 emitting_compound_assignment = false;
6490 var call = new CallEmitter ();
6491 call.InstanceExpression = InstanceExpression;
6493 call.InstanceExpressionOnStack = true;
6495 call.Emit (ec, Setter, args, loc);
6502 if (await_source_arg != null) {
6503 await_source_arg.Release (ec);
6507 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6509 eclass = ExprClass.PropertyAccess;
6511 if (best_candidate.IsNotCSharpCompatible) {
6512 Error_PropertyNotValid (rc);
6515 ResolveInstanceExpression (rc, right_side);
6517 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6518 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6519 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6521 type = p.MemberType;
6525 DoBestMemberChecks (rc, best_candidate);
6527 // Handling of com-imported properties with any number of default property parameters
6528 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6529 var p = best_candidate.Get.Parameters;
6530 arguments = new Arguments (p.Count);
6531 for (int i = 0; i < p.Count; ++i) {
6532 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6534 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6535 var p = best_candidate.Set.Parameters;
6536 arguments = new Arguments (p.Count - 1);
6537 for (int i = 0; i < p.Count - 1; ++i) {
6538 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6545 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6547 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6551 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6553 // getter and setter can be different for base calls
6554 MethodSpec getter, setter;
6555 protected T best_candidate;
6557 protected LocalTemporary temp;
6558 protected bool emitting_compound_assignment;
6559 protected bool has_await_arguments;
6561 protected PropertyOrIndexerExpr (Location l)
6568 protected abstract Arguments Arguments { get; set; }
6570 public MethodSpec Getter {
6579 public MethodSpec Setter {
6590 protected override Expression DoResolve (ResolveContext ec)
6592 if (eclass == ExprClass.Unresolved) {
6593 var expr = OverloadResolve (ec, null);
6598 return expr.Resolve (ec);
6601 if (!ResolveGetter (ec))
6607 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6609 if (right_side == EmptyExpression.OutAccess) {
6610 // TODO: best_candidate can be null at this point
6611 INamedBlockVariable variable = null;
6612 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6613 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6614 best_candidate.Name);
6616 right_side.DoResolveLValue (ec, this);
6621 if (eclass == ExprClass.Unresolved) {
6622 var expr = OverloadResolve (ec, right_side);
6627 return expr.ResolveLValue (ec, right_side);
6629 ResolveInstanceExpression (ec, right_side);
6632 if (!ResolveSetter (ec))
6639 // Implements the IAssignMethod interface for assignments
6641 public virtual void Emit (EmitContext ec, bool leave_copy)
6643 var call = new CallEmitter ();
6644 call.InstanceExpression = InstanceExpression;
6645 if (has_await_arguments)
6646 call.HasAwaitArguments = true;
6648 call.DuplicateArguments = emitting_compound_assignment;
6650 call.Emit (ec, Getter, Arguments, loc);
6652 if (call.HasAwaitArguments) {
6653 InstanceExpression = call.InstanceExpression;
6654 Arguments = call.EmittedArguments;
6655 has_await_arguments = true;
6659 ec.Emit (OpCodes.Dup);
6660 temp = new LocalTemporary (Type);
6665 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6667 public override void Emit (EmitContext ec)
6672 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6674 has_await_arguments = true;
6679 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6681 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6683 bool ResolveGetter (ResolveContext rc)
6685 if (!best_candidate.HasGet) {
6686 if (InstanceExpression != EmptyExpression.Null) {
6687 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6688 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6689 best_candidate.GetSignatureForError ());
6692 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6693 if (best_candidate.HasDifferentAccessibility) {
6694 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6695 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6696 TypeManager.CSharpSignature (best_candidate));
6698 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6699 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6703 if (best_candidate.HasDifferentAccessibility) {
6704 CheckProtectedMemberAccess (rc, best_candidate.Get);
6707 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6711 bool ResolveSetter (ResolveContext rc)
6713 if (!best_candidate.HasSet) {
6714 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6715 GetSignatureForError ());
6719 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6720 if (best_candidate.HasDifferentAccessibility) {
6721 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6722 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6723 GetSignatureForError ());
6725 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6726 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6730 if (best_candidate.HasDifferentAccessibility)
6731 CheckProtectedMemberAccess (rc, best_candidate.Set);
6733 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6739 /// Fully resolved expression that evaluates to an Event
6741 public class EventExpr : MemberExpr, IAssignMethod
6743 readonly EventSpec spec;
6746 public EventExpr (EventSpec spec, Location loc)
6754 protected override TypeSpec DeclaringType {
6756 return spec.DeclaringType;
6760 public override string Name {
6766 public override bool IsInstance {
6768 return !spec.IsStatic;
6772 public override bool IsStatic {
6774 return spec.IsStatic;
6778 public override string KindName {
6779 get { return "event"; }
6782 public MethodSpec Operator {
6790 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6793 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6795 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6796 if (spec.BackingField != null &&
6797 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6799 spec.MemberDefinition.SetIsUsed ();
6801 if (!ec.IsObsolete) {
6802 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6804 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6807 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6808 Error_AssignmentEventOnly (ec);
6810 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6812 InstanceExpression = null;
6814 return ml.ResolveMemberAccess (ec, left, original);
6818 return base.ResolveMemberAccess (ec, left, original);
6821 public override Expression CreateExpressionTree (ResolveContext ec)
6823 throw new NotSupportedException ("ET");
6826 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6828 if (right_side == EmptyExpression.EventAddition) {
6829 op = spec.AccessorAdd;
6830 } else if (right_side == EmptyExpression.EventSubtraction) {
6831 op = spec.AccessorRemove;
6835 Error_AssignmentEventOnly (ec);
6839 op = CandidateToBaseOverride (ec, op);
6843 protected override Expression DoResolve (ResolveContext ec)
6845 eclass = ExprClass.EventAccess;
6846 type = spec.MemberType;
6848 ResolveInstanceExpression (ec, null);
6850 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6851 Error_AssignmentEventOnly (ec);
6854 DoBestMemberChecks (ec, spec);
6858 public override void Emit (EmitContext ec)
6860 throw new NotSupportedException ();
6861 //Error_CannotAssign ();
6864 #region IAssignMethod Members
6866 public void Emit (EmitContext ec, bool leave_copy)
6868 throw new NotImplementedException ();
6871 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6873 if (leave_copy || !isCompound)
6874 throw new NotImplementedException ("EventExpr::EmitAssign");
6876 Arguments args = new Arguments (1);
6877 args.Add (new Argument (source));
6879 var call = new CallEmitter ();
6880 call.InstanceExpression = InstanceExpression;
6881 call.Emit (ec, op, args, loc);
6886 void Error_AssignmentEventOnly (ResolveContext ec)
6888 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6889 ec.Report.Error (79, loc,
6890 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6891 GetSignatureForError ());
6893 ec.Report.Error (70, loc,
6894 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6895 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6899 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6901 name = name.Substring (0, name.LastIndexOf ('.'));
6902 base.Error_CannotCallAbstractBase (rc, name);
6905 public override string GetSignatureForError ()
6907 return TypeManager.CSharpSignature (spec);
6910 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6912 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6916 public class TemporaryVariableReference : VariableReference
6918 public class Declarator : Statement
6920 TemporaryVariableReference variable;
6922 public Declarator (TemporaryVariableReference variable)
6924 this.variable = variable;
6928 protected override void DoEmit (EmitContext ec)
6930 variable.li.CreateBuilder (ec);
6933 public override void Emit (EmitContext ec)
6935 // Don't create sequence point
6939 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6944 protected override void CloneTo (CloneContext clonectx, Statement target)
6952 public TemporaryVariableReference (LocalVariable li, Location loc)
6955 this.type = li.Type;
6959 public override bool IsLockedByStatement {
6967 public LocalVariable LocalInfo {
6973 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6975 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6976 return new TemporaryVariableReference (li, loc);
6979 protected override Expression DoResolve (ResolveContext ec)
6981 eclass = ExprClass.Variable;
6984 // Don't capture temporary variables except when using
6985 // state machine redirection and block yields
6987 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6988 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6989 ec.IsVariableCapturingRequired) {
6990 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6991 storey.CaptureLocalVariable (ec, li);
6997 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6999 return Resolve (ec);
7002 public override void Emit (EmitContext ec)
7004 li.CreateBuilder (ec);
7009 public void EmitAssign (EmitContext ec, Expression source)
7011 li.CreateBuilder (ec);
7013 EmitAssign (ec, source, false, false);
7016 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7018 return li.HoistedVariant;
7021 public override bool IsFixed {
7022 get { return true; }
7025 public override bool IsRef {
7026 get { return false; }
7029 public override string Name {
7030 get { throw new NotImplementedException (); }
7033 public override void SetHasAddressTaken ()
7035 throw new NotImplementedException ();
7038 protected override ILocalVariable Variable {
7042 public override VariableInfo VariableInfo {
7043 get { return null; }
7048 /// Handles `var' contextual keyword; var becomes a keyword only
7049 /// if no type called var exists in a variable scope
7051 class VarExpr : SimpleName
7053 public VarExpr (Location loc)
7058 public bool InferType (ResolveContext ec, Expression right_side)
7061 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7063 type = right_side.Type;
7064 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7065 ec.Report.Error (815, loc,
7066 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7067 type.GetSignatureForError ());
7071 eclass = ExprClass.Variable;
7075 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7077 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7078 base.Error_TypeOrNamespaceNotFound (ec);
7080 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");